1 | #include <stdlib.h>
|
---|
2 | #include <stdio.h>
|
---|
3 | #include "machdefs.h"
|
---|
4 | #include <iostream>
|
---|
5 | #include <float.h>
|
---|
6 | #include <math.h>
|
---|
7 | #include "harmspher.h"
|
---|
8 |
|
---|
9 | using namespace std;
|
---|
10 |
|
---|
11 | /*
|
---|
12 | ----------------------------------------------------------------
|
---|
13 | ----- Calcul des fonctions de Legendre Plm(cos(Theta)) ------
|
---|
14 | ----------------------------------------------------------------
|
---|
15 | (partie theta des harmoniques spheriques)
|
---|
16 |
|
---|
17 | HarmSph_array(int lmax,int m,double cost,double *Plm)
|
---|
18 | HarmSph_array_teta(int lmax,int m,double teta,double *Plm)
|
---|
19 |
|
---|
20 | - Input:
|
---|
21 | lmax, m and teta or cos(teta) (lmax>=m)
|
---|
22 | array Plm with size at least "lmax-m+1"
|
---|
23 | (calling with HarmSph_array_teta for small teta is more accurate)
|
---|
24 |
|
---|
25 | - Action:
|
---|
26 | compute Psph for fixed "m" and all "l" from "m" to "lmax"
|
---|
27 |
|
---|
28 | - Return array: Psph(l,m)
|
---|
29 | index Psph(l,m) = Plm[l-m]
|
---|
30 |
|
---|
31 | - Return value:
|
---|
32 | Psph(lmax,m) = Plm[lmax-m]
|
---|
33 |
|
---|
34 | - Rappel: x = cos(teta)
|
---|
35 | Polynomes de Legendre associes: P(l,m)
|
---|
36 | Polynomes de Legendre pour les harmoniques spheriques: Psph(l,m)
|
---|
37 | (souvent appelles lambda_lm)
|
---|
38 | Psph(l,m) = sqrt((2l+1)/4Pi) * sqrt((l-m)!/(l+m)!) * P(l,m)
|
---|
39 | ----------------------------------------------------------------
|
---|
40 | */
|
---|
41 |
|
---|
42 | double HarmSph_array(int lmax,int m,double x,double *xlm)
|
---|
43 | {
|
---|
44 | if(x>1.) x=1.; else if(x<-1.) x=-1.;
|
---|
45 | return HarmSph_array_teta(lmax,m,acos(x),xlm);
|
---|
46 | }
|
---|
47 |
|
---|
48 | double HarmSph_array_teta(int lmax,int m,double teta,double *xlm)
|
---|
49 | {
|
---|
50 | // Debug level
|
---|
51 | const int lp=0;
|
---|
52 | // Si une valeur finale est <10^EXPO_MINI on retourne zero
|
---|
53 | const double EXPO_MINI = DBL_MIN_10_EXP +5;
|
---|
54 | // Si une valeur dans la reccurence est <FACTMINI on renormalise
|
---|
55 | const double FACTMINI = 1.e-50;
|
---|
56 |
|
---|
57 | if(m<0 || m>lmax) {
|
---|
58 | cout<<"HarmSph_array_Error: bad arguments lmax="<<lmax<<" m="<<m<<endl;
|
---|
59 | return(0.);
|
---|
60 | }
|
---|
61 |
|
---|
62 | double x = cos(teta);
|
---|
63 | if(lp) cout<<"HarmSph_array_teta: x="<<x<<" lmax="<<lmax<<" m="<<m<<endl;
|
---|
64 |
|
---|
65 | /* ---- calcul Psph(0,0) = 1/sqrt(4Pi) */
|
---|
66 | xlm[0] = M_2_SQRTPI/4.;
|
---|
67 | if(m==0 && lmax==0) return xlm[0];
|
---|
68 |
|
---|
69 | /* ---- calcul Psph(m,m):
|
---|
70 | Recurrence:
|
---|
71 | P(l,m) = (-1)^m * (2m-1)!! * (1-x^2)^(m/2)
|
---|
72 | Psph(m+1,m+1) = -Psph(m,m) * sin(teta)*sqrt((2m+3)/(2m+2))
|
---|
73 | ou Psph(m,m) = - Psph(m-1,m-1) * sin(teta)*sqrt((2m+1)/2m)
|
---|
74 | et Psph(0,0) = 1/sqrt(4Pi)
|
---|
75 | Pb: pour m grand et sin(teta) petit sin(teta)^m devient
|
---|
76 | plus petit que la limite machine (1e-300) et on obtient zero
|
---|
77 | */
|
---|
78 | double expos = 0.;
|
---|
79 | if(m>0) { // Psph(0,0) == xlm[0]
|
---|
80 | //double st = sqrt((1.-x)*(1.+x));
|
---|
81 | double st = fabs(sin(teta));
|
---|
82 | for(int i=1;i<=m;i++) {
|
---|
83 | xlm[0] *= -sqrt(((double)i+0.5)/(double)i) *st;
|
---|
84 | double fxlm = fabs(xlm[0]);
|
---|
85 | if(fxlm<FACTMINI && fxlm>0.) {
|
---|
86 | if(lp>1) cout<<i<<" renorm: xlm[0]="<<xlm[0]<<" e="<<log10(fxlm);
|
---|
87 | xlm[0] = (xlm[0]>0.)? 1.: -1.;
|
---|
88 | expos += log10(fxlm);
|
---|
89 | if(lp>1) cout<<" --> "<<xlm[0]<<", expos="<<expos<<endl;
|
---|
90 | }
|
---|
91 | }
|
---|
92 | }
|
---|
93 | if(lp) cout<<"End computing Pmm="<<xlm[0]<<", expos="<<expos<<endl;
|
---|
94 |
|
---|
95 | /* ---- calcul Psph(m+1,m):
|
---|
96 | Formule:
|
---|
97 | P(m+1,m) = cos(teta)*(2m+1)*P(m,m)
|
---|
98 | Psph(m+1,m) = cos(teta)*(2m+3)*Psph(m,m)
|
---|
99 | En fait cela s'integre sans probleme dans la recurrence generale ci-dessous
|
---|
100 | */
|
---|
101 | /* ---- calcul de Psph(l,m) pour l>m+1 :
|
---|
102 | Recurrence:
|
---|
103 | P(l,m) = [ (2l-1)*x * P(l-1,m) - (l-1+m) * P(l-2,m) ] / (l-m)
|
---|
104 | Psph(l,m) = sqrt((4*l^2-1)/(l^2-m^2))
|
---|
105 | * [ cos(teta) * Psph(l-1,m)
|
---|
106 | - sqrt(((l-1)^2-m^2)/(4*(l-1)^2-1)) * Psph(l-2,m) ]
|
---|
107 | Psph(l,m) = sqrt((2l-1)*(2l+1)/((l-m)*(l+m)))
|
---|
108 | * [ cos(teta) * Psph(l-1,m)
|
---|
109 | - sqrt((l-m-1)*(l-1+m)/((2l-3)*(2l-1))) * Psph(l-2,m) ]
|
---|
110 |
|
---|
111 | */
|
---|
112 | if(lmax>m) {
|
---|
113 | const double expo_factmini = log10(FACTMINI);
|
---|
114 | double factmaxi = 1./FACTMINI;
|
---|
115 | double pm2=0., pm1=xlm[0], b_rec=0.;
|
---|
116 | for(int ll=m+1;ll<=lmax;ll++) {
|
---|
117 | int il = ll-m;
|
---|
118 | double a_rec = sqrt( (2.*ll-1.)*(2.*ll+1.)/((ll-m)*(ll+m)) );
|
---|
119 | xlm[il] = a_rec*(x*pm1-b_rec*pm2);
|
---|
120 | double fxlm = fabs(xlm[il]);
|
---|
121 | // Par construction "expos" est negatif ou nul (car FACTMINI<1)
|
---|
122 | if(expos<0. && fxlm>factmaxi) {
|
---|
123 | // On renormalise par factmaxi si on a encore de la reserve d'exposant
|
---|
124 | double fact,efact;
|
---|
125 | if(expos<expo_factmini) {
|
---|
126 | fact = factmaxi;
|
---|
127 | efact = -expo_factmini;
|
---|
128 | expos += efact;
|
---|
129 | } else {
|
---|
130 | fact = pow(10.,expos);
|
---|
131 | efact = expos;
|
---|
132 | expos = 0.;
|
---|
133 | if(lp>1) cout<<"!! expos==0 !!"<<endl;
|
---|
134 | }
|
---|
135 | if(lp>1) cout<<ll<<" renorm: xlm["<<il<<"]="<<xlm[il]<<", expos="<<expos<<endl;
|
---|
136 | for(int i=0;i<=ll-m;i++) xlm[i] /= fact;
|
---|
137 | }
|
---|
138 | pm2 = xlm[il-1];
|
---|
139 | pm1 = xlm[il];
|
---|
140 | b_rec = 1./a_rec;
|
---|
141 | }
|
---|
142 | }
|
---|
143 |
|
---|
144 | if(lp) cout<<"Return: Final expos="<<expos<<endl;
|
---|
145 | if(expos!=0.) {
|
---|
146 | for(int i=0;i<=lmax-m;i++) {
|
---|
147 | double e = log10(fabs(xlm[i]));
|
---|
148 | if(lp>1) cout<<" xlm["<<i<<"]="<<xlm[i]<<" (e="<<e<<")";
|
---|
149 | if(expos+e<EXPO_MINI) xlm[i] = 0.;
|
---|
150 | else if(expos>EXPO_MINI) xlm[i] *= pow(10.,expos);
|
---|
151 | else xlm[i] = pow(10.,expos+e);
|
---|
152 | if(lp>1) cout<<" ---> "<<xlm[i]<<endl;
|
---|
153 | }
|
---|
154 | }
|
---|
155 | return xlm[lmax-m];
|
---|
156 |
|
---|
157 | }
|
---|