Legendre.cpp (getdp-3.4.0-source.tgz) | : | Legendre.cpp (getdp-3.5.0-source.tgz) | ||
---|---|---|---|---|
// GetDP - Copyright (C) 1997-2021 P. Dular and C. Geuzaine, University of Liege | // GetDP - Copyright (C) 1997-2022 P. Dular and C. Geuzaine, University of Liege | |||
// | // | |||
// See the LICENSE.txt file for license information. Please report all | // See the LICENSE.txt file for license information. Please report all | |||
// issues on https://gitlab.onelab.info/getdp/getdp/issues. | // issues on https://gitlab.onelab.info/getdp/getdp/issues. | |||
// | // | |||
// Contributor(s): | // Contributor(s): | |||
// Ruth Sabariego | // Ruth Sabariego | |||
// | // | |||
#include <math.h> | #include <math.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include "Message.h" | #include "Message.h" | |||
#define THESIGN(a) ((a)>=0 ? 1 : -1) | #define THESIGN(a) ((a) >= 0 ? 1 : -1) | |||
#define THEABS(a) ((a)>=0 ? a : -a) | #define THEABS(a) ((a) >= 0 ? a : -a) | |||
#define ONE_OVER_FOUR_PI 7.9577471545947668E-02 | #define ONE_OVER_FOUR_PI 7.9577471545947668E-02 | |||
double Factorial(double n) | double Factorial(double n) | |||
{ | { | |||
/* FACTORIAL(n) is the product of all the integers from 1 to n */ | /* FACTORIAL(n) is the product of all the integers from 1 to n */ | |||
double F ; | double F; | |||
if ( n < 0 ){ | if(n < 0) { | |||
Message::Error("Factorial(n): n must be a positive integer") ; | Message::Error("Factorial(n): n must be a positive integer"); | |||
return 0; | return 0; | |||
} | } | |||
if ( n == 0 ) return 1. ; | if(n == 0) return 1.; | |||
if ( n <= 2 ) return n ; | if(n <= 2) return n; | |||
F = n ; | F = n; | |||
while ( n > 2 ){ n-- ; F *= n ; } | while(n > 2) { | |||
n--; | ||||
F *= n; | ||||
} | ||||
return F; | return F; | |||
} | } | |||
double BinomialCoef(double n, double m) | double BinomialCoef(double n, double m) | |||
{ | { | |||
/* Binomial Coefficients: (n m) Computes de number of ways of | /* Binomial Coefficients: (n m) Computes de number of ways of | |||
choosing m objects from a collection of n distinct objects */ | choosing m objects from a collection of n distinct objects */ | |||
int i ; | int i; | |||
double B = 1. ; | double B = 1.; | |||
if (m==0 || n==m) return 1. ; | if(m == 0 || n == m) return 1.; | |||
for(i = (int)n ; i > m ; i--) | for(i = (int)n; i > m; i--) B *= (double)i / (double)(i - m); | |||
B *= (double)i/(double)(i-m); | ||||
return B; | return B; | |||
} | } | |||
double Legendre(int l, int m, double x) | double Legendre(int l, int m, double x) | |||
{ | { | |||
/* Computes the associated Legendre polynomial P_l^m(x). Here the | /* Computes the associated Legendre polynomial P_l^m(x). Here the | |||
degree l and the order m are the integers satisfying -l<=m<=l, | degree l and the order m are the integers satisfying -l<=m<=l, | |||
while x lies in the range -1<=x<=1 */ | while x lies in the range -1<=x<=1 */ | |||
double fact, pll=0., pmm, pmmp1, somx2, Cte ; | double fact, pll = 0., pmm, pmmp1, somx2, Cte; | |||
int i, ll; | int i, ll; | |||
if ( THEABS(m) > l || fabs(x) > 1.){ | if(THEABS(m) > l || fabs(x) > 1.) { | |||
Message::Error("Bad arguments for Legendre: P_l^m(x) with -l<=m<=l (int)," | Message::Error("Bad arguments for Legendre: P_l^m(x) with -l<=m<=l (int)," | |||
" -1<=x<=1 l = %d m = %d x = %.8g", l, m, x); | " -1<=x<=1 l = %d m = %d x = %.8g", | |||
l, m, x); | ||||
return 0.; | return 0.; | |||
} | } | |||
Cte = (m > 0) ? 1. : Factorial((double)(l-THEABS(m))) / | Cte = (m > 0) ? | |||
Factorial((double)(l+THEABS(m))) * pow(-1.,(double)THEABS(m)) ; | 1. : | |||
m = THEABS(m) ; | Factorial((double)(l - THEABS(m))) / | |||
Factorial((double)(l + THEABS(m))) * pow(-1., (double)THEABS(m)); | ||||
pmm = 1. ; | m = THEABS(m); | |||
if (m > 0) { | pmm = 1.; | |||
somx2 = sqrt((1.-x)*(1.+x)) ; | ||||
fact = 1. ; | if(m > 0) { | |||
for (i=1;i<=m;i++){ | somx2 = sqrt((1. - x) * (1. + x)); | |||
pmm *= -fact*somx2 ; | fact = 1.; | |||
fact += 2. ; | for(i = 1; i <= m; i++) { | |||
pmm *= -fact * somx2; | ||||
fact += 2.; | ||||
} | } | |||
} | } | |||
if (l==m){ | if(l == m) { return Cte * pmm; } | |||
return Cte*pmm ; | ||||
} | ||||
else { | else { | |||
pmmp1 = x * (2*m+1)*pmm ; | pmmp1 = x * (2 * m + 1) * pmm; | |||
if (l==(m+1)){ | if(l == (m + 1)) { return Cte * pmmp1; } | |||
return Cte*pmmp1 ; | ||||
} | ||||
else { | else { | |||
for (ll=(m+2);ll<=l;ll++) { | for(ll = (m + 2); ll <= l; ll++) { | |||
pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m) ; | pll = (x * (2 * ll - 1) * pmmp1 - (ll + m - 1) * pmm) / (ll - m); | |||
pmm = pmmp1 ; | pmm = pmmp1; | |||
pmmp1 = pll ; | pmmp1 = pll; | |||
} | } | |||
return Cte*pll ; | return Cte * pll; | |||
} | } | |||
} | } | |||
} | } | |||
void LegendreRecursive(int l, int m, double x, double P[]) | void LegendreRecursive(int l, int m, double x, double P[]) | |||
{ | { | |||
/* Computes recursively a (l+1)-terms sequence of the associated | /* Computes recursively a (l+1)-terms sequence of the associated | |||
Legendre polynomial P_l^m(x). | Legendre polynomial P_l^m(x). | |||
l and m are the integers satisfying 0<=m<=l | l and m are the integers satisfying 0<=m<=l | |||
x lies in the range -1<=x<=1 | x lies in the range -1<=x<=1 | |||
l = maximum order considered, m = invariable */ | l = maximum order considered, m = invariable */ | |||
int il ; | int il; | |||
double Pl_m, Plm1_m ; | double Pl_m, Plm1_m; | |||
P[0] = Plm1_m = Legendre(0, m, x) ; | P[0] = Plm1_m = Legendre(0, m, x); | |||
P[1] = Pl_m = Legendre(1, m, x) ; | P[1] = Pl_m = Legendre(1, m, x); | |||
if (l >=2) | if(l >= 2) | |||
for(il = 1 ; il < l ; il ++){ | for(il = 1; il < l; il++) { | |||
P[il+1] = (2*il+1)*x*Pl_m/(il-m+1) + (il+m)*Plm1_m/(m-il-1) ; | P[il + 1] = (2 * il + 1) * x * Pl_m / (il - m + 1) + | |||
Plm1_m = Pl_m ; | (il + m) * Plm1_m / (m - il - 1); | |||
Pl_m = P[il+1]; | Plm1_m = Pl_m; | |||
Pl_m = P[il + 1]; | ||||
} | } | |||
} | } | |||
void LegendreRecursiveM(int l, double x, double P[]) | void LegendreRecursiveM(int l, double x, double P[]) | |||
{ | { | |||
/* Computes recursively a (l+1)-terms sequence of the associated | /* Computes recursively a (l+1)-terms sequence of the associated | |||
Legendre polynomial P_l^m(x). | Legendre polynomial P_l^m(x). | |||
x lies in the range -1<=x<=1, l = invariable, -l<=m<=l */ | x lies in the range -1<=x<=1, l = invariable, -l<=m<=l */ | |||
int m ; | int m; | |||
double Pl_m, Plm1_m ; | double Pl_m, Plm1_m; | |||
if (fabs(x) == 1.) | if(fabs(x) == 1.) | |||
for(m = -l ; m <= l ; m ++) | for(m = -l; m <= l; m++) | |||
P[l+m] = (m==0) ? pow(THESIGN(x),(double)l) : 0. ; | P[l + m] = (m == 0) ? pow(THESIGN(x), (double)l) : 0.; | |||
else{ | else { | |||
if (l==0){ | if(l == 0) { | |||
P[0] = Legendre(0, 0, x) ; | P[0] = Legendre(0, 0, x); | |||
return; | return; | |||
} | } | |||
P[0] = Plm1_m = Legendre(l, -l, x) ; | P[0] = Plm1_m = Legendre(l, -l, x); | |||
P[1] = Pl_m = Legendre(l, -l+1, x) ; | P[1] = Pl_m = Legendre(l, -l + 1, x); | |||
if (l >= 1) | if(l >= 1) | |||
for(m = -l+1 ; m < l ; m ++){ | for(m = -l + 1; m < l; m++) { | |||
P[l+m+1] = -2*m*x*Pl_m/sqrt(1-x*x) + (m*(m-1)-l*(l+1))*Plm1_m ; | P[l + m + 1] = -2 * m * x * Pl_m / sqrt(1 - x * x) + | |||
Plm1_m = Pl_m ; | (m * (m - 1) - l * (l + 1)) * Plm1_m; | |||
Pl_m = P[l+m+1]; | Plm1_m = Pl_m; | |||
Pl_m = P[l + m + 1]; | ||||
} | } | |||
else return ; | else | |||
return; | ||||
} | } | |||
} | } | |||
double dLegendre (int l, int m, double x) | double dLegendre(int l, int m, double x) | |||
{ | { | |||
/* Computes the derivative of the associated Legendre polynomial | /* Computes the derivative of the associated Legendre polynomial | |||
P_l^m(x) */ | P_l^m(x) */ | |||
double dpl; | double dpl; | |||
if ( THEABS(m) > l || fabs(x) > 1.){ | if(THEABS(m) > l || fabs(x) > 1.) { | |||
Message::Error("Bad arguments for dLegendre: -l<=m<=l (integers), -1<=x<=1." | Message::Error("Bad arguments for dLegendre: -l<=m<=l (integers), -1<=x<=1." | |||
" Current values: l %d m %d x %.8g", l, m, x) ; | " Current values: l %d m %d x %.8g", | |||
l, m, x); | ||||
return 0.; | return 0.; | |||
} | } | |||
if (fabs(x)==1.) dpl = 0.; | if(fabs(x) == 1.) | |||
dpl = 0.; | ||||
else | else | |||
dpl = ((l+m)*(l-m+1)*sqrt(1-x*x)*((THEABS((m-1))>l) ? 0. : | dpl = ((l + m) * (l - m + 1) * sqrt(1 - x * x) * | |||
Legendre(l, m-1, x)) + m*x* Legendre (l,m,x))/(1-x*x); | ((THEABS((m - 1)) > l) ? 0. : Legendre(l, m - 1, x)) + | |||
m * x * Legendre(l, m, x)) / | ||||
(1 - x * x); | ||||
return dpl; | return dpl; | |||
} | } | |||
double dLegendreFinDif (int l, int m, double x) | double dLegendreFinDif(int l, int m, double x) | |||
{ | { | |||
/* Computes the derivative of the associated Legendre polynomial | /* Computes the derivative of the associated Legendre polynomial | |||
P_l^m(x) using Finite Differences: f'(x) = (f(x+\delta | P_l^m(x) using Finite Differences: f'(x) = (f(x+\delta | |||
x)-f(x-\delta x))/(2 \delta) */ | x)-f(x-\delta x))/(2 \delta) */ | |||
double dpl, delta = 1e-6; | double dpl, delta = 1e-6; | |||
if ( THEABS(m) > l || fabs(x) > 1.){ | if(THEABS(m) > l || fabs(x) > 1.) { | |||
Message::Error("Bad arguments for dLegendreFinDif: -l<=m<=l (integers), " | Message::Error("Bad arguments for dLegendreFinDif: -l<=m<=l (integers), " | |||
"-1<=x<=1. Current values: l %d m %d x %.8g", l, m, x ); | "-1<=x<=1. Current values: l %d m %d x %.8g", | |||
l, m, x); | ||||
return 0.; | return 0.; | |||
} | } | |||
dpl = (Legendre (l, m, x+delta) - Legendre (l, m, x-delta))/(2*delta); | dpl = (Legendre(l, m, x + delta) - Legendre(l, m, x - delta)) / (2 * delta); | |||
return dpl; | return dpl; | |||
} | } | |||
void SphericalHarmonics(int l, int m, double Theta, double Phi, double Yl_m[]) | void SphericalHarmonics(int l, int m, double Theta, double Phi, double Yl_m[]) | |||
{ | { | |||
int am ; | int am; | |||
double cn, Pl_m, F, cRe ; | double cn, Pl_m, F, cRe; | |||
cn = sqrt((2*l+1)*ONE_OVER_FOUR_PI) ; /* Normalization Factor */ | cn = sqrt((2 * l + 1) * ONE_OVER_FOUR_PI); /* Normalization Factor */ | |||
am = THESIGN(m)*m ; | am = THESIGN(m) * m; | |||
F= sqrt(Factorial((double)(l-am))/ Factorial((double)(l+am))) ; | F = sqrt(Factorial((double)(l - am)) / Factorial((double)(l + am))); | |||
Pl_m = Legendre(l, am, cos(Theta)); | Pl_m = Legendre(l, am, cos(Theta)); | |||
cRe = cn * F * Pl_m ; | cRe = cn * F * Pl_m; | |||
Yl_m[0] = cRe*cos(m*Phi) ; | Yl_m[0] = cRe * cos(m * Phi); | |||
Yl_m[1] = cRe*sin(m*Phi) ; | Yl_m[1] = cRe * sin(m * Phi); | |||
} | } | |||
End of changes. 38 change blocks. | ||||
87 lines changed or deleted | 95 lines changed or added |