muMECH  1.0
legendreIntegrals.cpp
Go to the documentation of this file.
1 //********************************************************************************************************
2 // code: ### ### ##### #### ## ##
3 // ## ## ######## ## ## ## ## ##
4 // ## ## ## ## ## ### ## ######
5 // ## ## ## ## ## ## ## ## ##
6 // ##### ## ## ##### #### ## ##
7 // ##
8 //
9 // name: legendreIntegrals.cpp
10 // author(s): Jan Novak
11 // language: C, C++
12 // license: This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU Lesser General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 //********************************************************************************************************
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <float.h>
31 #include "legendreIntegrals.h"
32 #include "gelib.h"
33 #include "macros.h"
34 
35 
36 namespace mumech {
37 
38 //********************************************************************************************************
39 // PUBLIC FUNCTIONS
40 //********************************************************************************************************
41 
42 //********************************************************************************************************
43 // description: Function calculating the Legendre's integral of the first kind
44 // last edit: 24. 11. 2008
45 //-------------------------------------------------------------------------------------------------------
46 // Legendre elliptic integral of the 1st kind F(@Theta, @k), evaluated using Carlson's function RF.
47 // The argument ranges are 0 <= Theta <= PI/2, 0 <= k*sin(Theta) <= 1.
48 //********************************************************************************************************
49 double legendreIntegrals :: ellf (double phi, double ak)
50 {
51  double s = sin (phi);
52 
53  return ( s * legendreIntegrals::rf( SQR( cos( phi ) ), ( 1.0 - s * ak ) * ( 1.0 + s * ak ), 1.0 ) );
54 }
55 
56 //********************************************************************************************************
57 // description: Function calculating the Legendre's integral of the seccond kind
58 // last edit: 24. 11. 2008
59 //-------------------------------------------------------------------------------------------------------
60 // Legendre elliptic integral of the 2nd kind E(@Theta, @k), evaluated using Carlson's functions RD and RF.
61 // The argument ranges are 0 <= Theta <= PI/2, 0 <= k*sin(Theta) <= 1.
62 //********************************************************************************************************
63 double legendreIntegrals :: elle (double phi, double ak)
64 {
65  double s, cc, q;
66  s = sin( phi );
67  cc = SQR( cos( phi ) );
68  q = ( 1.0 - s * ak ) * ( 1.0 + s * ak );
69 
70  return ( s * ( legendreIntegrals::rf( cc, q, 1.0 ) - ( SQR( s * ak ) ) * legendreIntegrals::rd( cc, q, 1.0 )/3.0 ) );
71 }
72 
73 //********************************************************************************************************
74 // description: Function calculating the Legendre's integral of the third kind
75 // last edit: 24. 11. 2008
76 //-------------------------------------------------------------------------------------------------------
77 // Legendre elliptic integral of the 3rd kind PI(@Theta, @n, @k), evaluated using Carlson's functions RJ and
78 // RF. (Note that the sign convention on n is opposite that of Abramowitz and Stegun.)
79 // The argument ranges are 0 <= Theta <= PI/2, 0 <= k*sin(Theta) <= 1.
80 //********************************************************************************************************
81 double legendreIntegrals :: ellpi (double phi, double en, double ak)
82 {
83  double s, enss, cc, q;
84  s = sin( phi );
85  enss = en * s * s;
86  cc = SQR( cos( phi ) );
87  q = ( 1.0 - s * ak ) * ( 1.0 + s * ak );
88 
89  return ( s * ( legendreIntegrals::rf( cc, q, 1.0 ) - enss * legendreIntegrals::rj( cc, q, 1.0, 1.0 + enss )/3.0 ) );
90 }
91 
92 
93 //********************************************************************************************************
94 // PROTECTED FUNCTIONS
95 //********************************************************************************************************
96 
97 //********************************************************************************************************
98 // description: Solution of Carlson's integral of the first kind - numerical recepies
99 // last edit: 24. 11. 2008
100 //-------------------------------------------------------------------------------------------------------
101 // Computes Carlson's elliptic integral of the first kind, RF(@x, @y, @z). @x, @y, and @z must be
102 // nonnegative, and at most one can be zero. TINY must be at least 5 times the machine underflow limit,
103 // BIG at most one fifth the machine overflow limit.
104 //********************************************************************************************************
105 
106 #define RF_ERRTOL 0.0025
107 //#define RF_TINY 1.5e-38 //as in Numer. recepies
108 //#define RF_BIG 3.0e37 //as in Numer. recepies
109 #define RF_TINY ( DBL_MIN * 5. )
110 #define RF_BIG ( DBL_MAX / 5. )
111 #define RF_THIRD ( 1.0/3.0 )
112 #define RF_C1 ( 1.0/24.0 )
113 #define RF_C2 0.1
114 #define RF_C3 ( 3.0/44.0 )
115 #define RF_C4 ( 1.0/14.0 )
116 
117 double legendreIntegrals::rf( double x, double y, double z )
118 {
119  double alamb, ave, delx, dely, delz, e2, e3, sqrtx, sqrty, sqrtz, xt, yt, zt;
120 
121  if ( MIN( MIN( x, y ), z ) < 0.0 ||
122  MIN( MIN( x + y, x + z ), y + z ) < RF_TINY ||
123  MAX( MAX( x, y ), z ) > RF_BIG ){
124  _errorr1( "legendreIntegrals::rf: invalid argument(s)\n" );
125  }
126 
127  xt = x;
128  yt = y;
129  zt = z;
130 
131  do {
132  sqrtx = sqrt( xt );
133  sqrty = sqrt( yt );
134  sqrtz = sqrt( zt );
135  alamb = sqrtx * ( sqrty + sqrtz ) + sqrty * sqrtz;
136  xt = 0.25 * ( xt + alamb );
137  yt = 0.25 * ( yt + alamb );
138  zt = 0.25 * ( zt + alamb );
139  ave = RF_THIRD * ( xt + yt + zt );
140  delx = ( ave - xt )/ave;
141  dely = ( ave - yt )/ave;
142  delz = ( ave - zt )/ave;
143  }while( MAX( MAX( ABS( delx ), ABS( dely ) ), ABS( delz ) ) > RF_ERRTOL );
144 
145  e2 = delx * dely - delz * delz;
146  e3 = delx * dely * delz;
147 
148  return( 1.0 + ( RF_C1 * e2 - RF_C2 - RF_C3 * e3 ) * e2 + RF_C4 * e3 )/sqrt( ave );
149 }//end of function: rf()
150 
151 //********************************************************************************************************
152 // description: Solution of Carlson's integral of the seccond kind - numerical recepies
153 // last edit: 24. 11. 2008
154 //-------------------------------------------------------------------------------------------------------
155 // Computes Carlson's elliptic integral of the second kind, RD(@x, @y, @z). @x and @y must be nonnegative,
156 // and at most one can be zero. @z must be positive. TINY must be at least twice the
157 // negative 2/3 power of the machine overflow limit. BIG must be at most 0.1*ERRTOL times
158 // the negative 2/3 power of the machine underflow limit.
159 //********************************************************************************************************
160 
161 #define RD_ERRTOL 0.0015
162 //#define RD_TINY 1.0e-25 //as in Numer. recepies
163 //#define RD_BIG 4.5e21 //as in Numer. recepies
164 #define RD_TINY ( 2. * pow( DBL_MAX, (-2./3.) ) )
165 #define RD_BIG ( 0.1 * RD_ERRTOL * pow( DBL_MIN, (-2./3.) ) )
166 #define RD_C1 ( 3.0/14.0 )
167 #define RD_C2 ( 1.0/6.0 )
168 #define RD_C3 ( 9.0/22.0 )
169 #define RD_C4 ( 3.0/26.0 )
170 #define RD_C5 ( 0.25 * RD_C3 )
171 #define RD_C6 ( 1.5 * RD_C4 )
172 
173 double legendreIntegrals::rd( double x, double y, double z )
174 {
175  double alamb, ave, delx, dely, delz, ea, eb, ec, ed, ee, fac, sqrtx, sqrty, sqrtz, sum, xt, yt, zt;
176 
177  if( MIN( x, y ) < 0.0 || MIN( x + y, z ) < RD_TINY || MAX( MAX( x, y ), z ) > RD_BIG ){
178  _errorr( "legendreIntegrals::rd: invalid argument(s)\n" );
179  }
180 
181  xt = x;
182  yt = y;
183  zt = z;
184  sum = 0.0;
185  fac = 1.0;
186 
187  do{
188  sqrtx = sqrt( xt );
189  sqrty = sqrt( yt );
190  sqrtz = sqrt( zt );
191  alamb = sqrtx * ( sqrty + sqrtz ) + sqrty * sqrtz;
192  sum += fac/( sqrtz *( zt + alamb ) );
193  fac = 0.25 * fac;
194  xt = 0.25 * ( xt + alamb );
195  yt = 0.25 * ( yt + alamb );
196  zt = 0.25 * ( zt + alamb );
197  ave = 0.2 * ( xt + yt + 3.0 * zt );
198  delx = ( ave - xt )/ave;
199  dely = ( ave - yt )/ave;
200  delz = ( ave - zt )/ave;
201  }while( MAX( MAX( ABS( delx ), ABS( dely ) ), ABS( delz ) ) > RD_ERRTOL );
202 
203  ea = delx * dely;
204  eb = delz * delz;
205  ec = ea - eb;
206  ed = ea - 6.0 * eb;
207  ee = ed + ec + ec;
208 
209  return( 3.0 * sum + fac * ( 1.0 + ed * ( -RD_C1 + RD_C5 * ed - RD_C6 * delz * ee )
210  + delz * ( RD_C2 * ee + delz * ( -RD_C3 * ec + delz * RD_C4 * ea ) ) )/( ave * sqrt( ave ) ) );
211 }//end of function: rd()
212 
213 
214 //********************************************************************************************************
215 // description: Solution of Carlson's integral of the third kind - numerical recepies
216 // last edit: 24. 11. 2008
217 //-------------------------------------------------------------------------------------------------------
218 // Computes Carlson's elliptic integral of the third kind, RJ(@x, @y, @z, @p). @x, @y, and @z must be
219 // nonnegative, and at most one can be zero. @p must be nonzero. If p < 0, the Cauchy principal
220 // value is returned. TINY must be at least twice the cube root of the machine underflow limit,
221 // BIG at most one fifth the cube root of the machine overflow limit.
222 //********************************************************************************************************
223 
224 #define RJ_ERRTOL 0.0015
225 //#define RJ_TINY 2.5e-13 //as in Numer. recepies
226 //#define RJ_BIG 9.0e11 //as in Numer. recepies
227 #define RJ_TINY ( 2. * pow( DBL_MIN, ( 1./3. ) ) )
228 #define RJ_BIG ( pow( DBL_MAX, ( 1./3. ) ) / 5. )
229 #define RJ_C1 ( 3.0/14.0 )
230 #define RJ_C2 ( 1.0/3.0 )
231 #define RJ_C3 ( 3.0/22.0 )
232 #define RJ_C4 ( 3.0/26.0 )
233 #define RJ_C5 ( 0.75 * RJ_C3 )
234 #define RJ_C6 ( 1.5 * RJ_C4 )
235 #define RJ_C7 ( 0.5 * RJ_C2 )
236 #define RJ_C8 ( RJ_C3 + RJ_C3 )
237 
238 double legendreIntegrals::rj( double x, double y, double z, double p )
239 {
240  double a = 0.0, alamb = 0.0, alpha = 0.0, ans = 0.0, ave = 0.0;
241  double b = 0.0, beta = 0.0, delp = 0.0, delx = 0.0, dely = 0.0, delz = 0.0, ea = 0.0;
242  double eb = 0.0, ec = 0.0, ed = 0.0, ee = 0.0, fac = 0.0, pt = 0.0, rcx = 0.0;
243  double rho = 0.0, sqrtx = 0.0, sqrty = 0.0, sqrtz = 0.0, sum = 0.0, tau = 0.0;
244  double xt = 0.0, yt = 0.0, zt = 0.0;
245  /* Originally in Numerical recepies
246  if ( MIN( MIN( x, y ), z ) < 0.0 ||
247  MIN( MIN( x + y, x + z ), MIN( y + z, ABS( p ) ) ) < RJ_TINY ||
248  MAX( MAX( x, y ), MAX( z, ABS( p ) ) ) > RJ_BIG ){
249  _errorr( "legendreIntegrals::rj: invalid argument(s)\n" );
250  }
251  */
252  //bug version from: http://www.nr.com/latest-known-bugs.html, last edit 02.09.2009
253  if ( MIN( MIN( x, y ), z ) < 0.0 ||
254  MIN( MIN( MIN( x + y, x + z ), y + z ), ABS( p ) ) < RJ_TINY ||
255  MAX( MAX( MAX( x, y ), z ), ABS( p ) ) > RJ_BIG ){
256  _errorr( "legendreIntegrals::rj: invalid argument(s)\n" );
257  }
258 
259  sum = 0.0;
260  fac = 1.0;
261 
262  if( p > 0.0 ){
263  xt = x;
264  yt = y;
265  zt = z;
266  pt = p;
267  }
268  else{
269  xt = MIN( MIN( x, y ), z );
270  zt = MAX( MAX( x, y ), z );
271  yt = x + y + z - xt - zt;
272  a = 1.0/( yt - p );
273  b = a * ( zt - yt ) * ( yt - xt );
274  pt = yt + b;
275  rho = xt * zt/yt;
276  tau = p * pt/yt;
277  rcx = rc( rho, tau );
278  }
279 
280  do{
281  sqrtx = sqrt( xt );
282  sqrty = sqrt( yt );
283  sqrtz = sqrt( zt );
284  alamb = sqrtx * ( sqrty + sqrtz ) + sqrty * sqrtz;
285  alpha = SQR( pt * ( sqrtx + sqrty + sqrtz ) + sqrtx * sqrty * sqrtz );
286  beta = pt * SQR( pt + alamb );
287  sum += fac * rc( alpha, beta );
288  fac = 0.25 * fac;
289  xt = 0.25 * ( xt + alamb );
290  yt = 0.25 *( yt + alamb );
291  zt = 0.25 *( zt + alamb );
292  pt = 0.25 *( pt + alamb );
293  ave = 0.2 * ( xt + yt + zt + pt + pt );
294  delx = ( ave - xt )/ave;
295  dely = ( ave - yt )/ave;
296  delz = ( ave - zt )/ave;
297  delp = ( ave - pt )/ave;
298  }
299  /* Originally in Numerical recepies
300  while( MAX( MAX( ABS( delx ), ABS( dely ) ), MAX( ABS( delz ), ABS( delp ) ) ) > RJ_ERRTOL );
301  */
302  //bug version from: http://www.nr.com/latest-known-bugs.html, last edit 02.09.2009
303  while( MAX( MAX( MAX( ABS( delx ), ABS( dely ) ), ABS( delz ) ), ABS( delp ) ) > RJ_ERRTOL );
304 
305  ea = delx * ( dely + delz ) + dely * delz;
306  eb = delx * dely * delz;
307  ec = delp * delp;
308  ed = ea - 3.0 * ec;
309  ee = eb + 2.0 * delp * ( ea - ec );
310  ans = 3.0 * sum + fac * ( 1.0 + ed * ( -RJ_C1 + RJ_C5 * ed - RJ_C6 * ee ) + eb * ( RJ_C7 + delp * ( -RJ_C8 + delp * RJ_C4 ) ) + delp * ea * ( RJ_C2 - delp * RJ_C3 ) -RJ_C2 * delp * ec )/( ave * sqrt( ave ) );
311 
312  if( p <= 0.0 ){
313  ans = a * ( b * ans + 3.0 * ( rcx - rf( xt, yt, zt ) ) );
314  }
315 
316  return( ans );
317 }//end of function: rj()
318 
319 //********************************************************************************************************
320 // description: Solution of Carlson's degenerate elliptic integral - numerical recepies
321 // last edit: 24. 11. 2008
322 //-------------------------------------------------------------------------------------------------------
323 // Computes Carlson's degenerate elliptic integral, RC(@x, @y). @x must be nonnegative and y must
324 // be nonzero. If y < 0, the Cauchy principal value is returned. TINY must be at least 5 times
325 // the machine underflow limit, BIG at most one fifth the machine maximum overflow limit.
326 //********************************************************************************************************
327 
328 #define RC_ERRTOL 0.0012
329 //#define RC_TINY 1.69e-38 //as in Numer. recepies
330 //#define RC_SQRTNY 1.3e-19 //as in Numer. recepies
331 //#define RC_BIG 3.e37 //as in Numer. recepies
332 #define RC_TINY ( DBL_MIN * 5. )
333 #define RC_SQRTNY ( sqrt( RC_TINY ) )
334 #define RC_BIG ( DBL_MAX / 5. )
335 #define RC_TNBG ( RC_TINY * RC_BIG )
336 #define RC_COMP1 ( 2.236/RC_SQRTNY )
337 #define RC_COMP2 ( RC_TNBG * RC_TNBG/25.0 )
338 #define RC_THIRD ( 1.0/3.0)
339 #define RC_C1 0.3
340 #define RC_C2 ( 1.0/7.0 )
341 #define RC_C3 0.375
342 #define RC_C4 ( 9.0/22.0 )
343 
344 double legendreIntegrals::rc( double x, double y )
345 {
346  double alamb, ave, s, w, xt, yt;
347  if ( x < 0.0 || y == 0.0 || ( x + ABS( y ) ) < RC_TINY ||
348  ( x + ABS( y ) ) > RC_BIG || ( y <- RC_COMP1 && x > 0.0 && x < RC_COMP2 ) ){
349  _errorr( "legendreIntegrals::rc: invalid argument(s)\n" );
350  }
351 
352  if( y > 0.0 ){
353  xt = x;
354  yt = y;
355  w = 1.0;
356  }
357  else{
358  xt = x - y;
359  yt = -y;
360  w = sqrt( x )/sqrt( xt );
361  }
362 
363  do{
364  alamb = 2.0 * sqrt( xt ) * sqrt( yt ) + yt;
365  xt = 0.25 * ( xt + alamb );
366  yt = 0.25 * ( yt + alamb );
367  ave = RC_THIRD * ( xt + yt + yt );
368  s = ( yt - ave )/ave;
369  }while( fabs( s ) > RC_ERRTOL );
370 
371  return( w * ( 1.0 + s * s * ( RC_C1 + s * ( RC_C2 + s * ( RC_C3 + s * RC_C4 ) ) ) )/sqrt( ave ) );
372 }//end of function: rc()
373 
374 
375 } // end of namespace mumech
376 
377 /*end of file*/
#define MAX(a, b)
Definition: macros.h:101
#define RC_ERRTOL
static double rc(double x, double y)
Solution of Carlson&#39;s degenerate elliptic integral - numerical recepies.
#define RJ_C6
#define RD_BIG
General functions.
Class legendreIntegrals.
#define RF_TINY
#define RC_THIRD
static double rf(double x, double y, double z)
Solution of Carlson&#39;s integral of the first kind - numerical recepies.
static double ellf(double phi, double ak)
Function calculating the Legendre&#39;s integral of the first kind - numerical recepies.
#define RD_TINY
#define RF_C3
static double ellpi(double phi, double en, double ak)
Function calculating the Legendre&#39;s integral of the third kind - numerical recepies.
#define RC_C1
#define RJ_C2
#define RD_C4
The header file of usefull macros.
#define RF_BIG
static double rj(double x, double y, double z, double p)
Solution of Carlson&#39;s integral of the third kind - numerical recepies.
#define MIN(a, b)
Definition: macros.h:100
#define RC_C2
#define RD_C1
#define ABS(a)
Definition: macros.h:118
#define RJ_C4
#define RC_TINY
#define RD_C6
static double rd(double x, double y, double z)
Solution of Carlson&#39;s integral of the seccond kind - numerical recepies.
#define RD_ERRTOL
#define SQR(a)
Definition: macros.h:97
#define RF_C2
#define RJ_C1
#define _errorr(_1)
Definition: gelib.h:160
#define RC_C4
#define RJ_C3
#define RC_COMP2
#define RC_C3
#define RF_THIRD
#define RC_BIG
#define RF_ERRTOL
#define RF_C1
#define _errorr1(_1)
Definition: gelib.h:153
#define RJ_TINY
#define RD_C5
static double elle(double phi, double ak)
Function calculating the Legendre&#39;s integral of the seccond kind - numerical recepies.
#define RJ_C7
#define RD_C3
#define RJ_C8
#define RF_C4
#define RD_C2
#define RJ_BIG
#define RJ_C5
#define RJ_ERRTOL