| 1 | #include "machdefs.h" | 
|---|
| 2 | #include <iostream> | 
|---|
| 3 | #include <stdlib.h> | 
|---|
| 4 | #include <stdio.h> | 
|---|
| 5 | #include <string.h> | 
|---|
| 6 | #include <math.h> | 
|---|
| 7 |  | 
|---|
| 8 | #include "pexceptions.h" | 
|---|
| 9 |  | 
|---|
| 10 | #include "constcosmo.h" | 
|---|
| 11 | #include "planckspectra.h" | 
|---|
| 12 |  | 
|---|
| 13 | namespace SOPHYA { | 
|---|
| 14 |  | 
|---|
| 15 | /* | 
|---|
| 16 | ---------------------------------------------------------------- | 
|---|
| 17 | - UNITES: | 
|---|
| 18 | Temperature en Kelvin  "K" | 
|---|
| 19 | Frequence en GigaHertz  "Hz" | 
|---|
| 20 | Longueur d'onde en Metre  "m" | 
|---|
| 21 | ---------------------------------------------------------------- | 
|---|
| 22 | - Frequence / Longeur d'onde | 
|---|
| 23 | l = c/f ; f = c/l | 
|---|
| 24 | dl = c/f^2 df = l^2/c df | 
|---|
| 25 | df = c/l^2 dl = f^2/c dl | 
|---|
| 26 | P[f] df = P[l] dl = P[f] c/l^2 dl = P[l] c/f^2 df | 
|---|
| 27 | ---------------------------------------------------------------- | 
|---|
| 28 | - Lois de Planck Wien et Rayleigh | 
|---|
| 29 | Planck   H*Nu/(K*T) = H*C/(Lambda*K*T) quelconque | 
|---|
| 30 | Wien     H*Nu/(K*T) = H*C/(Lambda*K*T) >> 1 | 
|---|
| 31 | Rayleigh H*Nu/(K*T) = H*C/(Lambda*K*T) << 1 | 
|---|
| 32 | ---------------------------------------------------------------- | 
|---|
| 33 | - Les termes en facteur pour les lois de Planck Wien et Rayleigh | 
|---|
| 34 | (la partie contenant l'exponentielle) | 
|---|
| 35 | ainsi que pour les derivees des ces termes par rapport a la temperature | 
|---|
| 36 | Planck:   1/[exp(H*f/(K*t))-1] = 1/[exp(HC/(l*K*t))-1] | 
|---|
| 37 | der=  H*f/(K*t) /t * exp(HC/(l*K*t))/[exp(HC/(l*K*t))-1]^2 | 
|---|
| 38 | Wien:     1/exp(H*f/(K*t)) | 
|---|
| 39 | der=  H*f/(K*t) /t /exp(H*f/(K*t)) | 
|---|
| 40 | Rayleigh: 1/(H*f/(K*t)) | 
|---|
| 41 | der=  K/(H*f) | 
|---|
| 42 | Pour x->0: compute exp(x)=1+x+x^2/2 for 1/(exp(x)-1) | 
|---|
| 43 | soit 1/(exp(x)-1)  -> 1/(x+x^2/2) | 
|---|
| 44 | car exp(x)-1 vaut zero plus vite que son DL a cause de la soustraction | 
|---|
| 45 | ---------------------------------------------------------------- | 
|---|
| 46 | - RADIANCE (Brillance) en fonction de nu ou lambda | 
|---|
| 47 | nombre de watts (ou photons par seconde) | 
|---|
| 48 | radies par unite de surface par steradian et par hertz (ou metre) | 
|---|
| 49 | 2*f^2/c^2   * 1/(exp()-1)    ph/s/m^2/Sr/Hz | 
|---|
| 50 | 2*h*f^3/c^2 * 1/(exp()-1)    W/m^2/Sr/Hz | 
|---|
| 51 | 2*c/l^4     * 1/(exp()-1)    ph/s/m^2/Sr/m | 
|---|
| 52 | 2*h*c^2/l^5 * 1/(exp()-1)    W/m^2/Sr/m | 
|---|
| 53 | ---------------------------------------------------------------- | 
|---|
| 54 | - EMITTANCE en fonction de nu ou lambda | 
|---|
| 55 | nombre de watts (ou photons par seconde) | 
|---|
| 56 | radies dans un hemisphere (2*PI sr) | 
|---|
| 57 | par unite de surface et par hertz (ou metre) | 
|---|
| 58 | ..quand on integre sur 2Pi sr il faut | 
|---|
| 59 | ..multiplier par cos(theta)  -> facteur Pi uniquement | 
|---|
| 60 | EMITTANCE = Pi * RADIANCE | 
|---|
| 61 | 2*Pi*f^2/c^2   * 1/(exp()-1)    ph/s/m^2/Hz | 
|---|
| 62 | 2*Pi*h*f^3/c^2 * 1/(exp()-1)    W/m^2/Hz | 
|---|
| 63 | 2*Pi*c/l^4     * 1/(exp()-1)    ph/s/m^2/m | 
|---|
| 64 | 2*Pi*h*c^2/l^5 * 1/(exp()-1)    W/m^2/m | 
|---|
| 65 | ---------------------------------------------------------------- | 
|---|
| 66 | - DENSITE en fonction de nu ou lambda | 
|---|
| 67 | nombre de joules (ou photons) par m^3  et par hertz (ou metre) | 
|---|
| 68 | DENSITE = 4*Pi/c * RADIANCE | 
|---|
| 69 | 8*Pi*f^2/c^3    * 1/(exp()-1)    ph/m^3/Hz | 
|---|
| 70 | 8*Pi*h*f^3/c^3  * 1/(exp()-1)    J/m^3/Hz | 
|---|
| 71 | 8*Pi/l^4        * 1/(exp()-1)    ph/m^3/m | 
|---|
| 72 | 8*Pi*h*c/l^5    * 1/(exp()-1)    J/m^3/m | 
|---|
| 73 | ---------------------------------------------------------------- | 
|---|
| 74 | - DENSITE d'energie totale  (loi de Stefan-Boltzman) | 
|---|
| 75 | 4*sigma*T^4/C   J/m^3 | 
|---|
| 76 | Sigma = 2*PI^5*K^4/(15.*C^2*H^3) = PI^2*K^4/(60.*Hbar^3*C2) | 
|---|
| 77 | ---------------------------------------------------------------- | 
|---|
| 78 | */ | 
|---|
| 79 |  | 
|---|
| 80 | /* | 
|---|
| 81 | POUR TESTER LES LIMITES DE L'EXPONENTIELLE: | 
|---|
| 82 | 1-/ copier/coller les lignes suivantes dans toto.icc | 
|---|
| 83 | double x=10.; | 
|---|
| 84 | for(int i=0;i<35;i++) { | 
|---|
| 85 | double ex = exp(x); | 
|---|
| 86 | double exm1a = x*(1.+x/2.*(1.+x/3.)),; | 
|---|
| 87 | printf("x=%g exp(x)=%e exp(x)-1=%e dl=%e (d=%e)\n",x,ex,ex-1.,exm1a,ex-1.-exm1a); | 
|---|
| 88 | x /= 10.; | 
|---|
| 89 | } | 
|---|
| 90 | 2-/ executer sous spiapp: > c++execfrf toto.icc | 
|---|
| 91 | */ | 
|---|
| 92 |  | 
|---|
| 93 |  | 
|---|
| 94 | #define MAXARGEXP 100.    /* maxi = 709.7827128933840 */ | 
|---|
| 95 | #define MINARGEXP 1.e-10  /* Replace exp(x) by DL for 1/(exp(x)-1) when x->0 */ | 
|---|
| 96 |  | 
|---|
| 97 | //************************************************************************ | 
|---|
| 98 | // vitesse de la lumiere en m/s | 
|---|
| 99 | double CinM_ = SpeedOfLight_Cst*1e+3; | 
|---|
| 100 | // h/k pour une frequence en Hz | 
|---|
| 101 | double HsK_ = h_Planck_Cst/k_Boltzman_Cst; | 
|---|
| 102 | // hc/k pour une longeur d'onde en metre | 
|---|
| 103 | double HCsK_ = h_Planck_Cst*CinM_/k_Boltzman_Cst; | 
|---|
| 104 |  | 
|---|
| 105 | //************************************************************************ | 
|---|
| 106 | PlanckSpectra::PlanckSpectra(double T) | 
|---|
| 107 | : T_(T) , spectraapprox_(PLANCK) , spectrafunc_(VALUE) , spectravar_(NU) | 
|---|
| 108 | , spectraunit_(ANGSFLUX) , spectrapower_(POWER) | 
|---|
| 109 | { | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | PlanckSpectra::PlanckSpectra(PlanckSpectra& s) | 
|---|
| 113 | : T_(s.T_) , spectraapprox_(s.spectraapprox_) , spectrafunc_(s.spectrafunc_) , spectravar_(s.spectravar_) | 
|---|
| 114 | , spectraunit_(s.spectraunit_), spectrapower_(s.spectrapower_) | 
|---|
| 115 | { | 
|---|
| 116 | } | 
|---|
| 117 |  | 
|---|
| 118 | PlanckSpectra::~PlanckSpectra(void) | 
|---|
| 119 | { | 
|---|
| 120 | } | 
|---|
| 121 |  | 
|---|
| 122 | //************************************************************************ | 
|---|
| 123 | void PlanckSpectra::SetSpectraApprox(SpectraApprox spectraapprox) | 
|---|
| 124 | // spectraapprox = PLANCK   : Planck spectra | 
|---|
| 125 | //               = RAYLEIGH : Rayleigh spectra | 
|---|
| 126 | //               = WIEN     : Wien spectra | 
|---|
| 127 | { | 
|---|
| 128 | spectraapprox_ = spectraapprox; | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | void PlanckSpectra::SetSpectraFunc(SpectraFunc spectrafunc) | 
|---|
| 132 | // spectrafunc = VALUE : spectra | 
|---|
| 133 | //             = DERIV : derivative of spectra relative to temperature | 
|---|
| 134 | { | 
|---|
| 135 | spectrafunc_ = spectrafunc; | 
|---|
| 136 | } | 
|---|
| 137 |  | 
|---|
| 138 | void PlanckSpectra::SetSpectraVar(SpectraVar spectravar) | 
|---|
| 139 | // spectravar = NU     : variable is frequency (Hz) | 
|---|
| 140 | //            = LAMBDA : variable is wavelength (m) | 
|---|
| 141 | { | 
|---|
| 142 | spectravar_ = spectravar; | 
|---|
| 143 | } | 
|---|
| 144 |  | 
|---|
| 145 | void PlanckSpectra::SetSpectraPower(SpectraPower spectrapower) | 
|---|
| 146 | // spectrapower = POWER : in W/... | 
|---|
| 147 | //              = PHOTON : in photon/s/... | 
|---|
| 148 | { | 
|---|
| 149 | spectrapower_ = spectrapower; | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | void PlanckSpectra::SetSpectraUnit(SpectraUnit spectraunit) | 
|---|
| 153 | // spectraunit = ANGSFLUX  : radiance   W/m^2/Sr/Hz  or ... | 
|---|
| 154 | //             = SFLUX     : emittance  W/m^2/Hz     or ... | 
|---|
| 155 | //             = DENSENERG : density    J/m^3/Hz     or ... | 
|---|
| 156 | //             = EXPON     : just the function exp() or equivalent for Rayleigh | 
|---|
| 157 | { | 
|---|
| 158 | spectraunit_ = spectraunit; | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 |  | 
|---|
| 162 | //************************************************************************ | 
|---|
| 163 | double PlanckSpectra::F2L(double nu_or_lambda) | 
|---|
| 164 | // Convert frequency (GHz) to/from Wavelength (m) | 
|---|
| 165 | // Lambda(m) * Nu(GHz) = C(km/s) * 10^-6 | 
|---|
| 166 | { | 
|---|
| 167 | return CinM_ / nu_or_lambda; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | //************************************************************************ | 
|---|
| 171 | double PlanckSpectra::PlanckExp(double fl) | 
|---|
| 172 | { | 
|---|
| 173 | double x = (spectravar_==LAMBDA) ? HCsK_/(fl*T_) : HsK_*fl/T_; | 
|---|
| 174 |  | 
|---|
| 175 | if(spectraapprox_ == RAYLEIGH) return 1./x;  // Rayleigh | 
|---|
| 176 |  | 
|---|
| 177 | if(x>MAXARGEXP) return 0.; | 
|---|
| 178 |  | 
|---|
| 179 | if(spectraapprox_ == WIEN) return exp(-x);  // Wien | 
|---|
| 180 |  | 
|---|
| 181 | if(x<MINARGEXP) return 1./(x*(1.+x/2.)); | 
|---|
| 182 | return 1./(exp(x)-1.); | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | double PlanckSpectra::DPlanckExp_DT(double fl) | 
|---|
| 186 | { | 
|---|
| 187 | if(spectraapprox_ == RAYLEIGH) | 
|---|
| 188 | return (spectravar_==LAMBDA) ? fl/HCsK_: 1. / (HsK_*fl);  // Rayleigh | 
|---|
| 189 |  | 
|---|
| 190 | double x = (spectravar_==LAMBDA) ? HCsK_/(fl*T_) : HsK_*fl/T_; | 
|---|
| 191 |  | 
|---|
| 192 | if(x>MAXARGEXP) return 0.; | 
|---|
| 193 |  | 
|---|
| 194 | if(spectraapprox_ == WIEN) return x/T_ * exp(-x);  // Wien | 
|---|
| 195 |  | 
|---|
| 196 | double v; | 
|---|
| 197 | if(x<MINARGEXP) { // 1/(exp(x)-1)  -derive-> -exp(x)/(exp(x)-1)^2 | 
|---|
| 198 | v = x*(1.+x/2.); | 
|---|
| 199 | return x/T_ * (1.+v)/(v*v); | 
|---|
| 200 | } | 
|---|
| 201 | v = exp(x); | 
|---|
| 202 | return x/T_ * v/((v-1.)*(v-1.)); | 
|---|
| 203 | } | 
|---|
| 204 |  | 
|---|
| 205 | //------------------------------------------------------------ | 
|---|
| 206 | double PlanckSpectra::operator() (double x) | 
|---|
| 207 | { | 
|---|
| 208 | // --- type de spectre et d'approximation selon choix variable | 
|---|
| 209 | double fex = (spectrafunc_==DERIV) ? DPlanckExp_DT(x): PlanckExp(x); | 
|---|
| 210 |  | 
|---|
| 211 | // --- le coefficient multiplicateur devant l'expo | 
|---|
| 212 | if(spectraunit_ == EXPON) return fex;  // expo seule | 
|---|
| 213 |  | 
|---|
| 214 | // radiance en ph/...               longeur d'onde         frequency | 
|---|
| 215 | double coeff = (spectravar_==LAMBDA) ? 2.*CinM_/(x*x*x*x): 2.*x*x/(CinM_*CinM_); | 
|---|
| 216 |  | 
|---|
| 217 | if(spectraunit_ == SFLUX)      coeff *= M_PI;  // emittance en ph/... | 
|---|
| 218 | else if(spectraunit_ == DENSENERG) coeff *= 4.*M_PI/CinM_;  // densite en ph/... | 
|---|
| 219 |  | 
|---|
| 220 | // unite en W/...                longeur d'onde         frequency | 
|---|
| 221 | if(spectrapower_ == POWER) | 
|---|
| 222 | coeff *= (spectravar_==LAMBDA) ? h_Planck_Cst*CinM_/x: h_Planck_Cst*x; | 
|---|
| 223 |  | 
|---|
| 224 | return coeff * fex; | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 | //------------------------------------------------------------ | 
|---|
| 228 | double PlanckSpectra::PlanckEnergie(void) | 
|---|
| 229 | //  densite d'energie: energie par m^3  en "J / m^3" | 
|---|
| 230 | // cste de Stefan-Boltzmann en W/m^2/K^4 | 
|---|
| 231 | { | 
|---|
| 232 | return 4.*StefBoltz_Cst*T_*T_*T_*T_/(SpeedOfLight_Cst*1000.); | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | //------------------------------------------------------------ | 
|---|
| 236 | double PlanckSpectra::PlanckPhoton(void) | 
|---|
| 237 | //  densite de photons: nombre de photons par m^3  en "ph / m^3" | 
|---|
| 238 | { | 
|---|
| 239 | double x = k_Boltzman_Cst*T_/(h_Planck_Cst*SpeedOfLight_Cst*1000.); | 
|---|
| 240 | return 16.*M_PI*Zeta_3_Cst* x*x*x; | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | double PlanckSpectra::WienLaw(void) | 
|---|
| 244 | // Retourne la frequence (ou longeur d'onde) du maximum | 
|---|
| 245 | // du spectre de radiance (ou emittance ou densite). | 
|---|
| 246 | // La valeur du maximum depend de l'unite du spectre (W/... ou Ph/s/...) | 
|---|
| 247 | /* | 
|---|
| 248 | --- Les fonctions: | 
|---|
| 249 | En frequence: n = 3  en W/...  ,  n = 2  en Ph/... | 
|---|
| 250 | En longueur d'onde: n = 5  en W/...  ,  n = 4  en Ph/... | 
|---|
| 251 | f[x_] := x^n*Exp[-x]; Solve[f'[x]==0,x]   // Wien | 
|---|
| 252 | f[x_] := x^n/(Exp[x]-1); NSolve[f'[x]==0,x,17]  // Planck | 
|---|
| 253 | La derivee par rapport a T des fonctions en frequence: | 
|---|
| 254 | df/dT[x_] := x^(n+1)*Exp[-x]; Solve[f'[x]==0,x]  // Wien | 
|---|
| 255 | df/dT[x_] := x^(n+1)*Exp[x]/(Exp[x]-1)^2; NSolve[f'[x]==0,x,17]  // Planck | 
|---|
| 256 | */ | 
|---|
| 257 | { | 
|---|
| 258 | double x=-1.; | 
|---|
| 259 | if(spectravar_ == NU) { // Frequence | 
|---|
| 260 | if(spectrafunc_ == VALUE) {  // Le spectre | 
|---|
| 261 | if(spectrapower_ == POWER) //  W/... | 
|---|
| 262 | {if(spectraapprox_==PLANCK) x=2.82143938074; else if(spectraapprox_==WIEN) x=3.;} | 
|---|
| 263 | else if(spectrapower_ == PHOTON) //  Ph/s/... | 
|---|
| 264 | {if(spectraapprox_==PLANCK) x=1.59362426; else if(spectraapprox_==WIEN) x=2.;} | 
|---|
| 265 | } else if(spectrafunc_ == DERIV) {  // La derivee du spectre | 
|---|
| 266 | if(spectrapower_ == POWER) //  W/... | 
|---|
| 267 | {if(spectraapprox_==PLANCK) x=3.830016095; else if(spectraapprox_==WIEN) x=4.;} | 
|---|
| 268 | else if(spectrapower_ == PHOTON) //  Ph/s/... | 
|---|
| 269 | {if(spectraapprox_==PLANCK) x=2.575678888; else if(spectraapprox_==WIEN) x=3.;} | 
|---|
| 270 | } | 
|---|
| 271 | } else { // Longeur d'onde | 
|---|
| 272 | if(spectrafunc_ == VALUE) {  // Le spectre | 
|---|
| 273 | if(spectrapower_ == POWER) //  W/... | 
|---|
| 274 | {if(spectraapprox_==PLANCK) x=4.96511420; else if(spectraapprox_==WIEN) x=5.;} | 
|---|
| 275 | else if(spectrapower_ == PHOTON) //  Ph/s/... | 
|---|
| 276 | {if(spectraapprox_==PLANCK) x=3.9206904099; else if(spectraapprox_==WIEN) x=4.;} | 
|---|
| 277 | } else if(spectrafunc_ == DERIV) {  // La derivee du spectre | 
|---|
| 278 | if(spectrapower_ == POWER) //  W/... | 
|---|
| 279 | {if(spectraapprox_==PLANCK) x=5.969409190; else if(spectraapprox_==WIEN) x=6.;} | 
|---|
| 280 | else if(spectrapower_ == PHOTON) //  Ph/s/... | 
|---|
| 281 | {if(spectraapprox_==PLANCK) x=4.928119345; else if(spectraapprox_==WIEN) x=5.;} | 
|---|
| 282 | } | 
|---|
| 283 | } | 
|---|
| 284 |  | 
|---|
| 285 | if(x<0.) return x;  // Rayleigh n'a pas de maximum | 
|---|
| 286 | if(spectravar_ == NU) return x / HsK_ *T_; // Frequence | 
|---|
| 287 | return HCsK_ / x /T_; // Longeur d'onde | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | double PlanckSpectra::FindMaximum(double eps) | 
|---|
| 291 | // Retourne le maximum des spectres (a la precicion eps) | 
|---|
| 292 | { | 
|---|
| 293 | if(spectraapprox_ == RAYLEIGH) {  // Pas de maximum pour les spectres de Raleigh | 
|---|
| 294 | cout<<"PlanckSpectra::FindMaximum : no maximum for Raleigh spectra"<<endl; | 
|---|
| 295 | throw ParmError("PlanckSpectra::FindMaximum : no maximum for Raleigh spectra"); | 
|---|
| 296 | } | 
|---|
| 297 | if(eps<=0.) eps = 0.001; | 
|---|
| 298 |  | 
|---|
| 299 | double xmax = WienLaw(), wmax=(*this)(xmax); | 
|---|
| 300 | double xlim[2]={xmax,xmax}; | 
|---|
| 301 |  | 
|---|
| 302 | // Encadrement du maximum par xlim[0] et xlim[1] | 
|---|
| 303 | while( (*this)(xlim[1])>=0.01*wmax ) xlim[1] *= 2.; | 
|---|
| 304 | while( (*this)(xlim[0])>=0.01*wmax ) xlim[0] /= 2.; | 
|---|
| 305 | //cout<<"FindMaximum: wmax="<<wmax<<" pour x=["<<xlim[0]<<","<<xlim[1]<<"]"<<endl; | 
|---|
| 306 |  | 
|---|
| 307 | while( (xlim[1]-xlim[0])/xmax > eps ) { | 
|---|
| 308 | wmax=-1.; | 
|---|
| 309 | double dx = (xlim[1]-xlim[0])/10.; | 
|---|
| 310 | for(double x=xlim[0]; x<=xlim[1]; x+=dx) { | 
|---|
| 311 | double f=(*this)(x); | 
|---|
| 312 | if(f>wmax) {wmax=f; xmax=x;} | 
|---|
| 313 | } | 
|---|
| 314 | //cout<<"...wmax="<<wmax<<" pour xmax="<<xmax<<" dx="<<dx<<endl; | 
|---|
| 315 | xlim[0] = xmax-dx*1.1; xlim[1] = xmax+dx*1.1; | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 |  | 
|---|
| 319 | //cout<<"wmax="<<wmax<<" pour x="<<xmax<<"  dx="<<xlim[1]-xlim[0]<<endl; | 
|---|
| 320 | return xmax; | 
|---|
| 321 | } | 
|---|
| 322 |  | 
|---|
| 323 | }  // Fin namespace SOPHYA | 
|---|