source: Sophya/trunk/Cosmo/SimLSS/planckspectra.cc@ 3336

Last change on this file since 3336 was 3325, checked in by cmv, 18 years ago

Mise en conformite / SOPHYA lib:

  1. on enleve #include "sopnamsp.h" dans les .cc de la librairie
  2. on encadre par "namespace SOPHYA { ... }" tout le code des .cc de la librairie y compris les fonctions
  3. on met les fcts des .h dans le "namespace SOPHYA { ... }"
  4. on met #include "sopnamsp.h" dans tous les cmv*.cc cad les main programs

cmv le mauvais eleve (sur les conseils de Reza) 13/09/2007

File size: 11.3 KB
Line 
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
13namespace 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/*
81POUR TESTER LES LIMITES DE L'EXPONENTIELLE:
821-/ copier/coller les lignes suivantes dans toto.icc
83double x=10.;
84for(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}
902-/ 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
99double CinM_ = SpeedOfLight_Cst*1e+3;
100// h/k pour une frequence en Hz
101double HsK_ = h_Planck_Cst/k_Boltzman_Cst;
102// hc/k pour une longeur d'onde en metre
103double HCsK_ = h_Planck_Cst*CinM_/k_Boltzman_Cst;
104
105//************************************************************************
106PlanckSpectra::PlanckSpectra(double T)
107 : T_(T) , approx_(0) , deriv_(0) , typvar_(0) , typspec_(0) , unitout_(0)
108{
109}
110
111PlanckSpectra::PlanckSpectra(PlanckSpectra& s)
112 : T_(s.T_) , approx_(s.approx_) , deriv_(s.deriv_) , typvar_(s.typvar_) , typspec_(s.typspec_)
113 , unitout_(s.unitout_)
114{
115}
116
117PlanckSpectra::~PlanckSpectra(void)
118{
119}
120
121//************************************************************************
122void PlanckSpectra::SetApprox(unsigned short approx)
123// approx = 0 : Planck spectra
124// = 1 : Rayleigh spectra
125// = 2 : Wien spectra
126{
127 if(approx>2) {
128 cout<<"PlanckSpectra::SetApprox : unknown approximation"<<endl;
129 throw ParmError("PlanckSpectra::SetApprox : unknown approximation");
130 }
131 approx_ = approx;
132}
133
134void PlanckSpectra::SetDeriv(unsigned short deriv)
135// deriv = 0 : spectra
136// = 1 : derivative of spectra relative to temperature
137{
138 if(deriv>1) {
139 cout<<"PlanckSpectra::SetDeriv : parameter out of range"<<endl;
140 throw ParmError("PlanckSpectra::SetDeriv : parameter out of range");
141 }
142 deriv_ = deriv;
143}
144
145void PlanckSpectra::SetVar(unsigned short typvar)
146// typvar = 0 : variable is frequency (Hz)
147// = 1 : variable is wavelength (m)
148{
149 if(typvar>1) {
150 cout<<"PlanckSpectra::SetVar : parameter out of range"<<endl;
151 throw ParmError("PlanckSpectra::SetVar : parameter out of range");
152 }
153 typvar_ = typvar;
154}
155
156void PlanckSpectra::SetUnitOut(unsigned short unitout)
157// unitout = 0 : in W/...
158// = 1 : in photon/s/...
159{
160 if(unitout>1) {
161 cout<<"PlanckSpectra::SetUnitOut : parameter out of range"<<endl;
162 throw ParmError("PlanckSpectra::SetUnitOut : parameter out of range");
163 }
164 unitout_ = unitout;
165}
166
167void PlanckSpectra::SetTypSpectra(unsigned short typspec)
168// typspec = 0 : radiance W/m^2/Sr/Hz or ...
169// = 1 : emittance W/m^2/Hz or ...
170// = 2 : density J/m^3/Hz or ...
171// = 3 : just the function exp() or equivalent for Rayleigh
172{
173 if(typspec>3) {
174 cout<<"PlanckSpectra::SetTypSpectra : parameter out of range"<<endl;
175 throw ParmError("PlanckSpectra::SetTypSpectra : parameter out of range");
176 }
177 typspec_ = typspec;
178}
179
180
181//************************************************************************
182double PlanckSpectra::F2L(double nu_or_lambda)
183// Convert frequency (GHz) to/from Wavelength (m)
184// Lambda(m) * Nu(GHz) = C(km/s) * 10^-6
185{
186 return CinM_ / nu_or_lambda;
187}
188
189//************************************************************************
190double PlanckSpectra::PlanckExp(double fl)
191{
192 double x = (typvar_) ? HCsK_/(fl*T_) : HsK_*fl/T_;
193
194 if(approx_ == 1) return 1./x; // Rayleigh
195
196 if(x>MAXARGEXP) return 0.;
197
198 if(approx_ == 2) return exp(-x); // Wien
199
200 if(x<MINARGEXP) return 1./(x*(1.+x/2.));
201 return 1./(exp(x)-1.);
202}
203
204double PlanckSpectra::DPlanckExp_DT(double fl)
205{
206 if(approx_ == 1) return (typvar_) ? fl/HCsK_: 1. / (HsK_*fl); // Rayleigh
207
208 double x = (typvar_) ? HCsK_/(fl*T_) : HsK_*fl/T_;
209
210 if(x>MAXARGEXP) return 0.;
211
212 if(approx_ == 2) return x/T_ * exp(-x); // Wien
213
214 double v;
215 if(x<MINARGEXP) { // 1/(exp(x)-1) -derive-> -exp(x)/(exp(x)-1)^2
216 v = x*(1.+x/2.);
217 return x/T_ * (1.+v)/(v*v);
218 }
219 v = exp(x);
220 return x/T_ * v/((v-1.)*(v-1.));
221}
222
223//------------------------------------------------------------
224double PlanckSpectra::operator() (double x)
225{
226 // --- type de spectre et d'approximation selon choix variable
227 double fex = (deriv_) ? DPlanckExp_DT(x): PlanckExp(x);
228
229 // --- le coefficient multiplicateur devant l'expo
230 if(typspec_ == 3) return fex; // expo seule
231
232 // radiance en ph/... longeur d'onde frequency
233 double coeff = (typvar_) ? 2.*CinM_/(x*x*x*x): 2.*x*x/(CinM_*CinM_);
234
235 if(typspec_ == 1) coeff *= M_PI; // emittance en ph/...
236 else if(typspec_ == 2) coeff *= 4.*M_PI/CinM_; // densite en ph/...
237
238 // unite en W/... longeur d'onde frequency
239 if(unitout_ == 0) coeff *= (typvar_) ? h_Planck_Cst*CinM_/x: h_Planck_Cst*x;
240
241 return coeff * fex;
242}
243
244//------------------------------------------------------------
245double PlanckSpectra::PlanckEnergie(void)
246// densite d'energie: energie par m^3 en "J / m^3"
247// cste de Stefan-Boltzmann en W/m^2/K^4
248{
249 return 4.*StefBoltz_Cst*T_*T_*T_*T_/(SpeedOfLight_Cst*1000.);
250}
251
252//------------------------------------------------------------
253double PlanckSpectra::PlanckPhoton(void)
254// densite de photons: nombre de photons par m^3 en "ph / m^3"
255{
256 double x = k_Boltzman_Cst*T_/(h_Planck_Cst*SpeedOfLight_Cst*1000.);
257 return 16.*M_PI*Zeta_3_Cst* x*x*x;
258}
259
260double PlanckSpectra::WienLaw(void)
261// Retourne la frequence (ou longeur d'onde) du maximum
262// du spectre de radiance (ou emittance ou densite).
263// La valeur du maximum depend de l'unite du spectre (W/... ou Ph/s/...)
264/*
265--- Les fonctions:
266En frequence: n = 3 en W/... , n = 2 en Ph/...
267En longueur d'onde: n = 5 en W/... , n = 4 en Ph/...
268f[x_] := x^n*Exp[-x]; Solve[f'[x]==0,x] // Wien
269f[x_] := x^n/(Exp[x]-1); NSolve[f'[x]==0,x,17] // Planck
270La derivee par rapport a T des fonctions en frequence:
271df/dT[x_] := x^(n+1)*Exp[-x]; Solve[f'[x]==0,x] // Wien
272df/dT[x_] := x^(n+1)*Exp[x]/(Exp[x]-1)^2; NSolve[f'[x]==0,x,17] // Planck
273*/
274{
275 double x=-1.;
276 if(typvar_ == 0) { // Frequence
277 if(deriv_ == 0) { // Le spectre
278 if(unitout_ == 0) // W/...
279 {if(approx_==0) x=2.82143938074; else if(approx_==2) x=3.;}
280 else if(unitout_ == 1) // Ph/s/...
281 {if(approx_==0) x=1.59362426; else if(approx_==2) x=2.;}
282 } else if(deriv_ == 1) { // La derivee du spectre
283 if(unitout_ == 0) // W/...
284 {if(approx_==0) x=3.830016095; else if(approx_==2) x=4.;}
285 else if(unitout_ == 1) // Ph/s/...
286 {if(approx_==0) x=2.575678888; else if(approx_==2) x=3.;}
287 }
288 } else { // Longeur d'onde
289 if(deriv_ == 0) { // Le spectre
290 if(unitout_ == 0) // W/...
291 {if(approx_==0) x=4.96511420; else if(approx_==2) x=5.;}
292 else if(unitout_ == 1) // Ph/s/...
293 {if(approx_==0) x=3.9206904099; else if(approx_==2) x=4.;}
294 } else if(deriv_ == 1) { // La derivee du spectre
295 if(unitout_ == 0) // W/...
296 {if(approx_==0) x=5.969409190; else if(approx_==2) x=6.;}
297 else if(unitout_ == 1) // Ph/s/...
298 {if(approx_==0) x=4.928119345; else if(approx_==2) x=5.;}
299 }
300 }
301
302 if(x<0.) return x; // Rayleigh n'a pas de maximum
303 if(typvar_ == 0) return x / HsK_ *T_; // Frequence
304 return HCsK_ / x /T_; // Longeur d'onde
305}
306
307double PlanckSpectra::FindMaximum(double eps)
308// Retourne le maximum des spectres (a la precicion eps)
309{
310 if(approx_ == 1) { // Pas de maximum pour les spectres de Raleigh
311 cout<<"PlanckSpectra::FindMaximum : no maximum for Raleigh spectra"<<endl;
312 throw ParmError("PlanckSpectra::FindMaximum : no maximum for Raleigh spectra");
313 }
314 if(eps<=0.) eps = 0.001;
315
316 double xmax = WienLaw(), wmax=(*this)(xmax);
317 double xlim[2]={xmax,xmax};
318
319 // Encadrement du maximum par xlim[0] et xlim[1]
320 while( (*this)(xlim[1])>=0.01*wmax ) xlim[1] *= 2.;
321 while( (*this)(xlim[0])>=0.01*wmax ) xlim[0] /= 2.;
322 //cout<<"FindMaximum: wmax="<<wmax<<" pour x=["<<xlim[0]<<","<<xlim[1]<<"]"<<endl;
323
324 while( (xlim[1]-xlim[0])/xmax > eps ) {
325 wmax=-1.;
326 double dx = (xlim[1]-xlim[0])/10.;
327 for(double x=xlim[0]; x<=xlim[1]; x+=dx) {
328 double f=(*this)(x);
329 if(f>wmax) {wmax=f; xmax=x;}
330 }
331 //cout<<"...wmax="<<wmax<<" pour xmax="<<xmax<<" dx="<<dx<<endl;
332 xlim[0] = xmax-dx*1.1; xlim[1] = xmax+dx*1.1;
333 }
334
335
336 //cout<<"wmax="<<wmax<<" pour x="<<xmax<<" dx="<<xlim[1]-xlim[0]<<endl;
337 return xmax;
338}
339
340} // Fin namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.