| 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"
 | 
|---|
| 12 | #include "geneutils.h"
 | 
|---|
| 13 | #include "pkspectrum.h"
 | 
|---|
| 14 | 
 | 
|---|
| 15 | namespace SOPHYA {
 | 
|---|
| 16 | 
 | 
|---|
| 17 | ///////////////////////////////////////////////////////////
 | 
|---|
| 18 | //******************** InitialSpectrum ******************//
 | 
|---|
| 19 | ///////////////////////////////////////////////////////////
 | 
|---|
| 20 | 
 | 
|---|
| 21 | InitialSpectrum::InitialSpectrum(double n,double a)
 | 
|---|
| 22 |   : n_(n), A_(a)
 | 
|---|
| 23 | {
 | 
|---|
| 24 | }
 | 
|---|
| 25 | 
 | 
|---|
| 26 | InitialSpectrum::InitialSpectrum(InitialSpectrum& pkinf)
 | 
|---|
| 27 |   : n_(pkinf.n_), A_(pkinf.A_)
 | 
|---|
| 28 | {
 | 
|---|
| 29 | }
 | 
|---|
| 30 | 
 | 
|---|
| 31 | InitialSpectrum::~InitialSpectrum(void)
 | 
|---|
| 32 | {
 | 
|---|
| 33 | }
 | 
|---|
| 34 | 
 | 
|---|
| 35 | 
 | 
|---|
| 36 | ///////////////////////////////////////////////////////////
 | 
|---|
| 37 | //****************** TransfertEisenstein ****************//
 | 
|---|
| 38 | ///////////////////////////////////////////////////////////
 | 
|---|
| 39 | 
 | 
|---|
| 40 | // From Eisenstein & Hu ApJ 496:605-614 1998 April 1 (ou astro-ph/9709112)
 | 
|---|
| 41 | TransfertEisenstein::TransfertEisenstein(double h100,double OmegaCDM0,double OmegaBaryon0,double tcmb,bool nobaryon,int lp)
 | 
|---|
| 42 |   : lp_(lp)
 | 
|---|
| 43 |   , Oc_(OmegaCDM0) , Ob_(OmegaBaryon0) , h100_(h100) , tcmb_(tcmb)
 | 
|---|
| 44 |   , nobaryon_(nobaryon) , nooscenv_(0), retpart_(ALL)
 | 
|---|
| 45 | {
 | 
|---|
| 46 |  zero_();
 | 
|---|
| 47 |  Init_();
 | 
|---|
| 48 | }
 | 
|---|
| 49 | 
 | 
|---|
| 50 | TransfertEisenstein::TransfertEisenstein(TransfertEisenstein& tf)
 | 
|---|
| 51 |   : lp_(tf.lp_)
 | 
|---|
| 52 |   ,Oc_(tf.Oc_) , Ob_(tf.Ob_) , h100_(tf.h100_) , tcmb_(tf.tcmb_)
 | 
|---|
| 53 |   , nobaryon_(tf.nobaryon_) , nooscenv_(tf.nooscenv_), retpart_(tf.retpart_)
 | 
|---|
| 54 | {
 | 
|---|
| 55 |  zero_();
 | 
|---|
| 56 |  Init_();
 | 
|---|
| 57 | }
 | 
|---|
| 58 | 
 | 
|---|
| 59 | TransfertEisenstein::~TransfertEisenstein(void)
 | 
|---|
| 60 | {
 | 
|---|
| 61 | }
 | 
|---|
| 62 | 
 | 
|---|
| 63 | void 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 | 
 | 
|---|
| 69 | void TransfertEisenstein::Init_(void)
 | 
|---|
| 70 | {
 | 
|---|
| 71 | 
 | 
|---|
| 72 |   O0_ = Oc_ + Ob_;
 | 
|---|
| 73 |   if(nobaryon_) {O0_ = Oc_; Ob_ = 0.;}
 | 
|---|
| 74 |   double H0 = 100. * h100_, h2 = h100_*h100_;
 | 
|---|
| 75 |   if(lp_) cout<<"h100="<<h100_<<" H0="<<H0<<") Omatter="<<O0_<<" Ocdm="<<Oc_<<" Ob="<<Ob_<<endl;
 | 
|---|
| 76 | 
 | 
|---|
| 77 | 
 | 
|---|
| 78 |   if(tcmb_<0.) tcmb_ = T_CMB_Par;
 | 
|---|
| 79 |   th2p7_ = tcmb_/2.7;
 | 
|---|
| 80 |   double th2p7P4 = th2p7_*th2p7_*th2p7_*th2p7_;
 | 
|---|
| 81 |   if(lp_) cout<<"tcmb = "<<tcmb_<<" K = "<<th2p7_<<" *2.7K "<<endl;
 | 
|---|
| 82 | 
 | 
|---|
| 83 |   // Formule 2 p 606
 | 
|---|
| 84 |   zeq_ = 2.50e4 * O0_ * h2 / th2p7P4;
 | 
|---|
| 85 |   if(lp_) cout<<"zeq = "<<zeq_<<" (redshift of matter-radiation equality)"<<endl;
 | 
|---|
| 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_);
 | 
|---|
| 91 |   if(lp_) cout<<"keq = "<<keq_<<" Mpc^-1 (scale of equality)"<<endl;
 | 
|---|
| 92 | 
 | 
|---|
| 93 |   // On s'arrete ici si pas de baryons
 | 
|---|
| 94 |   if(nobaryon_) return;
 | 
|---|
| 95 | 
 | 
|---|
| 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);
 | 
|---|
| 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;
 | 
|---|
| 102 | 
 | 
|---|
| 103 |   // Formule 5 page 607    (R = 3*rho_baryon/4*rho_gamma)
 | 
|---|
| 104 |   Req_ = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zeq_);
 | 
|---|
| 105 |   //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: zd -> (1+zd)
 | 
|---|
| 106 |   Rd_  = 31.5*Ob_*h2 / th2p7P4 * (1.e3/zd_);
 | 
|---|
| 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 |   }
 | 
|---|
| 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_)) );
 | 
|---|
| 118 |   if(lp_) cout<<"s = "<<s_<<" Mpc (sound horizon at drag epoch)"<<endl;
 | 
|---|
| 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));
 | 
|---|
| 122 |   if(lp_) cout<<"ksilk = "<<ksilk_<<" Mpc^-1 (silk damping scale)"<<endl;
 | 
|---|
| 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.) );
 | 
|---|
| 131 |   if(lp_) cout<<"alphac = "<<alphac_<<" betac = "<<betac_
 | 
|---|
| 132 |                <<" (CDM suppression/log shift)"<<endl;
 | 
|---|
| 133 | 
 | 
|---|
| 134 |   // Formule 23 page 610
 | 
|---|
| 135 |   bnode_ = 8.41 * pow(O0_*h2,0.435);
 | 
|---|
| 136 |   if(lp_) cout<<"bnode = "<<bnode_<<" (sound horizon shift)"<<endl;
 | 
|---|
| 137 | 
 | 
|---|
| 138 |   // Formule 14 page 608
 | 
|---|
| 139 |   //WARNING: W.Hu code (tf_fit.c) en des-accord avec l'article: (1+zeq) -> zeq
 | 
|---|
| 140 |   double y = (1.+zeq_)/(1.+zd_);
 | 
|---|
| 141 |   //in tf_fit.c: double y = zeq_/(1.+zd_);
 | 
|---|
| 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.);
 | 
|---|
| 149 |   if(lp_) cout<<"alphab = "<<alphab_<<" betab = "<<betab_
 | 
|---|
| 150 |                <<" (Baryon suppression/envelope shift)"<<endl;
 | 
|---|
| 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.);
 | 
|---|
| 156 |   if(lp_) cout<<"alphag = "<<alphag_<<" (gamma suppression in approximate TF)"<<endl;
 | 
|---|
| 157 | 
 | 
|---|
| 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;
 | 
|---|
| 161 | 
 | 
|---|
| 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 | 
 | 
|---|
| 166 |   return;
 | 
|---|
| 167 | }
 | 
|---|
| 168 | 
 | 
|---|
| 169 | bool TransfertEisenstein::SetParTo(double h100,double OmegaCDM0,double OmegaBaryon0)
 | 
|---|
| 170 | // Changement des valeurs des parametres (suivi de re-init eventuel)
 | 
|---|
| 171 | // Si h100,Omega...<=0. alors pas de changement, on garde l'ancienne valeur
 | 
|---|
| 172 | {
 | 
|---|
| 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;
 | 
|---|
| 183 | }
 | 
|---|
| 184 | 
 | 
|---|
| 185 | void TransfertEisenstein::SetNoOscEnv(unsigned short nooscenv)
 | 
|---|
| 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)
 | 
|---|
| 188 | // nooscenv = 1 : use approx. paragraph 3.3 p610 (middle of right column)
 | 
|---|
| 189 | //                Replace  j0(k*stilde)  ->  [1+(k*stilde)^4]^(-1/4)
 | 
|---|
| 190 | // nooscenv = 2 : use formulae 29+30+31 page 612
 | 
|---|
| 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.
 | 
|---|
| 195 | {
 | 
|---|
| 196 |  if(nooscenv!=1 && nooscenv!=2) nooscenv = 0;
 | 
|---|
| 197 |  nooscenv_ = nooscenv;
 | 
|---|
| 198 | }
 | 
|---|
| 199 | 
 | 
|---|
| 200 | void TransfertEisenstein::SetReturnPart(ReturnPart retpart)
 | 
|---|
| 201 | // To return only baryon or CDM part part of transfert function
 | 
|---|
| 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
 | 
|---|
| 205 | // WARNING: only relevant for nobaryon_=false AND nooscenv!=2
 | 
|---|
| 206 | {
 | 
|---|
| 207 |  retpart_ = retpart;
 | 
|---|
| 208 | }
 | 
|---|
| 209 | 
 | 
|---|
| 210 | void TransfertEisenstein::SetPrintLevel(int lp)
 | 
|---|
| 211 | {
 | 
|---|
| 212 |  lp_ = lp;
 | 
|---|
| 213 | }
 | 
|---|
| 214 | 
 | 
|---|
| 215 | 
 | 
|---|
| 216 | double TransfertEisenstein::T0tild(double k,double alphac,double betac)
 | 
|---|
| 217 | {
 | 
|---|
| 218 |   // Formule 10 p 608
 | 
|---|
| 219 |   //double q = k*th2p7_*th2p7_/(O0_*h100_*h100_);
 | 
|---|
| 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 | 
 | 
|---|
| 228 | double TransfertEisenstein::operator() (double k)
 | 
|---|
| 229 | {
 | 
|---|
| 230 | 
 | 
|---|
| 231 |   // --- Pour zero baryon
 | 
|---|
| 232 |   //  OU Pour function lissee sans oscillation baryon
 | 
|---|
| 233 |   if(nobaryon_  || nooscenv_ == 2) {
 | 
|---|
| 234 |     double gamma = O0_*h100_;
 | 
|---|
| 235 |     // Calcul de Gamma_eff, formule 30 page 612 (pour fct lissee)
 | 
|---|
| 236 |     if( nobaryon_==false && nooscenv_ == 2 )
 | 
|---|
| 237 |       gamma = O0_*h100_*(alphag_ + (1.-alphag_)/(1.+pow(0.43*k*sfit_,4.))); // Gamma_eff
 | 
|---|
| 238 |     // Formule 28 page 612 : qui est est equivalent a:
 | 
|---|
| 239 |     //    q = k / h100_ * th2p7_*th2p7_ / gamma;
 | 
|---|
| 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)
 | 
|---|
| 245 |     //double q = k / h100_ * th2p7_*th2p7_ / gamma;  // Mpc^-1
 | 
|---|
| 246 |     double q = k/(13.41*keq_) * (O0_*h100_/gamma);  // Mpc^-1
 | 
|---|
| 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 | 
 | 
|---|
| 253 |   // --- Pour CDM + Baryons
 | 
|---|
| 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_);
 | 
|---|
| 257 |   if(retpart_ == CDM) return Tc; 
 | 
|---|
| 258 | 
 | 
|---|
| 259 |   // --- Baryons
 | 
|---|
| 260 |   // Formule 22 page 610
 | 
|---|
| 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.);
 | 
|---|
| 264 |   // Formule 21 page 610
 | 
|---|
| 265 |   double j0kst = 0.;
 | 
|---|
| 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;
 | 
|---|
| 270 |     if(x<0.01) j0kst = 1. - x*x/6.*(1.-x*x/20.);
 | 
|---|
| 271 |       else j0kst = sin(x)/x;
 | 
|---|
| 272 |     //cout<<"DEBUG: k="<<k<<" stilde="<<stilde<<" x="<<x<<" j0kst="<<j0kst<<endl;
 | 
|---|
| 273 |   }
 | 
|---|
| 274 |   double Tb = T0tild(k,1.,1.) / (1. + pow(k*s_/5.2,2.));
 | 
|---|
| 275 |   Tb += alphab_/(1.+pow(betab_/(k*s_),3.)) * exp(-pow(k/ksilk_,1.4));
 | 
|---|
| 276 |   Tb *= j0kst;
 | 
|---|
| 277 |   if(retpart_ == BARYON) return Tb;
 | 
|---|
| 278 | 
 | 
|---|
| 279 |   // --- Total
 | 
|---|
| 280 |   double T = (Ob_/O0_)*Tb + (Oc_/O0_)*Tc;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |   return T;
 | 
|---|
| 283 | }
 | 
|---|
| 284 | 
 | 
|---|
| 285 | double TransfertEisenstein::KPeak(void)
 | 
|---|
| 286 | // Position du premier pic acoustic
 | 
|---|
| 287 | {
 | 
|---|
| 288 |  if(nobaryon_) return -1.;
 | 
|---|
| 289 |  return kpeak_;
 | 
|---|
| 290 | }
 | 
|---|
| 291 | 
 | 
|---|
| 292 | 
 | 
|---|
| 293 | ///////////////////////////////////////////////////////////
 | 
|---|
| 294 | //******************* TransfertTabulate *****************//
 | 
|---|
| 295 | ///////////////////////////////////////////////////////////
 | 
|---|
| 296 | 
 | 
|---|
| 297 | TransfertTabulate::TransfertTabulate(double h100,double OmegaCDM0,double OmegaBaryon0)
 | 
|---|
| 298 | : Oc_(OmegaCDM0) , Ob_(OmegaBaryon0) , h100_(h100) , kmin_(1.) , kmax_(-1.)
 | 
|---|
| 299 | , interptyp_(0)
 | 
|---|
| 300 | {
 | 
|---|
| 301 | }
 | 
|---|
| 302 | 
 | 
|---|
| 303 | TransfertTabulate::TransfertTabulate(TransfertTabulate& tf)
 | 
|---|
| 304 | : Oc_(tf.Oc_) , Ob_(tf.Ob_) , h100_(tf.h100_) , kmin_(tf.kmin_) , kmax_(tf.kmax_)
 | 
|---|
| 305 | , interptyp_(tf.interptyp_) , k_(tf.k_) , tf_(tf.tf_)
 | 
|---|
| 306 | {
 | 
|---|
| 307 | }
 | 
|---|
| 308 | 
 | 
|---|
| 309 | TransfertTabulate::~TransfertTabulate(void)
 | 
|---|
| 310 | {
 | 
|---|
| 311 | }
 | 
|---|
| 312 | 
 | 
|---|
| 313 | void 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 | 
 | 
|---|
| 320 | double TransfertTabulate::operator() (double k)
 | 
|---|
| 321 | {
 | 
|---|
| 322 |  return InterpTab(k,k_,tf_,interptyp_);
 | 
|---|
| 323 | }
 | 
|---|
| 324 | 
 | 
|---|
| 325 | int TransfertTabulate::ReadCMBFast(string filename)
 | 
|---|
| 326 | {
 | 
|---|
| 327 |  FILE *file = fopen(filename.c_str(),"r");
 | 
|---|
| 328 |  if(file==NULL) return -1;
 | 
|---|
| 329 | 
 | 
|---|
| 330 |  const int lenline = 512;
 | 
|---|
| 331 |  char *line = new char[lenline];
 | 
|---|
| 332 | 
 | 
|---|
| 333 |  int nread = 0;
 | 
|---|
| 334 |  double tmax = -1.;
 | 
|---|
| 335 |  while ( fgets(line,lenline,file) != NULL ) {
 | 
|---|
| 336 |    double k,tc,tb,tf;
 | 
|---|
| 337 |    sscanf(line,"%lf %lf %lf",&k,&tc,&tb);
 | 
|---|
| 338 |    k *= h100_;     // convert h^-1 Mpc  ->  Mpc
 | 
|---|
| 339 |    tf = (Oc_*tc+Ob_*tb)/(Oc_+Ob_);
 | 
|---|
| 340 |    if(tf>tmax) tmax = tf;
 | 
|---|
| 341 |    k_.push_back(k);
 | 
|---|
| 342 |    tf_.push_back(tf);
 | 
|---|
| 343 |    nread++;
 | 
|---|
| 344 |  }
 | 
|---|
| 345 | 
 | 
|---|
| 346 |  cout<<"TransfertTabulate::ReadCMBFast: nread="<<nread<<" tf_max="<<tmax<<endl;
 | 
|---|
| 347 |  delete [] line;
 | 
|---|
| 348 |  if(nread==0) return nread;
 | 
|---|
| 349 | 
 | 
|---|
| 350 |  for(unsigned int i=0;i<tf_.size();i++) tf_[i] /= tmax;
 | 
|---|
| 351 | 
 | 
|---|
| 352 |  return nread;
 | 
|---|
| 353 | }
 | 
|---|
| 354 | 
 | 
|---|
| 355 | ///////////////////////////////////////////////////////////
 | 
|---|
| 356 | //********************* GrowthFactor ********************//
 | 
|---|
| 357 | ///////////////////////////////////////////////////////////
 | 
|---|
| 358 | 
 | 
|---|
| 359 | // From Eisenstein & Hu ApJ 496:605-614 1998 April 1
 | 
|---|
| 360 | // Pour avoir D(z) = 1/(1+z) faire: OmegaMatter0=1 OmegaLambda0=0
 | 
|---|
| 361 | GrowthFactor::GrowthFactor(double OmegaMatter0,double OmegaLambda0)
 | 
|---|
| 362 |   : O0_(OmegaMatter0) , Ol_(OmegaLambda0)
 | 
|---|
| 363 | {
 | 
|---|
| 364 |   if(OmegaMatter0==0.) {
 | 
|---|
| 365 |     cout<<"GrowthFactor::GrowthFactor: Error bad OmegaMatter0  value : "<<OmegaMatter0<<endl;
 | 
|---|
| 366 |     throw ParmError("GrowthFactor::GrowthFactor: Error badOmegaMatter0  value");
 | 
|---|
| 367 |   }
 | 
|---|
| 368 | }
 | 
|---|
| 369 | 
 | 
|---|
| 370 | GrowthFactor::GrowthFactor(GrowthFactor& d1)
 | 
|---|
| 371 |   : O0_(d1.O0_) , Ol_(d1.Ol_)
 | 
|---|
| 372 | {
 | 
|---|
| 373 | }
 | 
|---|
| 374 | 
 | 
|---|
| 375 | GrowthFactor::~GrowthFactor(void)
 | 
|---|
| 376 | {
 | 
|---|
| 377 | }
 | 
|---|
| 378 | 
 | 
|---|
| 379 | double GrowthFactor::operator() (double z)
 | 
|---|
| 380 | // see Formulae A4 + A5 + A6 page 614
 | 
|---|
| 381 | {
 | 
|---|
| 382 |  z += 1.;
 | 
|---|
| 383 |  double z2 = z*z, z3 = z2*z;
 | 
|---|
| 384 | 
 | 
|---|
| 385 |  // Calcul de la normalisation (pour z=0 -> growth=1.)
 | 
|---|
| 386 |  double D1z0 = pow(O0_,4./7.) - Ol_ + (1.+O0_/2.)*(1.+Ol_/70.);
 | 
|---|
| 387 |  D1z0 = 2.5*O0_ / D1z0;
 | 
|---|
| 388 | 
 | 
|---|
| 389 |  // Calcul du growthfactor pour z
 | 
|---|
| 390 |  double Ok = 1. - O0_ - Ol_;
 | 
|---|
| 391 |  double den = Ol_ + Ok*z2 + O0_*z3;
 | 
|---|
| 392 |  double o0z = O0_ *z3 / den;
 | 
|---|
| 393 |  double olz = Ol_ / den;
 | 
|---|
| 394 | 
 | 
|---|
| 395 |  double D1z = pow(o0z,4./7.) - olz + (1.+o0z/2.)*(1.+olz/70.);
 | 
|---|
| 396 |  D1z = 2.5*o0z / z / D1z;
 | 
|---|
| 397 | 
 | 
|---|
| 398 |  return D1z / D1z0;
 | 
|---|
| 399 | }
 | 
|---|
| 400 | 
 | 
|---|
| 401 | void GrowthFactor::SetParTo(double OmegaMatter0,double OmegaLambda0)
 | 
|---|
| 402 | {
 | 
|---|
| 403 |  if(OmegaMatter0>0.) O0_ = OmegaMatter0;
 | 
|---|
| 404 |  Ol_ = OmegaLambda0;
 | 
|---|
| 405 | }
 | 
|---|
| 406 | 
 | 
|---|
| 407 | bool GrowthFactor::SetParTo(double OmegaMatter0)
 | 
|---|
| 408 | // idem precedent sans changer OmegaLambda0
 | 
|---|
| 409 | {
 | 
|---|
| 410 |  if(OmegaMatter0<=0.) return false;
 | 
|---|
| 411 |  O0_ = OmegaMatter0;
 | 
|---|
| 412 |  return true;
 | 
|---|
| 413 | }
 | 
|---|
| 414 | 
 | 
|---|
| 415 | 
 | 
|---|
| 416 | ///////////////////////////////////////////////////////////
 | 
|---|
| 417 | //************** PkSpectrum0 et PkSpectrumZ *************//
 | 
|---|
| 418 | ///////////////////////////////////////////////////////////
 | 
|---|
| 419 | 
 | 
|---|
| 420 | PkSpectrum0::PkSpectrum0(InitialSpectrum& pkinf,TransfertEisenstein& tf)
 | 
|---|
| 421 |   : pkinf_(pkinf) , tf_(tf)
 | 
|---|
| 422 | {
 | 
|---|
| 423 | }
 | 
|---|
| 424 | 
 | 
|---|
| 425 | PkSpectrum0::PkSpectrum0(PkSpectrum0& pk0)
 | 
|---|
| 426 |   : pkinf_(pk0.pkinf_) , tf_(pk0.tf_)
 | 
|---|
| 427 | {
 | 
|---|
| 428 | }
 | 
|---|
| 429 | 
 | 
|---|
| 430 | PkSpectrum0::~PkSpectrum0(void)
 | 
|---|
| 431 | {
 | 
|---|
| 432 | }
 | 
|---|
| 433 | 
 | 
|---|
| 434 | double PkSpectrum0::operator() (double k)
 | 
|---|
| 435 | {
 | 
|---|
| 436 |   double tf = tf_(k);
 | 
|---|
| 437 |   double pkinf = pkinf_(k);
 | 
|---|
| 438 |   return pkinf *tf*tf;
 | 
|---|
| 439 | }
 | 
|---|
| 440 | 
 | 
|---|
| 441 | //------------------------------------
 | 
|---|
| 442 | PkSpectrumZ::PkSpectrumZ(PkSpectrum0& pk0,GrowthFactor& d1,double zref)
 | 
|---|
| 443 |   : pk0_(pk0) , d1_(d1) , zref_(zref) , scale_(1.) , typspec_(PK)
 | 
|---|
| 444 | {
 | 
|---|
| 445 | }
 | 
|---|
| 446 | 
 | 
|---|
| 447 | PkSpectrumZ::PkSpectrumZ(PkSpectrumZ& pkz)
 | 
|---|
| 448 |   : pk0_(pkz.pk0_) , d1_(pkz.d1_) , zref_(pkz.zref_) , scale_(pkz.scale_) , typspec_(PK)
 | 
|---|
| 449 | {
 | 
|---|
| 450 | }
 | 
|---|
| 451 | 
 | 
|---|
| 452 | PkSpectrumZ::~PkSpectrumZ(void) 
 | 
|---|
| 453 | {
 | 
|---|
| 454 | }
 | 
|---|
| 455 | 
 | 
|---|
| 456 | void PkSpectrumZ::SetTypSpec(ReturnSpectrum typspec)
 | 
|---|
| 457 | // typsec = PK : compute Pk(k)
 | 
|---|
| 458 | //        = DELTA : compute Delta^2(k) = k^3*Pk(k)/2Pi^2
 | 
|---|
| 459 | {
 | 
|---|
| 460 |   typspec_ = typspec;
 | 
|---|
| 461 | }
 | 
|---|
| 462 | 
 | 
|---|
| 463 | double PkSpectrumZ::operator() (double k)
 | 
|---|
| 464 | {
 | 
|---|
| 465 |   return (*this)(k,zref_);
 | 
|---|
| 466 | }
 | 
|---|
| 467 | 
 | 
|---|
| 468 | double PkSpectrumZ::operator() (double k,double z)
 | 
|---|
| 469 | {
 | 
|---|
| 470 |   double d1 = d1_(z);
 | 
|---|
| 471 | 
 | 
|---|
| 472 |   double v = pk0_(k) * d1*d1;
 | 
|---|
| 473 |   if(typspec_==DELTA) v *= k*k*k/(2.*M_PI*M_PI);
 | 
|---|
| 474 | 
 | 
|---|
| 475 |   return scale_ * v;
 | 
|---|
| 476 | }
 | 
|---|
| 477 | 
 | 
|---|
| 478 | 
 | 
|---|
| 479 | 
 | 
|---|
| 480 | ///////////////////////////////////////////////////////////
 | 
|---|
| 481 | //******************* VarianceSpectrum ******************//
 | 
|---|
| 482 | ///////////////////////////////////////////////////////////
 | 
|---|
| 483 | 
 | 
|---|
| 484 | VarianceSpectrum::VarianceSpectrum(GenericFunc& pk,double R,TypeFilter typfilter)
 | 
|---|
| 485 |   : pk_(pk)
 | 
|---|
| 486 | {
 | 
|---|
| 487 |   SetRadius(R);
 | 
|---|
| 488 |   SetFilter(typfilter);
 | 
|---|
| 489 | }
 | 
|---|
| 490 | 
 | 
|---|
| 491 | VarianceSpectrum::VarianceSpectrum(VarianceSpectrum& vpk)
 | 
|---|
| 492 |   : pk_(vpk.pk_) , R_(vpk.R_)
 | 
|---|
| 493 | {
 | 
|---|
| 494 |   SetFilter(vpk.typfilter_);
 | 
|---|
| 495 | }
 | 
|---|
| 496 | 
 | 
|---|
| 497 | VarianceSpectrum::~VarianceSpectrum(void)
 | 
|---|
| 498 | {
 | 
|---|
| 499 | }
 | 
|---|
| 500 | 
 | 
|---|
| 501 | void VarianceSpectrum::SetRadius(double R)
 | 
|---|
| 502 | // R = taille du filter top-hat ou gaussien
 | 
|---|
| 503 | {
 | 
|---|
| 504 |  if(R<=0.) {
 | 
|---|
| 505 |     cout<<"VarianceSpectrum::SetRadius: Error R<=0"<<endl;
 | 
|---|
| 506 |     throw ParmError("VarianceSpectrum::SetRadius: Error R<=0");
 | 
|---|
| 507 |   }
 | 
|---|
| 508 |   R_ = R;
 | 
|---|
| 509 | }
 | 
|---|
| 510 | 
 | 
|---|
| 511 | //------------------------------------
 | 
|---|
| 512 | void VarianceSpectrum::SetFilter(TypeFilter typfilter)
 | 
|---|
| 513 | // typfilter = TOPHAT : spherical 3D top-hat
 | 
|---|
| 514 | //           = GAUSSIAN : spherical 3D gaussian
 | 
|---|
| 515 | //           = NOFILTER : no filter juste integrate spectrum)
 | 
|---|
| 516 | // Remarque:
 | 
|---|
| 517 | //   la meilleure approximation du filtre top-hat (R) est un filtre gaussien avec (Rg=R/sqrt(5))
 | 
|---|
| 518 | {
 | 
|---|
| 519 |   typfilter_ = typfilter;
 | 
|---|
| 520 | }
 | 
|---|
| 521 | 
 | 
|---|
| 522 | void VarianceSpectrum::SetInteg(double dperc,double dlogkinc,double dlogkmax,unsigned short glorder)
 | 
|---|
| 523 | // ATTENTION: on n'integre pas f(k)*dk mais k*f(k)*d(log10(k))
 | 
|---|
| 524 | // see argument details in function IntegrateFuncLog (geneutils.cc)
 | 
|---|
| 525 | {
 | 
|---|
| 526 |   dperc_ = dperc;  if(dperc_<=0.) dperc_ = 0.1;
 | 
|---|
| 527 |   dlogkinc_ = dlogkinc;
 | 
|---|
| 528 |   dlogkmax_ = dlogkmax;
 | 
|---|
| 529 |   glorder_ = glorder;
 | 
|---|
| 530 | }
 | 
|---|
| 531 | 
 | 
|---|
| 532 | 
 | 
|---|
| 533 | //------------------------------------
 | 
|---|
| 534 | double VarianceSpectrum::Filter2(double x)
 | 
|---|
| 535 | // ATTENTION: c'est le filtre au carre qui est renvoye
 | 
|---|
| 536 | {
 | 
|---|
| 537 |   // Just integrate the spectrum without filtering
 | 
|---|
| 538 |   if(typfilter_ == NOFILTER) return 1.;
 | 
|---|
| 539 | 
 | 
|---|
| 540 |   double x2 = x*x;
 | 
|---|
| 541 |   // Filtre gaussien G(x) = exp(-x^2/2)
 | 
|---|
| 542 |   //        remarque G(x)^2 = exp(-x^2)
 | 
|---|
| 543 |   // on prend le DL de G(x)^2 pour x->0 a l'ordre O(x^6)
 | 
|---|
| 544 |   //             DL(x) = 1-x^2*(1-x^2/2)
 | 
|---|
| 545 |   //             pour x<0.01  |DL(x)-G(X)^2|<2.0e-13
 | 
|---|
| 546 |   if(typfilter_ == GAUSSIAN)
 | 
|---|
| 547 |     {if(x<0.01) return 1.-x2*(1.-x2/2.); else return exp(-x2);}
 | 
|---|
| 548 | 
 | 
|---|
| 549 |   // Filtre top-hat T(x) = 3*(sin(x)-x*cos(x))/x^3
 | 
|---|
| 550 |   // --- Gestion de la pseudo-divergence pour x->0
 | 
|---|
| 551 |   // on prend le DL de T(x)^2 pour x->0 a l'ordre O(x^7)
 | 
|---|
| 552 |   //             DL(x) = 1-x^2/5*(1-3*x^2/35*(1-4*x^2/81))
 | 
|---|
| 553 |   //             pour x<0.1  |DL(x)-T(X)^2|<2.5e-13
 | 
|---|
| 554 |   double f2=0.;
 | 
|---|
| 555 |   if(x<0.1) {
 | 
|---|
| 556 |     f2 = 1.-x2/5.*(1.-3.*x2/35.*(1.-4.*x2/81.));
 | 
|---|
| 557 |   } else {
 | 
|---|
| 558 |     f2 = 3.*(sin(x)-x*cos(x))/(x2*x);
 | 
|---|
| 559 |     f2 *= f2;
 | 
|---|
| 560 |   }
 | 
|---|
| 561 |   return f2;
 | 
|---|
| 562 |   
 | 
|---|
| 563 | }
 | 
|---|
| 564 | 
 | 
|---|
| 565 | double VarianceSpectrum::Variance(double kmin,double kmax)
 | 
|---|
| 566 | // Compute variance of spectrum pk_ by integration
 | 
|---|
| 567 | // Input:
 | 
|---|
| 568 | //     kmin,kmax = bornes en k de l'integrale pour calculer la variance
 | 
|---|
| 569 | // Return:
 | 
|---|
| 570 | //     valeur de la variance (sigma^2)
 | 
|---|
| 571 | // Remarque:
 | 
|---|
| 572 | //   la variance renvoyee est la variance de la masse
 | 
|---|
| 573 | {
 | 
|---|
| 574 |   if(kmin<=0 || kmax<=0. || kmin>=kmax) {
 | 
|---|
| 575 |     cout<<"VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax"<<endl;
 | 
|---|
| 576 |     throw ParmError("VarianceSpectrum::Variance: Error kmin<=0 or kmax<=0 or kmin>=kmax");
 | 
|---|
| 577 |   }
 | 
|---|
| 578 | 
 | 
|---|
| 579 |   double lkmin = log10(kmin), lkmax = log10(kmax);
 | 
|---|
| 580 | 
 | 
|---|
| 581 |   double var = IntegrateFuncLog(*this,lkmin,lkmax,dperc_,dlogkinc_,dlogkmax_,glorder_);
 | 
|---|
| 582 | 
 | 
|---|
| 583 |   return var;
 | 
|---|
| 584 | }
 | 
|---|
| 585 | 
 | 
|---|
| 586 | //------------------------------------
 | 
|---|
| 587 | double VarianceSpectrum::FindMaximum(double kmin,double kmax,double eps)
 | 
|---|
| 588 | // Retourne le maximum de la fonction a integrer
 | 
|---|
| 589 | // La recherche a lieu entre [kmin,kmax] par pas logarithmiques
 | 
|---|
| 590 | // Input:
 | 
|---|
| 591 | //     kmin,kmax : intervalle de recherche
 | 
|---|
| 592 | //     eps : precision requise sur les valeurs
 | 
|---|
| 593 | // Return:
 | 
|---|
| 594 | //     position (en k) du maximum
 | 
|---|
| 595 | {
 | 
|---|
| 596 |   if(kmin<=0 || kmax<=0. || kmin>=kmax) {
 | 
|---|
| 597 |     cout<<"VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0"<<endl;
 | 
|---|
| 598 |     throw ParmError("VarianceSpectrum::FindMaximum: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
 | 
|---|
| 599 |   }
 | 
|---|
| 600 | 
 | 
|---|
| 601 |   int n = 10; // toujours >2
 | 
|---|
| 602 |   double lkmin = log10(kmin), lkmax = log10(kmax), dlk = (lkmax-lkmin)/n;
 | 
|---|
| 603 | 
 | 
|---|
| 604 |   double lkfind=lkmin, pkfind=-1.;
 | 
|---|
| 605 |   while(1) {
 | 
|---|
| 606 |     for(int i=0; i<=n; i++) {
 | 
|---|
| 607 |       double lk = lkmin  + i*dlk;
 | 
|---|
| 608 |       double v = (*this)(pow(10.,lk));
 | 
|---|
| 609 |       if(v<pkfind) continue;
 | 
|---|
| 610 |       pkfind = v; lkfind = lk;
 | 
|---|
| 611 |     }
 | 
|---|
| 612 |     //cout<<"VarianceSpectrum::FindMaximum: lkfind="<<lkfind<<" pkfind="<<pkfind
 | 
|---|
| 613 |     //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
 | 
|---|
| 614 |     // --- Convergence si l'encadrement de "kfind" est tel que "dk/kfind<eps"
 | 
|---|
| 615 |     // On a dk = 10^(lkfind+dlk) - 10^(lkfind-dlk) = kfind * (10^(dlk) - 10^(-dlk))
 | 
|---|
| 616 |     if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
 | 
|---|
| 617 |     if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
 | 
|---|
| 618 |     if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
 | 
|---|
| 619 |     dlk = (lkmax-lkmin)/n;
 | 
|---|
| 620 |   }
 | 
|---|
| 621 | 
 | 
|---|
| 622 |   return pow(10.,lkfind);
 | 
|---|
| 623 | }
 | 
|---|
| 624 | 
 | 
|---|
| 625 | int VarianceSpectrum::FindLimits(double high,double &kmin,double &kmax,double eps)
 | 
|---|
| 626 | // Retourne "[kmin,kmax]" tel que la fonction a integrer soit "f(k) <= high"
 | 
|---|
| 627 | //   La recherche a lieu entre [kmin,kmax] par pas logarithmiques
 | 
|---|
| 628 | // Input:
 | 
|---|
| 629 | //     kmin,kmax : intervalle de recherche
 | 
|---|
| 630 | //     eps : precision requise sur les valeurs kmin et kmax
 | 
|---|
| 631 | // Output:
 | 
|---|
| 632 | //     kmin,kmax telles que "f(k) <= high"
 | 
|---|
| 633 | // Return:
 | 
|---|
| 634 | //     rc  = 0 si OK
 | 
|---|
| 635 | //     rc |= 1 "f(kmin) >= high"   (bit0 =1)
 | 
|---|
| 636 | //     rc |= 2 "f(kmax) >= high"   (bit1 =1)
 | 
|---|
| 637 | //     rc |= 4 "f(k) < high pour tout k"   (bit2 =1)
 | 
|---|
| 638 | {
 | 
|---|
| 639 |   if(kmin<=0 || kmax<=0. || kmin>=kmax  || eps<=0.) {
 | 
|---|
| 640 |     cout<<"VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax or eps<=0"<<endl;
 | 
|---|
| 641 |     throw ParmError("VarianceSpectrum::FindLimits: Error kmin<=0 or kmax<=0 or kmin>=kmax || eps<=0");
 | 
|---|
| 642 |   }
 | 
|---|
| 643 | 
 | 
|---|
| 644 |   int n = 10; // toujours >2
 | 
|---|
| 645 | 
 | 
|---|
| 646 |   int rc = 0;
 | 
|---|
| 647 |   double lkmin,lkmax,dlk,lkfind;
 | 
|---|
| 648 | 
 | 
|---|
| 649 |   // --- Find kmin
 | 
|---|
| 650 |   lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
 | 
|---|
| 651 |   while(1) {
 | 
|---|
| 652 |     lkfind = lkmin;
 | 
|---|
| 653 |     for(int i=0;i<=n;i++) {
 | 
|---|
| 654 |       if( (*this)(pow(10,lkfind)) >= high ) break;
 | 
|---|
| 655 |       lkfind = lkmin + i*dlk;
 | 
|---|
| 656 |     }
 | 
|---|
| 657 |     //cout<<"VarianceSpectrum::FindLimits[kmin]: lkfind="<<lkfind
 | 
|---|
| 658 |     //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
 | 
|---|
| 659 |     if(fabs(lkfind-lkmax)<dlk/2.) {rc |= 4; return rc;} // protect against f(k)<high for all k
 | 
|---|
| 660 |     if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
 | 
|---|
| 661 |     if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
 | 
|---|
| 662 |     if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
 | 
|---|
| 663 |     dlk = (lkmax-lkmin)/n;
 | 
|---|
| 664 |   }
 | 
|---|
| 665 |   if(lkfind-lkmin<dlk/2.) rc |= 1;  // f(kmin) >= high
 | 
|---|
| 666 |   else kmin = pow(10.,lkmin);
 | 
|---|
| 667 |   //cout<<"rc="<<rc<<" lkmin="<<lkmin<<"  pk="<<(*this)(pow(10.,lkmin))<<endl;
 | 
|---|
| 668 | 
 | 
|---|
| 669 |   // --- Find kmax
 | 
|---|
| 670 |   lkmin=log10(kmin); lkmax=log10(kmax); dlk=(lkmax-lkmin)/n;
 | 
|---|
| 671 |   while(1) {
 | 
|---|
| 672 |     lkfind=lkmax;
 | 
|---|
| 673 |     for(int i=0;i<=n;i++) {
 | 
|---|
| 674 |       if( (*this)(pow(10,lkfind)) >= high ) break;
 | 
|---|
| 675 |       lkfind -= dlk;
 | 
|---|
| 676 |       lkfind = lkmax - i*dlk;
 | 
|---|
| 677 |     }
 | 
|---|
| 678 |     //cout<<"VarianceSpectrum::FindLimits[kmax]: lkfind="<<lkfind
 | 
|---|
| 679 |     //    <<" lkmin,max="<<lkmin<<","<<lkmax<<" dlk="<<dlk<<endl;
 | 
|---|
| 680 |     if( pow(10.,dlk)-pow(10.,-dlk) < eps ) break;
 | 
|---|
| 681 |     if(lkfind-dlk>lkmin) lkmin = lkfind-dlk;
 | 
|---|
| 682 |     if(lkfind+dlk<lkmax) lkmax = lkfind+dlk;
 | 
|---|
| 683 |     dlk = (lkmax-lkmin)/n;
 | 
|---|
| 684 |   }
 | 
|---|
| 685 |   if(lkmax-lkfind<dlk/2.) rc |= 2;  // f(kmax) >= high
 | 
|---|
| 686 |   else kmax = pow(10.,lkmax);
 | 
|---|
| 687 |   //cout<<"rc="<<rc<<" lkmax="<<lkmax<<"  pk="<<(*this)(pow(10.,lkmax))<<endl;
 | 
|---|
| 688 | 
 | 
|---|
| 689 |   return rc;
 | 
|---|
| 690 | }
 | 
|---|
| 691 | 
 | 
|---|
| 692 | }  // Fin namespace SOPHYA
 | 
|---|