source: Sophya/trunk/Cosmo/SimLSS/pkspectrum.cc@ 3805

Last change on this file since 3805 was 3805, checked in by cmv, 15 years ago

Refonte totale de la structure des classes InitialSpectrum, TransfertFunction, GrowthFactor, PkSpectrum et classes tabulate pour lecture des fichiers CAMB, cmv 24/07/2010

File size: 25.4 KB
RevLine 
[3115]1#include "machdefs.h"
2#include <iostream>
3#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6#include <math.h>
7#include <unistd.h>
8
9#include "pexceptions.h"
10
11#include "constcosmo.h"
[3196]12#include "geneutils.h"
[3115]13#include "pkspectrum.h"
14
[3325]15namespace SOPHYA {
[3115]16
17///////////////////////////////////////////////////////////
[3805]18//******************** InitialPowerLaw ******************//
[3115]19///////////////////////////////////////////////////////////
20
[3805]21InitialPowerLaw::InitialPowerLaw(double n,double a)
[3115]22 : n_(n), A_(a)
23{
24}
25
[3805]26InitialPowerLaw::InitialPowerLaw(InitialPowerLaw& pkinf)
[3115]27 : n_(pkinf.n_), A_(pkinf.A_)
28{
29}
30
[3805]31InitialPowerLaw::~InitialPowerLaw(void)
[3115]32{
33}
34
35
36///////////////////////////////////////////////////////////
37//****************** TransfertEisenstein ****************//
38///////////////////////////////////////////////////////////
39
[3314]40// From Eisenstein & Hu ApJ 496:605-614 1998 April 1 (ou astro-ph/9709112)
41TransfertEisenstein::TransfertEisenstein(double h100,double OmegaCDM0,double OmegaBaryon0,double tcmb,bool nobaryon,int lp)
42 : lp_(lp)
[3378]43 , Oc_(OmegaCDM0) , Ob_(OmegaBaryon0) , h100_(h100) , tcmb_(tcmb)
[3348]44 , nobaryon_(nobaryon) , nooscenv_(0), retpart_(ALL)
[3115]45{
[3314]46 zero_();
47 Init_();
[3115]48}
49
50TransfertEisenstein::TransfertEisenstein(TransfertEisenstein& tf)
[3314]51 : lp_(tf.lp_)
[3378]52 ,Oc_(tf.Oc_) , Ob_(tf.Ob_) , h100_(tf.h100_) , tcmb_(tf.tcmb_)
[3314]53 , nobaryon_(tf.nobaryon_) , nooscenv_(tf.nooscenv_), retpart_(tf.retpart_)
[3115]54{
[3314]55 zero_();
56 Init_();
[3115]57}
58
[3378]59TransfertEisenstein::~TransfertEisenstein(void)
60{
61}
62
[3318]63void TransfertEisenstein::zero_(void)
64{
65 th2p7_=zeq_=keq_=zd_=Req_=Rd_=s_=ksilk_=alphac_=betac_=bnode_
66 =alphab_=betab_=alphag_=sfit_=kpeak_=1.e99;
67}
68
[3314]69void TransfertEisenstein::Init_(void)
[3115]70{
71
72 O0_ = Oc_ + Ob_;
[3314]73 if(nobaryon_) {O0_ = Oc_; Ob_ = 0.;}
[3378]74 double H0 = 100. * h100_, h2 = h100_*h100_;
75 if(lp_) cout<<"h100="<<h100_<<" H0="<<H0<<") Omatter="<<O0_<<" Ocdm="<<Oc_<<" Ob="<<Ob_<<endl;
[3115]76
[3329]77
[3314]78 if(tcmb_<0.) tcmb_ = T_CMB_Par;
[3115]79 th2p7_ = tcmb_/2.7;
80 double th2p7P4 = th2p7_*th2p7_*th2p7_*th2p7_;
[3314]81 if(lp_) cout<<"tcmb = "<<tcmb_<<" K = "<<th2p7_<<" *2.7K "<<endl;
[3115]82
83 // Formule 2 p 606
84 zeq_ = 2.50e4 * O0_ * h2 / th2p7P4;
[3314]85 if(lp_) cout<<"zeq = "<<zeq_<<" (redshift of matter-radiation equality)"<<endl;
[3115]86
87 // Formule 3 p 607
88 // (attention ici C=1 : H0 -> H0/C si on utilise la premiere formule)
89 // keq_ = sqrt(2.*O0_*H0*H0*zeq_) / SpeedOfLight_Cst;
90 keq_ = 7.46e-2 * O0_ * h2 / (th2p7_*th2p7_);
[3314]91 if(lp_) cout<<"keq = "<<keq_<<" Mpc^-1 (scale of equality)"<<endl;
[3115]92
[3314]93 // On s'arrete ici si pas de baryons
94 if(nobaryon_) return;
95
[3115]96 // Formule 4 p 607
97 double b1_eq4 = 0.313*pow(O0_*h2,-0.419)*(1. + 0.607*pow(O0_*h2,0.674));
98 double b2_eq4 = 0.238*pow(O0_*h2,0.223);
[3314]99 zd_ = 1291. * pow(O0_*h2,0.251) / (1.+0.659* pow(O0_*h2,0.828))
100 * (1. + b1_eq4*pow(Ob_*h2,b2_eq4));
101 if(lp_) cout<<"zd = "<<zd_<<" (Redshift of drag epoch)"<<endl;
[3115]102
[3314]103 // Formule 5 page 607 (R = 3*rho_baryon/4*rho_gamma)
[3115]104 Req_ = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zeq_);
[3314]105 //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: zd -> (1+zd)
[3115]106 Rd_ = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zd_);
[3314]107 //in tf_fit.c: Rd_ = 31.5*Ob_*h2 / th2p7P4 * (1.e3/(1.+zd_));
108 if(lp_) {
109 cout<<"Req = "<<Req_<<" Rd = "<<Rd_
110 <<" (Photon-baryon ratio at equality/drag epoch)"<<endl;
111 cout<<"Sound speed at equality "<<1./sqrt(3.*(1.+Req_))
112 <<", at drag "<<1./sqrt(3.*(1.+Rd_))<<" in unit of C"<<endl;
113 }
[3115]114
115 // Formule 6 p 607
116 s_ = 2./(3.*keq_) * sqrt(6./Req_)
117 * log( (sqrt(1.+Rd_) + sqrt(Rd_+Req_)) / (1.+sqrt(Req_)) );
[3314]118 if(lp_) cout<<"s = "<<s_<<" Mpc (sound horizon at drag epoch)"<<endl;
[3115]119
120 // Formule 7 page 607
121 ksilk_ = 1.6*pow(Ob_*h2,0.52)*pow(O0_*h2,0.73) * (1. + pow(10.4*O0_*h2,-0.95));
[3314]122 if(lp_) cout<<"ksilk = "<<ksilk_<<" Mpc^-1 (silk damping scale)"<<endl;
[3115]123
124 // Formules 10 page 608
125 double a1 = pow(46.9*O0_*h2,0.670) * (1. + pow(32.1*O0_*h2,-0.532));
126 double a2 = pow(12.0*O0_*h2,0.424) * (1. + pow(45.0*O0_*h2,-0.582));
127 alphac_ = pow(a1,-Ob_/O0_) * pow(a2,-pow(Ob_/O0_,3.));
128 double b1 = 0.944 / (1. + pow(458.*O0_*h2,-0.708));
129 double b2 = pow(0.395*O0_*h2,-0.0266);
130 betac_ = 1 / ( 1. + b1*(pow(Oc_/O0_,b2) - 1.) );
[3314]131 if(lp_) cout<<"alphac = "<<alphac_<<" betac = "<<betac_
132 <<" (CDM suppression/log shift)"<<endl;
[3115]133
134 // Formule 23 page 610
135 bnode_ = 8.41 * pow(O0_*h2,0.435);
[3314]136 if(lp_) cout<<"bnode = "<<bnode_<<" (sound horizon shift)"<<endl;
[3115]137
138 // Formule 14 page 608
[3314]139 //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: (1+zeq) -> zeq
[3115]140 double y = (1.+zeq_)/(1.+zd_);
[3314]141 //in tf_fit.c: double y = zeq_/(1.+zd_);
[3115]142 double s1py = sqrt(1.+y);
143 double Gy = y*( -6.*s1py + (2.+3.*y)*log((s1py+1.)/(s1py-1.)) );
144 alphab_ = 2.07*keq_*s_*pow(1.+Rd_,-3./4.)*Gy;
145
146 // Formule 24 page 610
147 betab_ = 0.5 + Ob_/O0_
148 + (3.-2.*Ob_/O0_) * sqrt(pow(17.2*O0_*h2,2.) + 1.);
[3314]149 if(lp_) cout<<"alphab = "<<alphab_<<" betab = "<<betab_
150 <<" (Baryon suppression/envelope shift)"<<endl;
[3115]151
152 // Formule 31 page 612
153 alphag_ = 1.
154 - 0.328*log(431.*O0_*h2)*Ob_/O0_
155 + 0.38*log(22.3*O0_*h2)*pow(Ob_/O0_,2.);
[3314]156 if(lp_) cout<<"alphag = "<<alphag_<<" (gamma suppression in approximate TF)"<<endl;
[3115]157
[3314]158 // The approximate value of the sound horizon, formule 26 page 611
159 sfit_ = 44.5*log(9.83/(O0_*h2)) / sqrt(1.+10.*pow(Ob_*h2,3./4.)); // Mpc
160 if(lp_) cout<<"sfit="<<sfit_<<" Mpc (fit to sound horizon)"<<endl;
[3115]161
[3314]162 // La positoin du premier pic acoustique, formule 25 page 611
163 kpeak_ = 5*M_PI/(2.*sfit_) * (1.+0.217*O0_*h2); // 1/Mpc
164 if(lp_) cout<<"kpeak="<<kpeak_<<" Mpc^-1 (fit to wavenumber of first peak)"<<endl;
165
[3115]166 return;
167}
168
[3381]169bool TransfertEisenstein::SetParTo(double h100,double OmegaCDM0,double OmegaBaryon0)
[3378]170// Changement des valeurs des parametres (suivi de re-init eventuel)
[3381]171// Si h100,Omega...<=0. alors pas de changement, on garde l'ancienne valeur
[3115]172{
[3378]173 bool haschanged = false;
174
175 if(h100>0.) {h100_ = h100; haschanged = true;}
176 if(OmegaCDM0>0.) {Oc_ = OmegaCDM0; haschanged = true;}
177 if(OmegaBaryon0>0.) {Ob_ = OmegaBaryon0; haschanged = true;}
178
179 // et on recalcule les initialisations
180 if(haschanged) Init_();
181
182 return haschanged;
[3115]183}
184
185void TransfertEisenstein::SetNoOscEnv(unsigned short nooscenv)
[3314]186// To obtain an approximate form of the non-oscillatory part of the transfert function
187// nooscenv = 0 : use the baryon oscillatory part of transfert function (full tf)
[3115]188// nooscenv = 1 : use approx. paragraph 3.3 p610 (middle of right column)
[3314]189// Replace j0(k*stilde) -> [1+(k*stilde)^4]^(-1/4)
[3115]190// nooscenv = 2 : use formulae 29+30+31 page 612
[3314]191// The value of an approximate transfer function that captures
192// the non-oscillatory part of a partial baryon transfer function.
193// In other words, the baryon oscillations are left out,
194// but the suppression of power below the sound horizon is included.
[3115]195{
[3314]196 if(nooscenv!=1 && nooscenv!=2) nooscenv = 0;
197 nooscenv_ = nooscenv;
[3115]198}
199
[3348]200void TransfertEisenstein::SetReturnPart(ReturnPart retpart)
[3314]201// To return only baryon or CDM part part of transfert function
[3348]202// retpart = ALL: return full transfert function
203// = CDM : return only CDM part of transfert function
204// = BARYON : return only Baryon part of transfert function
[3314]205// WARNING: only relevant for nobaryon_=false AND nooscenv!=2
206{
207 retpart_ = retpart;
208}
209
[3378]210void TransfertEisenstein::SetPrintLevel(int lp)
211{
212 lp_ = lp;
213}
214
215
[3115]216double TransfertEisenstein::T0tild(double k,double alphac,double betac)
217{
218 // Formule 10 p 608
[3378]219 //double q = k*th2p7_*th2p7_/(O0_*h100_*h100_);
[3115]220 double q = k/(13.41*keq_);
221 // Formule 20 p 610
222 double C = (14.2/alphac) + 386./(1.+69.9*pow(q,1.08));
223 // Formule 19 p 610
224 double x = log(M_E+1.8*betac*q);
225 return x / (x + C*q*q);
226}
227
228double TransfertEisenstein::operator() (double k)
229{
230
231 // --- Pour zero baryon
232 // OU Pour function lissee sans oscillation baryon
233 if(nobaryon_ || nooscenv_ == 2) {
[3378]234 double gamma = O0_*h100_;
[3314]235 // Calcul de Gamma_eff, formule 30 page 612 (pour fct lissee)
[3115]236 if( nobaryon_==false && nooscenv_ == 2 )
[3378]237 gamma = O0_*h100_*(alphag_ + (1.-alphag_)/(1.+pow(0.43*k*sfit_,4.))); // Gamma_eff
[3314]238 // Formule 28 page 612 : qui est est equivalent a:
[3378]239 // q = k / h100_ * th2p7_*th2p7_ / gamma;
[3314]240 // qui est est equivalent a:
241 // q = k / (13.41 * keq) pour Ob=0
242 // q = k / (13.41 * keq) * (O0*h/Gamma) pour le spectre lisse
243 // Les resultats sont legerement differents a cause des valeurs approx.
244 // des constantes numeriques: on prend comme W.Hu (tf_fit.c)
[3378]245 //double q = k / h100_ * th2p7_*th2p7_ / gamma; // Mpc^-1
246 double q = k/(13.41*keq_) * (O0_*h100_/gamma); // Mpc^-1
[3115]247 // Formules 29 page 612
248 double l0 = log(2.*M_E + 1.8*q);
249 double c0 = 14.2 + 731./(1.+62.5*q);
250 return l0 / (l0 + c0*q*q);
251 }
252
[3314]253 // --- Pour CDM + Baryons
[3115]254 // --- CDM
255 double f = 1. / (1. + pow(k*s_/5.4,4.));
256 double Tc = f*T0tild(k,1.,betac_) + (1.-f)*T0tild(k,alphac_,betac_);
[3348]257 if(retpart_ == CDM) return Tc;
[3115]258
259 // --- Baryons
260 // Formule 22 page 610
[3314]261 double stilde, ksbnode = k*s_/bnode_;
262 if(ksbnode<0.001) stilde =s_ * ksbnode;
263 else stilde = s_ / pow(1. + pow(1./ksbnode,3.), 1./3.);
[3115]264 // Formule 21 page 610
265 double j0kst = 0.;
[3314]266 if(nooscenv_ == 1) {
267 j0kst = pow(1.+pow(k*stilde,4.) , -1./4.); //lissee sans oscillation baryon
268 } else {
269 double x = k*stilde;
[3115]270 if(x<0.01) j0kst = 1. - x*x/6.*(1.-x*x/20.);
271 else j0kst = sin(x)/x;
[3314]272 //cout<<"DEBUG: k="<<k<<" stilde="<<stilde<<" x="<<x<<" j0kst="<<j0kst<<endl;
[3115]273 }
274 double Tb = T0tild(k,1.,1.) / (1. + pow(k*s_/5.2,2.));
[3314]275 Tb += alphab_/(1.+pow(betab_/(k*s_),3.)) * exp(-pow(k/ksilk_,1.4));
[3115]276 Tb *= j0kst;
[3348]277 if(retpart_ == BARYON) return Tb;
[3115]278
279 // --- Total
280 double T = (Ob_/O0_)*Tb + (Oc_/O0_)*Tc;
281
282 return T;
283}
284
285double TransfertEisenstein::KPeak(void)
286// Position du premier pic acoustic
287{
288 if(nobaryon_) return -1.;
289 return kpeak_;
290}
291
292
293///////////////////////////////////////////////////////////
[3318]294//******************* TransfertTabulate *****************//
295///////////////////////////////////////////////////////////
296
[3802]297TransfertTabulate::TransfertTabulate(void)
298: kmin_(1.) , kmax_(-1.) , interptyp_(0)
[3318]299{
[3805]300 k_.resize(0);
301 tf_.resize(0);
[3318]302}
303
304TransfertTabulate::TransfertTabulate(TransfertTabulate& tf)
[3802]305: kmin_(tf.kmin_) , kmax_(tf.kmax_) , interptyp_(tf.interptyp_) , k_(tf.k_) , tf_(tf.tf_)
[3318]306{
307}
308
309TransfertTabulate::~TransfertTabulate(void)
310{
311}
312
313void TransfertTabulate::SetInterpTyp(int typ)
314// see comment in InterpTab
315{
316 if(typ<0) typ=0; else if(typ>2) typ=2;
317 interptyp_ = typ;
318}
319
320double TransfertTabulate::operator() (double k)
321{
322 return InterpTab(k,k_,tf_,interptyp_);
323}
324
[3802]325int TransfertTabulate::ReadCMBFast(string filename,double h100,double OmegaCDM0,double OmegaBaryon0)
[3318]326{
327 FILE *file = fopen(filename.c_str(),"r");
328 if(file==NULL) return -1;
[3802]329 cout<<"TransfertTabulate::ReadCMBFast: fn="<<filename<<" h100="<<h100
330 <<" OmegaCDM0="<<OmegaCDM0<<" OmegaBaryon0="<<OmegaBaryon0<<endl;
[3318]331
332 const int lenline = 512;
333 char *line = new char[lenline];
334
[3805]335 k_.resize(0); tf_.resize(0);
[3318]336 double tmax = -1.;
337 while ( fgets(line,lenline,file) != NULL ) {
338 double k,tc,tb,tf;
339 sscanf(line,"%lf %lf %lf",&k,&tc,&tb);
[3802]340 k *= h100; // convert h Mpc^-1 -> Mpc^-1
341 tf = (OmegaCDM0*tc+OmegaBaryon0*tb)/(OmegaCDM0+OmegaBaryon0);
[3318]342 if(tf>tmax) tmax = tf;
343 k_.push_back(k);
344 tf_.push_back(tf);
345 }
346
[3805]347 cout<<"TransfertTabulate::ReadCMBFast: nread="<<tf_.size()<<" tf_max="<<tmax<<endl;
[3318]348 delete [] line;
[3805]349 if(tf_.size()==0) return (int)tf_.size();
[3318]350
351 for(unsigned int i=0;i<tf_.size();i++) tf_[i] /= tmax;
352
[3805]353 return (int)tf_.size();
[3318]354}
355
[3805]356int TransfertTabulate::ReadCAMB(string filename, double h100)
357{
358 FILE *file = fopen(filename.c_str(),"r");
359 if(file==NULL) return -1;
360 cout<<"TransfertTabulate::ReadCAMB: fn="<<filename<<" h100="<<h100<<endl;
361
362 const int lenline = 512;
363 char *line = new char[lenline];
364
365 k_.resize(0); tf_.resize(0);
366 double tmax = -1.;
367 while ( fgets(line,lenline,file) != NULL ) {
368 double k,tcdm,tbar,tph,trel,tnu,ttot, tf;
369 sscanf(line,"%lf %lf %lf %lf %lf %lf %lf",&k,&tcdm,&tbar,&tph,&trel,&tnu,&ttot);
370 k *= h100; // convert h Mpc^-1 -> Mpc^-1
371 tf = ttot;
372 if(tf>tmax) tmax = tf;
373 k_.push_back(k);
374 tf_.push_back(tf);
375 }
376
377 cout<<"TransfertTabulate::ReadCAMB nread="<<tf_.size()<<" tf_max="<<tmax<<endl;
378 delete [] line;
379 if(tf_.size()==0) return (int)tf_.size();
380
381 for(unsigned int i=0;i<tf_.size();i++) tf_[i] /= tmax;
382
383 return (int)tf_.size();
384}
385
386
[3318]387///////////////////////////////////////////////////////////
[3115]388//********************* GrowthFactor ********************//
389///////////////////////////////////////////////////////////
[3805]390double GrowthFactor::DsDz(double z, double)
391{
392 cout<<"Error: GrowthFactor::DsDz not implemented"<<endl;
393 throw AllocationError("Error: GrowthFactor::DsDz not implemented");
394}
[3115]395
[3805]396///////////////////////////////////////////////////////////
397//********************* GrowthEisenstein ********************//
398///////////////////////////////////////////////////////////
399
[3115]400// From Eisenstein & Hu ApJ 496:605-614 1998 April 1
[3193]401// Pour avoir D(z) = 1/(1+z) faire: OmegaMatter0=1 OmegaLambda0=0
[3805]402GrowthEisenstein::GrowthEisenstein(double OmegaMatter0,double OmegaLambda0)
[3381]403 : O0_(OmegaMatter0) , Ol_(OmegaLambda0)
[3115]404{
405 if(OmegaMatter0==0.) {
[3805]406 cout<<"GrowthEisenstein::GrowthEisenstein: Error bad OmegaMatter0 value : "<<OmegaMatter0<<endl;
407 throw ParmError("GrowthEisenstein::GrowthEisenstein: Error badOmegaMatter0 value");
[3115]408 }
409}
410
[3805]411GrowthEisenstein::GrowthEisenstein(GrowthEisenstein& d1)
[3381]412 : O0_(d1.O0_) , Ol_(d1.Ol_)
[3115]413{
414}
415
[3805]416GrowthEisenstein::~GrowthEisenstein(void)
[3115]417{
418}
419
[3805]420double GrowthEisenstein::operator() (double z)
[3115]421// see Formulae A4 + A5 + A6 page 614
422{
423 z += 1.;
424 double z2 = z*z, z3 = z2*z;
[3381]425
426 // Calcul de la normalisation (pour z=0 -> growth=1.)
427 double D1z0 = pow(O0_,4./7.) - Ol_ + (1.+O0_/2.)*(1.+Ol_/70.);
428 D1z0 = 2.5*O0_ / D1z0;
429
430 // Calcul du growthfactor pour z
431 double Ok = 1. - O0_ - Ol_;
432 double den = Ol_ + Ok*z2 + O0_*z3;
[3115]433 double o0z = O0_ *z3 / den;
434 double olz = Ol_ / den;
435
[3381]436 double D1z = pow(o0z,4./7.) - olz + (1.+o0z/2.)*(1.+olz/70.);
[3115]437 D1z = 2.5*o0z / z / D1z;
438
[3381]439 return D1z / D1z0;
[3115]440}
441
[3805]442double GrowthEisenstein::DsDz(double z,double dzinc)
[3768]443// y-y0 = a*(x-x0)^2 + b*(x-x0)
444// dy = a*dx^2 + b*dx avec dx = x-x0
445// dy'(dx) = 2*a*dx + b -> pour x=x0 on a dy'(0) = b
446{
447 if(z<0. || dzinc<=0.) {
[3805]448 cout<<"GrowthEisenstein::DsDz: z<0 or dzinc<=0. !"<<endl;
449 throw ParmError("GrowthEisenstein::DsDz: z<0 or dzinc<=0. !");
[3768]450 }
451
452 double z1, z2;
453 if(z>dzinc/2.) {
454 // cas ou z est suffisamment loin de zero
455 // resolution avec 2 points encadrant x0=z
456 z1 = z - dzinc; if(z1<0.) z1 = 0.;
457 z2 = z + dzinc;
458 } else {
459 // cas ou z est proche de zero
460 // resolution avec 2 points au dessus, x0=z1
461 z1 = z + dzinc;
462 z2 = z + 2.*dzinc;
463 }
464
465 double gz = (*this)(z);
466 double dgz1 = (*this)(z1) - gz;
467 double dgz2 = (*this)(z2) - gz;
468
469 z1 -= z;
470 z2 -= z;
471 return (dgz2*z1*z1 - dgz1*z2*z2)/(z1*z2*(z1-z2));
472}
473
[3805]474void GrowthEisenstein::SetParTo(double OmegaMatter0,double OmegaLambda0)
[3378]475{
[3381]476 if(OmegaMatter0>0.) O0_ = OmegaMatter0;
477 Ol_ = OmegaLambda0;
478}
[3115]479
[3805]480bool GrowthEisenstein::SetParTo(double OmegaMatter0)
[3381]481// idem precedent sans changer OmegaLambda0
482{
483 if(OmegaMatter0<=0.) return false;
484 O0_ = OmegaMatter0;
485 return true;
[3378]486}
487
488
[3115]489///////////////////////////////////////////////////////////
[3805]490//********************** PkSpectrum *********************//
[3115]491///////////////////////////////////////////////////////////
492
[3805]493PkSpectrum::PkSpectrum(void)
494 : zref_(0.) , scale_(1.) , typspec_(PK)
[3115]495{
496}
497
[3805]498PkSpectrum::PkSpectrum(PkSpectrum& pk)
499 : zref_(pk.zref_) , scale_(pk.scale_) , typspec_(pk.typspec_)
[3115]500{
501}
502
[3805]503
504///////////////////////////////////////////////////////////
505//********************** PkSpecCalc *********************//
506///////////////////////////////////////////////////////////
507
508PkSpecCalc::PkSpecCalc(InitialSpectrum& pkinf,TransfertFunction& tf,GrowthFactor& d1,double zref)
509 : pkinf_(pkinf) , tf_(tf) , d1_(d1)
[3115]510{
[3805]511 zref_ = zref;
[3115]512}
513
[3805]514PkSpecCalc::PkSpecCalc(PkSpecCalc& pkz)
515 : pkinf_(pkz.pkinf_) , tf_(pkz.tf_) , d1_(pkz.d1_)
[3115]516{
[3805]517}
518
519PkSpecCalc::~PkSpecCalc(void)
520{
521}
522
523double PkSpecCalc::operator() (double k)
524{
525 return (*this)(k,zref_);
526}
527
528double PkSpecCalc::operator() (double k,double z)
529{
[3115]530 double tf = tf_(k);
531 double pkinf = pkinf_(k);
[3805]532 double d1 = d1_(z);
533
534 double v = pkinf * (tf*tf) * (d1*d1);
535 if(typspec_ == DELTA) v *= k*k*k/(2.*M_PI*M_PI);
536
537 return scale_ * v;
[3115]538}
539
[3805]540///////////////////////////////////////////////////////////
541//********************** PkTabulate *********************//
542///////////////////////////////////////////////////////////
543
544PkTabulate::PkTabulate(void)
545: kmin_(1.) , kmax_(-1.) , interptyp_(0)
[3115]546{
[3805]547 k_.resize(0);
548 pk_.resize(0);
[3115]549}
550
[3805]551PkTabulate::PkTabulate(PkTabulate& pkz)
552 : kmin_(pkz.kmin_) , kmax_(pkz.kmax_) , interptyp_(pkz.interptyp_) , k_(pkz.k_) , pk_(pkz.pk_)
[3115]553{
554}
555
[3805]556
557PkTabulate::~PkTabulate(void)
[3115]558{
559}
560
[3805]561void PkTabulate ::SetInterpTyp(int typ)
562// see comment in InterpTab
[3115]563{
[3805]564 if(typ<0) typ=0; else if(typ>2) typ=2;
565 interptyp_ = typ;
[3115]566}
567
[3805]568double PkTabulate::operator() (double k)
[3115]569{
[3805]570 double v = InterpTab(k,k_,pk_,interptyp_);
571 if(typspec_ == DELTA) v *= k*k*k/(2.*M_PI*M_PI);
572 return scale_ * v;
573}
574
575double PkTabulate::operator() (double k,double z)
576{
577 cout<<"Error: PkTabulate::operator(double k,double z) not implemented"<<endl;
578 throw AllocationError("Error: PkTabulate::operator(double k,double z) not implemented");
579}
580
581int PkTabulate::ReadCAMB(string filename, double h100, double zreftab)
582{
583 FILE *file = fopen(filename.c_str(),"r");
584 if(file==NULL) return -1;
585 cout<<"PkTabulate::ReadCAMB: fn="<<filename<<" h100="<<h100<<" zreftab = "<<zreftab<<endl;
586
587 const int lenline = 512;
588 char *line = new char[lenline];
589
590 k_.resize(0); pk_.resize(0);
591 while ( fgets(line,lenline,file) != NULL ) {
592 double k, pk;
593 sscanf(line,"%lf %lf",&k,&pk);
594 k *= h100; // convert h Mpc^-1 -> Mpc^-1
595 pk /= h100*h100*h100; // convert h^-3 Mpc^3 -> Mpc^3
596 k_.push_back(k);
597 pk_.push_back(pk);
598 }
599
600 SetZ(zreftab);
601 cout<<"PkTabulate::ReadCAMB nread="<<pk_.size()<<"zref="<<GetZ()<<endl;
602 delete [] line;
603
604 return (int)pk_.size();
605}
606
607///////////////////////////////////////////////////////////
608//********************* PkEisenstein ********************//
609///////////////////////////////////////////////////////////
610
611PkEisenstein::PkEisenstein(InitialPowerLaw& pkinf,TransfertEisenstein& tf,GrowthEisenstein& d1,double zref)
612 : pkinf_(pkinf) , tf_(tf) , d1_(d1)
613{
614 zref_ = zref;
615}
616
617PkEisenstein::PkEisenstein(PkEisenstein& pkz)
618 : pkinf_(pkz.pkinf_) , tf_(pkz.tf_) , d1_(pkz.d1_)
619{
620}
621
622PkEisenstein::~PkEisenstein(void)
623{
624}
625
626double PkEisenstein::operator() (double k)
627{
[3115]628 return (*this)(k,zref_);
629}
630
[3805]631double PkEisenstein::operator() (double k,double z)
[3115]632{
[3805]633 double tf = tf_(k);
634 double pkinf = pkinf_(k);
[3381]635 double d1 = d1_(z);
[3115]636
[3805]637 double v = pkinf * (tf*tf) * (d1*d1);
638 if(typspec_ == DELTA) v *= k*k*k/(2.*M_PI*M_PI);
[3115]639
640 return scale_ * v;
641}
642
643
644///////////////////////////////////////////////////////////
645//******************* VarianceSpectrum ******************//
646///////////////////////////////////////////////////////////
647
[3348]648VarianceSpectrum::VarianceSpectrum(GenericFunc& pk,double R,TypeFilter typfilter)
649 : pk_(pk)
[3115]650{
[3348]651 SetRadius(R);
[3115]652 SetFilter(typfilter);
653}
654
655VarianceSpectrum::VarianceSpectrum(VarianceSpectrum& vpk)
656 : pk_(vpk.pk_) , R_(vpk.R_)
657{
658 SetFilter(vpk.typfilter_);
659}
660
661VarianceSpectrum::~VarianceSpectrum(void)
662{
663}
664
[3348]665void VarianceSpectrum::SetRadius(double R)
666// R = taille du filter top-hat ou gaussien
667{
668 if(R<=0.) {
669 cout<<"VarianceSpectrum::SetRadius: Error R<=0"<<endl;
670 throw ParmError("VarianceSpectrum::SetRadius: Error R<=0");
671 }
672 R_ = R;
673}
674
[3115]675//------------------------------------
[3348]676void VarianceSpectrum::SetFilter(TypeFilter typfilter)
677// typfilter = TOPHAT : spherical 3D top-hat
678// = GAUSSIAN : spherical 3D gaussian
679// = NOFILTER : no filter juste integrate spectrum)
680// Remarque:
681// la meilleure approximation du filtre top-hat (R) est un filtre gaussien avec (Rg=R/sqrt(5))
[3115]682{
683 typfilter_ = typfilter;
684}
685
686void VarianceSpectrum::SetInteg(double dperc,double dlogkinc,double dlogkmax,unsigned short glorder)
687// ATTENTION: on n'integre pas f(k)*dk mais k*f(k)*d(log10(k))
[3196]688// see argument details in function IntegrateFuncLog (geneutils.cc)
[3115]689{
690 dperc_ = dperc; if(dperc_<=0.) dperc_ = 0.1;
691 dlogkinc_ = dlogkinc;
692 dlogkmax_ = dlogkmax;
693 glorder_ = glorder;
694}
695
696
697//------------------------------------
698double VarianceSpectrum::Filter2(double x)
699// ATTENTION: c'est le filtre au carre qui est renvoye
700{
701 // Just integrate the spectrum without filtering
[3348]702 if(typfilter_ == NOFILTER) return 1.;
[3115]703
704 double x2 = x*x;
705 // Filtre gaussien G(x) = exp(-x^2/2)
706 // remarque G(x)^2 = exp(-x^2)
707 // on prend le DL de G(x)^2 pour x->0 a l'ordre O(x^6)
708 // DL(x) = 1-x^2*(1-x^2/2)
709 // pour x<0.01 |DL(x)-G(X)^2|<2.0e-13
[3348]710 if(typfilter_ == GAUSSIAN)
[3662]711 {if(x<0.01) return 1.-x2*(1.-x2/2.); else return exp(-x2);}
[3115]712
713 // Filtre top-hat T(x) = 3*(sin(x)-x*cos(x))/x^3
714 // --- Gestion de la pseudo-divergence pour x->0
715 // on prend le DL de T(x)^2 pour x->0 a l'ordre O(x^7)
716 // DL(x) = 1-x^2/5*(1-3*x^2/35*(1-4*x^2/81))
717 // pour x<0.1 |DL(x)-T(X)^2|<2.5e-13
718 double f2=0.;
719 if(x<0.1) {
720 f2 = 1.-x2/5.*(1.-3.*x2/35.*(1.-4.*x2/81.));
721 } else {
722 f2 = 3.*(sin(x)-x*cos(x))/(x2*x);
723 f2 *= f2;
724 }
725 return f2;
726
727}
728
[3348]729double VarianceSpectrum::Variance(double kmin,double kmax)
[3115]730// Compute variance of spectrum pk_ by integration
731// Input:
732// kmin,kmax = bornes en k de l'integrale pour calculer la variance
733// Return:
734// valeur de la variance (sigma^2)
735// Remarque:
736// la variance renvoyee est la variance de la masse
737{
[3348]738 if(kmin<=0 || kmax<=0. || kmin>=kmax) {
739 cout<<"VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax"<<endl;
740 throw ParmError("VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax");
[3115]741 }
742
743 double lkmin = log10(kmin), lkmax = log10(kmax);
744
745 double var = IntegrateFuncLog(*this,lkmin,lkmax,dperc_,dlogkinc_,dlogkmax_,glorder_);
746
747 return var;
748}
749
750//------------------------------------
[3348]751double VarianceSpectrum::FindMaximum(double kmin,double kmax,double eps)
[3115]752// Retourne le maximum de la fonction a integrer
753// La recherche a lieu entre [kmin,kmax] par pas logarithmiques
754// Input:
755// kmin,kmax : intervalle de recherche
756// eps : precision requise sur les valeurs
757// Return:
758// position (en k) du maximum
759{
[3348]760 if(kmin<=0 || kmax<=0. || kmin>=kmax) {
761 cout<<"VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0"<<endl;
762 throw ParmError("VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
[3115]763 }
764
765 int n = 10; // toujours >2
766 double lkmin = log10(kmin), lkmax = log10(kmax), dlk = (lkmax-lkmin)/n;
767
768 double lkfind=lkmin, pkfind=-1.;
769 while(1) {
770 for(int i=0; i<=n; i++) {
771 double lk = lkmin + i*dlk;
772 double v = (*this)(pow(10.,lk));
773 if(v<pkfind) continue;
774 pkfind = v; lkfind = lk;
775 }
776 //cout<<"VarianceSpectrum::FindMaximum: lkfind="<<lkfind<<" pkfind="<<pkfind
777 // <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
778 // --- Convergence si l'encadrement de "kfind" est tel que "dk/kfind<eps"
779 // On a dk = 10^(lkfind+dlk) - 10^(lkfind-dlk) = kfind * (10^(dlk) - 10^(-dlk))
780 if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
781 if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
782 if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
783 dlk = (lkmax-lkmin)/n;
784 }
785
786 return pow(10.,lkfind);
787}
788
[3348]789int VarianceSpectrum::FindLimits(double high,double &kmin,double &kmax,double eps)
[3115]790// Retourne "[kmin,kmax]" tel que la fonction a integrer soit "f(k) <= high"
791// La recherche a lieu entre [kmin,kmax] par pas logarithmiques
792// Input:
793// kmin,kmax : intervalle de recherche
794// eps : precision requise sur les valeurs kmin et kmax
795// Output:
796// kmin,kmax telles que "f(k) <= high"
797// Return:
798// rc = 0 si OK
799// rc |= 1 "f(kmin) >= high" (bit0 =1)
800// rc |= 2 "f(kmax) >= high" (bit1 =1)
801// rc |= 4 "f(k) < high pour tout k" (bit2 =1)
802{
[3348]803 if(kmin<=0 || kmax<=0. || kmin>=kmax || eps<=0.) {
804 cout<<"VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax or eps<=0"<<endl;
805 throw ParmError("VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
[3115]806 }
807
808 int n = 10; // toujours >2
809
810 int rc = 0;
811 double lkmin,lkmax,dlk,lkfind;
812
813 // --- Find kmin
814 lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
815 while(1) {
816 lkfind = lkmin;
817 for(int i=0;i<=n;i++) {
[3314]818 if( (*this)(pow(10,lkfind)) >= high ) break;
[3115]819 lkfind = lkmin + i*dlk;
820 }
821 //cout<<"VarianceSpectrum::FindLimits[kmin]: lkfind="<<lkfind
822 // <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
823 if(fabs(lkfind-lkmax)<dlk/2.) {rc |= 4; return rc;} // protect against f(k)<high for all k
824 if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
825 if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
826 if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
827 dlk = (lkmax-lkmin)/n;
828 }
829 if(lkfind-lkmin<dlk/2.) rc |= 1; // f(kmin) >= high
830 else kmin = pow(10.,lkmin);
831 //cout<<"rc="<<rc<<" lkmin="<<lkmin<<" pk="<<(*this)(pow(10.,lkmin))<<endl;
832
833 // --- Find kmax
834 lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
835 while(1) {
836 lkfind=lkmax;
837 for(int i=0;i<=n;i++) {
[3314]838 if( (*this)(pow(10,lkfind)) >= high ) break;
[3115]839 lkfind -= dlk;
840 lkfind = lkmax - i*dlk;
841 }
842 //cout<<"VarianceSpectrum::FindLimits[kmax]: lkfind="<<lkfind
843 // <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
844 if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
845 if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
846 if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
847 dlk = (lkmax-lkmin)/n;
848 }
849 if(lkmax-lkfind<dlk/2.) rc |= 2; // f(kmax) >= high
850 else kmax = pow(10.,lkmax);
851 //cout<<"rc="<<rc<<" lkmax="<<lkmax<<" pk="<<(*this)(pow(10.,lkmax))<<endl;
852
853 return rc;
854}
[3325]855
856} // Fin namespace SOPHYA
Note: See TracBrowser for help on using the repository browser.