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

Last change on this file since 3313 was 3115, checked in by ansari, 19 years ago

Creation initiale du groupe Cosmo avec le repertoire SimLSS de
simulation de distribution de masse 3D des galaxies par CMV+Rz
18/12/2006

File size: 11.3 KB
Line 
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/*
80POUR TESTER LES LIMITES DE L'EXPONENTIELLE:
811-/ copier/coller les lignes suivantes dans toto.icc
82double x=10.;
83for(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}
892-/ 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
98double CinM_ = SpeedOfLight_Cst*1e+3;
99// h/k pour une frequence en Hz
100double HsK_ = h_Planck_Cst/k_Boltzman_Cst;
101// hc/k pour une longeur d'onde en metre
102double HCsK_ = h_Planck_Cst*CinM_/k_Boltzman_Cst;
103
104//************************************************************************
105PlanckSpectra::PlanckSpectra(double T)
106 : T_(T) , approx_(0) , deriv_(0) , typvar_(0) , typspec_(0) , unitout_(0)
107{
108}
109
110PlanckSpectra::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
116PlanckSpectra::~PlanckSpectra(void)
117{
118}
119
120//************************************************************************
121void 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
133void 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
144void 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
155void 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
166void 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//************************************************************************
181double 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//************************************************************************
189double 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
203double 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//------------------------------------------------------------
223double 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//------------------------------------------------------------
244double 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//------------------------------------------------------------
252double 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
259double 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:
265En frequence: n = 3 en W/... , n = 2 en Ph/...
266En longueur d'onde: n = 5 en W/... , n = 4 en Ph/...
267f[x_] := x^n*Exp[-x]; Solve[f'[x]==0,x] // Wien
268f[x_] := x^n/(Exp[x]-1); NSolve[f'[x]==0,x,17] // Planck
269La derivee par rapport a T des fonctions en frequence:
270df/dT[x_] := x^(n+1)*Exp[-x]; Solve[f'[x]==0,x] // Wien
271df/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
306double 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}
Note: See TracBrowser for help on using the repository browser.