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