source: Sophya/trunk/SophyaLib/Samba/harmspher.cc@ 2634

Last change on this file since 2634 was 2634, checked in by cmv, 21 years ago

theta part of spherical harmonics, stand-alone routine cmv 19/11/04

File size: 4.9 KB
Line 
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
9using 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
42double 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
48double 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}
Note: See TracBrowser for help on using the repository browser.