| 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_teta(int lmax,int m,double teta,double *xlm)
 | 
|---|
| 43 | {
 | 
|---|
| 44 |  // Debug level
 | 
|---|
| 45 |  const int lp=0;
 | 
|---|
| 46 |  // Si une valeur finale est <10^EXPO_MINI on retourne zero
 | 
|---|
| 47 |  const double EXPO_MINI = DBL_MIN_10_EXP +5;
 | 
|---|
| 48 |  // Si une valeur dans la reccurence est <FACTMINI on renormalise
 | 
|---|
| 49 |  const double FACTMINI = 1.e-50;
 | 
|---|
| 50 | 
 | 
|---|
| 51 |  if(m<0 || m>lmax) {
 | 
|---|
| 52 |    cout<<"HarmSph_array_Error: bad arguments lmax="<<lmax<<" m="<<m<<endl;
 | 
|---|
| 53 |    return(0.);
 | 
|---|
| 54 |  }
 | 
|---|
| 55 | 
 | 
|---|
| 56 |  double x = cos(teta);
 | 
|---|
| 57 |  if(lp) cout<<"HarmSph_array_teta: x="<<x<<" lmax="<<lmax<<" m="<<m<<endl;
 | 
|---|
| 58 | 
 | 
|---|
| 59 |  /* ---- calcul Psph(0,0) = 1/sqrt(4Pi) */
 | 
|---|
| 60 |  xlm[0] = M_2_SQRTPI/4.;
 | 
|---|
| 61 |  if(m==0 && lmax==0) return xlm[0];
 | 
|---|
| 62 | 
 | 
|---|
| 63 |  /* ---- calcul Psph(m,m):
 | 
|---|
| 64 |  Recurrence:
 | 
|---|
| 65 |    P(l,m) = (-1)^m * (2m-1)!! * (1-x^2)^(m/2)
 | 
|---|
| 66 |    Psph(m+1,m+1) = -Psph(m,m) * sin(teta)*sqrt((2m+3)/(2m+2))
 | 
|---|
| 67 |    ou Psph(m,m) = - Psph(m-1,m-1) * sin(teta)*sqrt((2m+1)/2m)
 | 
|---|
| 68 |    et Psph(0,0) = 1/sqrt(4Pi)
 | 
|---|
| 69 |  Pb: pour m grand et sin(teta) petit sin(teta)^m devient
 | 
|---|
| 70 |      plus petit que la limite machine (1e-300) et on obtient zero
 | 
|---|
| 71 |  */
 | 
|---|
| 72 |  double expos = 0.;
 | 
|---|
| 73 |  if(m>0) {          // Psph(0,0) == xlm[0]
 | 
|---|
| 74 |    //double st = sqrt((1.-x)*(1.+x));
 | 
|---|
| 75 |    double st = fabs(sin(teta));
 | 
|---|
| 76 |    for(int i=1;i<=m;i++) {
 | 
|---|
| 77 |      xlm[0] *= -sqrt(((double)i+0.5)/(double)i) *st;
 | 
|---|
| 78 |      double fxlm = fabs(xlm[0]);
 | 
|---|
| 79 |      if(fxlm<FACTMINI && fxlm>0.) {
 | 
|---|
| 80 |        if(lp>1) cout<<i<<" renorm: xlm[0]="<<xlm[0]<<" e="<<log10(fxlm);
 | 
|---|
| 81 |        xlm[0] = (xlm[0]>0.)? 1.: -1.;
 | 
|---|
| 82 |        expos += log10(fxlm);
 | 
|---|
| 83 |        if(lp>1) cout<<" --> "<<xlm[0]<<", expos="<<expos<<endl;
 | 
|---|
| 84 |      }
 | 
|---|
| 85 |    }
 | 
|---|
| 86 |  }
 | 
|---|
| 87 |  if(lp) cout<<"End computing Pmm="<<xlm[0]<<", expos="<<expos<<endl;
 | 
|---|
| 88 | 
 | 
|---|
| 89 |  /* ---- calcul Psph(m+1,m):
 | 
|---|
| 90 |  Formule:
 | 
|---|
| 91 |    P(m+1,m) = cos(teta)*sqrt(2m+1)*P(m,m)
 | 
|---|
| 92 |    Psph(m+1,m) = cos(teta)*sqrt(2m+3)*Psph(m,m)
 | 
|---|
| 93 |  En fait cela s'integre sans probleme dans la recurrence generale ci-dessous
 | 
|---|
| 94 |  */
 | 
|---|
| 95 |  /* ---- calcul de Psph(l,m)  pour l>m+1 :
 | 
|---|
| 96 |  Recurrence:
 | 
|---|
| 97 |    P(l,m)  = [ (2l-1)*x * P(l-1,m) - (l-1+m) * P(l-2,m) ] / (l-m)
 | 
|---|
| 98 |    Psph(l,m) = sqrt((4*l^2-1)/(l^2-m^2))
 | 
|---|
| 99 |              * [ cos(teta) * Psph(l-1,m)
 | 
|---|
| 100 |                - sqrt(((l-1)^2-m^2)/(4*(l-1)^2-1)) * Psph(l-2,m) ]
 | 
|---|
| 101 |    Psph(l,m) = sqrt((2l-1)*(2l+1)/((l-m)*(l+m)))
 | 
|---|
| 102 |              * [ cos(teta) * Psph(l-1,m)
 | 
|---|
| 103 |                - sqrt((l-m-1)*(l-1+m)/((2l-3)*(2l-1))) * Psph(l-2,m) ]
 | 
|---|
| 104 | 
 | 
|---|
| 105 |  */
 | 
|---|
| 106 |  if(lmax>m) {
 | 
|---|
| 107 |    const double expo_factmini = log10(FACTMINI);
 | 
|---|
| 108 |    double factmaxi = 1./FACTMINI;
 | 
|---|
| 109 |    double pm2=0., pm1=xlm[0], b_rec=0.;
 | 
|---|
| 110 |    for(int ll=m+1;ll<=lmax;ll++) {
 | 
|---|
| 111 |      int il = ll-m;
 | 
|---|
| 112 |      double a_rec = sqrt( (2.*ll-1.)*(2.*ll+1.)/((ll-m)*(ll+m)) );
 | 
|---|
| 113 |      xlm[il] = a_rec*(x*pm1-b_rec*pm2);
 | 
|---|
| 114 |      double fxlm = fabs(xlm[il]);
 | 
|---|
| 115 |      // Par construction "expos" est negatif ou nul (car FACTMINI<1)
 | 
|---|
| 116 |      if(expos<0. && fxlm>factmaxi) {
 | 
|---|
| 117 |        // On renormalise par factmaxi si on a encore de la reserve d'exposant
 | 
|---|
| 118 |        double fact,efact;
 | 
|---|
| 119 |        if(expos<expo_factmini) {
 | 
|---|
| 120 |          fact  = factmaxi;
 | 
|---|
| 121 |          efact = -expo_factmini;
 | 
|---|
| 122 |          expos += efact;
 | 
|---|
| 123 |        } else {
 | 
|---|
| 124 |          fact = pow(10.,expos);
 | 
|---|
| 125 |          efact = expos;
 | 
|---|
| 126 |          expos = 0.;
 | 
|---|
| 127 |          if(lp>1) cout<<"!! expos==0 !!"<<endl;
 | 
|---|
| 128 |        }
 | 
|---|
| 129 |        if(lp>1) cout<<ll<<" renorm: xlm["<<il<<"]="<<xlm[il]<<", expos="<<expos<<endl;
 | 
|---|
| 130 |        for(int i=0;i<=ll-m;i++) xlm[i] /= fact;
 | 
|---|
| 131 |      }
 | 
|---|
| 132 |      pm2 = xlm[il-1];
 | 
|---|
| 133 |      pm1 = xlm[il];
 | 
|---|
| 134 |      b_rec = 1./a_rec;
 | 
|---|
| 135 |    }
 | 
|---|
| 136 |  }
 | 
|---|
| 137 | 
 | 
|---|
| 138 |  if(lp) cout<<"Return: Final expos="<<expos<<endl;
 | 
|---|
| 139 |  if(expos!=0.) {
 | 
|---|
| 140 |    for(int i=0;i<=lmax-m;i++) {
 | 
|---|
| 141 |      double fxml=fabs(xlm[i]);
 | 
|---|
| 142 |      if(lp>1) cout<<"     xlm["<<i<<"]="<<xlm[i];
 | 
|---|
| 143 |      if(fxml>0.) {
 | 
|---|
| 144 |        double e = log10(fxml);
 | 
|---|
| 145 |        if(lp>1) cout<<" (e="<<e<<")";
 | 
|---|
| 146 |        if(expos+e<EXPO_MINI) xlm[i] = 0.;
 | 
|---|
| 147 |        else if(expos>EXPO_MINI) xlm[i] *= pow(10.,expos);
 | 
|---|
| 148 |        else xlm[i] = pow(10.,expos+e);
 | 
|---|
| 149 |      }
 | 
|---|
| 150 |      if(lp>1) cout<<" ---> "<<xlm[i]<<endl;
 | 
|---|
| 151 |    }
 | 
|---|
| 152 |  }
 | 
|---|
| 153 |  return xlm[lmax-m];
 | 
|---|
| 154 | 
 | 
|---|
| 155 | }
 | 
|---|