elliptic.tcl

Go to the documentation of this file.
00001 /*  elliptic.tcl --*/
00002 /*     Compute elliptic functions and integrals*/
00003 /* */
00004 /*     Computation of elliptic functions cn, dn and sn*/
00005 /*     adapted from:*/
00006 /*         Michael W. Pashea*/
00007 /*         Numerical computation of elliptic functions*/
00008 /*         Doctor Dobbs' Journal, May 2005*/
00009 /* */
00010 
00011 /*  namespace ::math::special*/
00012 /* */
00013 namespace ::math::special {
00014     namespace export cn sn dn
00015 
00016     ::math::constants::constants pi
00017 
00018     variable halfpi [expr {$pi/2.0}]
00019     variable tol
00020 
00021      tol =  1.0e-10
00022 }
00023 
00024 /*  elliptic_K --*/
00025 /*     Compute the complete elliptic integral of the first kind*/
00026 /* */
00027 /*  Arguments:*/
00028 /*     k            Parameter of the integral*/
00029 /*  Result:*/
00030 /*     Value of K(k)*/
00031 /*  Note:*/
00032 /*     This relies on the arithmetic-geometric mean*/
00033 /* */
00034 ret  ::math::special::elliptic_K (type k) {
00035     variable halfpi
00036     if { $k < 0.0 || $k >= 1.0 } {
00037         error "Domain error: must be between 0 (inclusive) and 1 (not inclusive)"
00038     }
00039 
00040     if { $k == 0.0 } {
00041         return $halfpi
00042     }
00043 
00044     set a 1.0
00045     set b [expr {sqrt(1.0-$k*$k)}]
00046 
00047     for {set i 0} {$i < 10} {incr i} {
00048         set anew [expr {($a+$b)/2.0}]
00049         set bnew [expr {sqrt($a*$b)}]
00050 
00051         set a $anew
00052         set b $bnew
00053         #puts "$a $b"
00054     }
00055 
00056     return [expr {$halfpi/$a}]
00057 }
00058 
00059 /*  elliptic_E --*/
00060 /*     Compute the complete elliptic integral of the second kind*/
00061 /* */
00062 /*  Arguments:*/
00063 /*     k            Parameter of the integral*/
00064 /*  Result:*/
00065 /*     Value of E(k)*/
00066 /*  Note:*/
00067 /*     This relies on the arithmetic-geometric mean*/
00068 /* */
00069 ret  ::math::special::elliptic_E (type k) {
00070    variable halfpi
00071    if { $k < 0.0 || $k >= 1.0 } {
00072        error "Domain error: must be between 0 (inclusive) and 1 (not inclusive)"
00073    }
00074 
00075    if { $k == 0.0 } {
00076        return $halfpi
00077    }
00078    if { $k == 1.0 } {
00079        return 1.0
00080    }
00081 
00082    set a      1.0
00083    set b      [expr {sqrt(1.0-$k*$k)}]
00084    set sumc   [expr {$k*$k/2.0}]
00085    set factor 0.25
00086 
00087    for {set i 0} {$i < 10} {incr i} {
00088        set anew   [expr {($a+$b)/2.0}]
00089        set bnew   [expr {sqrt($a*$b)}]
00090        set sumc   [expr {$sumc+$factor*($a-$b)*($a-$b)}]
00091        set factor [expr {$factor*2.0}]
00092 
00093        set a $anew
00094        set b $bnew
00095        #puts "$a $b"
00096    }
00097 
00098    set Kk [expr {$halfpi/$a}]
00099    return [expr {(1.0-$sumc)*$Kk}]
00100 }
00101 
00102 namespace ::math::special {
00103 }
00104 
00105 /*  Nextk --*/
00106 /*      Auxiliary function for computing next value of k*/
00107 /* */
00108 /*  Arguments:*/
00109 /*      k           Parameter*/
00110 /*  Return value:*/
00111 /*      Next value to be used*/
00112 /* */
00113 ret  ::math::special::Nextk ( type k ) {
00114     set ksq [expr {sqrt(1.0-$k*$k)}]
00115     return [expr {(1.0-$ksq)/(1+$ksq)}]
00116 }
00117 
00118 /*  IterateUK --*/
00119 /*      Auxiliary function to compute the raw value (phi)*/
00120 /* */
00121 /*  Arguments:*/
00122 /*      u           Independent variable*/
00123 /*      k           Parameter*/
00124 /*  Return value:*/
00125 /*      phi*/
00126 /* */
00127 ret  ::math::special::IterateUK ( type u , type k ) {
00128     variable tol
00129     set kvalues {}
00130     set nmax    1
00131     while { $k > $tol } {
00132         set k [Nextk $k]
00133         set kvalues [concat $k $kvalues]
00134         set u [expr {$u*2.0/(1.0+$k)}]
00135         incr nmax
00136         #puts "$nmax -$u - $k"
00137     }
00138     foreach k $kvalues {
00139         set u [expr {( $u + asin($k*sin($u)) )/2.0}]
00140     }
00141     return $u
00142 }
00143 
00144 /*  cn --*/
00145 /*      Compute the elliptic function cn*/
00146 /* */
00147 /*  Arguments:*/
00148 /*      u           Independent variable*/
00149 /*      k           Parameter*/
00150 /*  Return value:*/
00151 /*      cn(u,k)*/
00152 /*  Note:*/
00153 /*      If k == 1, then the iteration does not stop*/
00154 /* */
00155 ret  ::math::special::cn ( type u , type k ) {
00156     if { $k > 1.0 } {
00157         return -code error "Parameter out of range - must be <= 1.0"
00158     }
00159     if { $k == 1.0 } {
00160         return [expr {1.0/cosh($u)}]
00161     } else {
00162         set u [IterateUK $u $k]
00163         return [expr {cos($u)}]
00164     }
00165 }
00166 
00167 /*  sn --*/
00168 /*      Compute the elliptic function sn*/
00169 /* */
00170 /*  Arguments:*/
00171 /*      u           Independent variable*/
00172 /*      k           Parameter*/
00173 /*  Return value:*/
00174 /*      sn(u,k)*/
00175 /*  Note:*/
00176 /*      If k == 1, then the iteration does not stop*/
00177 /* */
00178 ret  ::math::special::sn ( type u , type k ) {
00179     if { $k > 1.0 } {
00180         return -code error "Parameter out of range - must be <= 1.0"
00181     }
00182     if { $k == 1.0 } {
00183         return [expr {tanh($u)}]
00184     } else {
00185         set u [IterateUK $u $k]
00186         return [expr {sin($u)}]
00187     }
00188 }
00189 
00190 /*  dn --*/
00191 /*      Compute the elliptic function sn*/
00192 /* */
00193 /*  Arguments:*/
00194 /*      u           Independent variable*/
00195 /*      k           Parameter*/
00196 /*  Return value:*/
00197 /*      dn(u,k)*/
00198 /*  Note:*/
00199 /*      If k == 1, then the iteration does not stop*/
00200 /* */
00201 ret  ::math::special::sn ( type u , type k ) {
00202     if { $k > 1.0 } {
00203         return -code error "Parameter out of range - must be <= 1.0"
00204     }
00205     if { $k == 1.0 } {
00206         return [expr {1.0/cosh($u)}]
00207     } else {
00208         set u [IterateUK $u $k]
00209         return [expr {sqrt(1.0-$k*$k*sin($u)}]
00210     }
00211 }
00212 
00213 
00214 /*  main --*/
00215 /*     Simple tests*/
00216 /* */
00217 if { 0 } {
00218 puts "Special cases:"
00219 puts "cos(1):    [::math::special::cn 1.0 0.0] -- [expr {cos(1.0)}]"
00220 puts "1/cosh(1): [::math::special::cn 1.0 0.999] -- [expr {1.0/cosh(1.0)}]"
00221 }
00222 
00223 /*  some tests --*/
00224 /* */
00225 if { 0 } {
00226  tcl = _precision 17
00227 /* foreach k {0.0 0.1 0.2 0.4 0.6 0.8 0.9} {*/
00228 /*     puts "$k: [::math::special::elliptic_K $k]"*/
00229 /* }*/
00230 foreach k2 {0.0 0.1 0.2 0.4 0.6 0.8 0.9} {
00231      k =  [expr {sqrt($k2)}]
00232     puts "$k2: [::math::special::elliptic_K $k] \
00233 [::math::special::elliptic_E $k]"
00234 }
00235 }
00236 
00237 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1