#include "machdefs.h" #include #include #include #include #include #include #include "tarray.h" #include "pexceptions.h" #include "perandom.h" #include "srandgen.h" #include "fabtcolread.h" #include "fabtwriter.h" #include "fioarr.h" #include "ntuple.h" #include "arrctcast.h" #include "constcosmo.h" #include "geneutils.h" #include "schechter.h" #include "genefluct3d.h" #if defined(GEN3D_FLOAT) #define GEN3D_FFTW_INIT_THREADS fftwf_init_threads #define GEN3D_FFTW_CLEANUP_THREADS fftwf_cleanup_threads #define GEN3D_FFTW_PLAN_WITH_NTHREADS fftwf_plan_with_nthreads #define GEN3D_FFTW_PLAN_DFT_R2C_3D fftwf_plan_dft_r2c_3d #define GEN3D_FFTW_PLAN_DFT_C2R_3D fftwf_plan_dft_c2r_3d #define GEN3D_FFTW_DESTROY_PLAN fftwf_destroy_plan #define GEN3D_FFTW_EXECUTE fftwf_execute #else #define GEN3D_FFTW_INIT_THREADS fftw_init_threads #define GEN3D_FFTW_CLEANUP_THREADS fftw_cleanup_threads #define GEN3D_FFTW_PLAN_WITH_NTHREADS fftw_plan_with_nthreads #define GEN3D_FFTW_PLAN_DFT_R2C_3D fftw_plan_dft_r2c_3d #define GEN3D_FFTW_PLAN_DFT_C2R_3D fftw_plan_dft_c2r_3d #define GEN3D_FFTW_DESTROY_PLAN fftw_destroy_plan #define GEN3D_FFTW_EXECUTE fftw_execute #endif #define MODULE2(_x_) ((double)((_x_).real()*(_x_).real() + (_x_).imag()*(_x_).imag())) namespace SOPHYA { //------------------------------------------------------- GeneFluct3D::GeneFluct3D(long nx,long ny,long nz,double dx,double dy,double dz ,unsigned short nthread,int lp) { init_default(); lp_ = lp; nthread_ = nthread; setsize(nx,ny,nz,dx,dy,dz); setalloc(); setpointers(false); init_fftw(); } GeneFluct3D::GeneFluct3D(unsigned short nthread) { init_default(); setsize(2,2,2,1.,1.,1.); nthread_ = nthread; setalloc(); setpointers(false); init_fftw(); } GeneFluct3D::~GeneFluct3D(void) { delete_fftw(); } //------------------------------------------------------- void GeneFluct3D::init_default(void) { Nx_ = Ny_ = Nz_ = 0; is_set_fft_plan = false; nthread_ = 0; lp_ = 0; array_allocated_ = false; array_type = 0; cosmo_ = NULL; growth_ = NULL; good_dzinc_ = 0.01; compute_pk_redsh_ref_ = -999.; redsh_ref_ = -999.; kredsh_ref_ = 0.; dred_ref_ = -999.; h_ref_ = -999.; loscom_ref_ = -999.; dtrc_ref_ = dlum_ref_ = dang_ref_ = -999.; nu_ref_ = dnu_ref_ = -999.; loscom_min_ = loscom_max_ = -999.; loscom2zred_min_ = loscom2zred_max_ = 0.; xobs_[0] = xobs_[1] = xobs_[2] = 0.; zred_.resize(0); loscom_.resize(0); loscom2zred_.resize(0); } void GeneFluct3D::setsize(long nx,long ny,long nz,double dx,double dy,double dz) { if(lp_>1) cout<<"--- GeneFluct3D::setsize: N="<1) cout<<"--- GeneFluct3D::setalloc FLOAT ---"<1) cout<<"--- GeneFluct3D::setalloc DOUBLE ---"< // ATTENTION: TArray adresse en memoire a l'envers du C // Tarray(n1,n2,n3) == Carray[n3][n2][n1] sa_size_t SzK_[3] = {NCz_,Ny_,Nx_}; // a l'envers try { T_.ReSize(3,SzK_); array_allocated_ = true; array_type=0; if(lp_>1) cout<<" allocating: "<)/1.e6<<" Mo"<1) cout<<"--- GeneFluct3D::setpointers ---"<1) cout<<"--- GeneFluct3D::init_fftw ---"<0) { cout<<"...Computing with "<1) cout<<"...forward plan"<1) cout<<"...backward plan"<0) GEN3D_FFTW_CLEANUP_THREADS(); #endif is_set_fft_plan = false; } void GeneFluct3D::check_array_alloc(void) // Pour tester si le tableau T_ est alloue { if(array_allocated_) return; char bla[90]; sprintf(bla,"GeneFluct3D::check_array_alloc_Error: array is not allocated"); cout< Le pixel i=nx/2 j=ny/2 k=250.75 est au redshift 1.5 { if(redshref<0.) redshref = 0.; if(kredshref<0.) { if(Nz_<=0) { const char *bla = "GeneFluct3D::SetObservator_Error: for kredsh_ref<0 define cube geometry first"; cout<0) cout<<"--- GeneFluct3D::SetObservator zref="< zred // { if(zinc<=0.) zinc = good_dzinc_; if(lp_>0) cout<<"--- LosComRedshift: zinc="<Dhubble()/cosmo_->E(redsh_ref_)); loscom_ref_ = cosmo_->Dloscom(redsh_ref_); dtrc_ref_ = cosmo_->Dtrcom(redsh_ref_); dlum_ref_ = cosmo_->Dlum(redsh_ref_); dang_ref_ = cosmo_->Dang(redsh_ref_); h_ref_ = cosmo_->H(redsh_ref_); growth_ref_ = (*growth_)(redsh_ref_); dsdz_growth_ref_ = growth_->DsDz(redsh_ref_,zinc); nu_ref_ = Fr_HyperFin_Par/(1.+redsh_ref_); // GHz dnu_ref_ = Fr_HyperFin_Par *dred_ref_/pow(1.+redsh_ref_,2.); // GHz if(lp_>0) { cout<<"...reference pixel redshref="<=0. && xobs_[2]<=Nz_*Dz_) obs_in_cube = true; // Find MINIMUM los com distance to the observer: // c'est le centre de la face a k=0 // (ou zero si l'observateur est dans le cube) loscom_min_ = 0.; if(!obs_in_cube) loscom_min_ = -xobs_[2]; // TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED TO BE FIXED if(loscom_min_<=1.e-50) for(int i=0;i<10;i++) cout<<"ATTENTION TOUTES LES PARTIES DU CODE NE MARCHENT PAS POUR UN OBSERVATEUR DANS LE CUBE"<loscom_max_) loscom_max_ = dz2; } } } if(lp_>0) { cout<<"...zref="<loscom_max double zmin = 0., dlcmin=0.; while(1) { if(lp_>0) cout<<"...Filling zred starting at zmin="<Dloscom(z); if(dlcloscom_max_) { if(lp_>0) cout<<" Min: z="< d="<1) cout<<" , z="< d="<zred if(npoints<3) npoints = zred_.size(); InverseFunc invfun(zred_,loscom_); invfun.ComputeParab(npoints,loscom2zred_); loscom2zred_min_ = invfun.YMin(); loscom2zred_max_ = invfun.YMax(); if(lp_>0) { long n = loscom2zred_.size(); cout<<"...loscom -> zred[npoints="< zred=["; if(n>0) cout<1) cout<1 && n>0) for(int i=0;i=n-2) cout<<" i="<0) cout<<"...Compute table D'/D on "<H(z) * growth_->DsDz(z,good_dzinc_) / (*growth_)(z); dpsdfrzred_.push_back(v); if(lp_ && (i%nmod==0 || i==nptd-1)) cout<<" z="< ou le TArray > { cout<<"--- GeneFluct3D::WritePPF: Writing Cube (real="< >"<> PPFNameTag("pkgen") >> T_; from_real = false; } else { cout<<" ...reading space into TArray"<> PPFNameTag("rgen") >> R_; } setpointers(from_real); // a mettre ici pour relire les DVInfo int_8 nx = R_.Info()["NX"]; int_8 ny = R_.Info()["NY"]; int_8 nz = R_.Info()["NZ"]; r_8 dx = R_.Info()["DX"]; r_8 dy = R_.Info()["DY"]; r_8 dz = R_.Info()["DZ"]; r_8 pkzref = R_.Info()["ZREFPK"]; r_8 zref = R_.Info()["ZREF"]; r_8 kzref = R_.Info()["KZREF"]; setsize(nx,ny,nz,dx,dy,dz); init_fftw(); SetObservator(zref,kzref); array_allocated_ = true; compute_pk_redsh_ref_ = pkzref; } catch (PThrowable & exc) { cout<<"Exception : "<<(string)typeid(exc).name() <<" - Msg= "< S; char str[16]; long i,j,l; // Tranches en Z for(int s=0;s<3;s++) { S.ReSize(Nx_,Ny_); if(s==0) l=0; else if(s==1) l=(Nz_+1)/2; else l=Nz_-1; sprintf(str,"z%ld",l); for(i=0;i0) cout<<"...before fft real ---"<0) cout<<"...before Fourier realization filling"<(0.); // on coupe le continue et on l'initialise long lmod = Nx_/20; if(lmod<1) lmod=1; for(long i=0;i0 && i%lmod==0) cout<<"i="<0) cout<<"...computing power"<0) cout<<"Puissance dans la realisation: "< F = TF(f) --(FFT^-1)--> fb = TF^-1(F) = TF^-1(TF(f)) // sum(f(x_i)^2) = S // sum(F(nu_i)^2) = S*N // sum(fb(x_i)^2) = S*N^2 { // --- RaZ du tableau T_ = complex(0.); compute_pk_redsh_ref_ = pk_at_z.GetZ(); // --- On remplit avec une realisation if(lp_>0) cout<<"--- ComputeFourier at z="<0 && i%lmod==0) cout<<"i="<0) cout<<"Puissance dans la realisation: "<1) cout<<"...managing coefficients"<1) cout<<"Number of forced real number ="<1) cout<<"Number of forced conjugate on cont+nyq ="<1) cout<<"Number of forced conjugate hors cont+nyq ="<1) cout<<"Check: ddl= "<H(zpk) * growth_->DsDz(zpk,good_dzinc_) / (*growth_)(zpk); if(lp_>0) cout<<"--- ToVelLoS --- at z="<(0.,k2); } } } } //------------------------------------------------------------------- void GeneFluct3D::ApplyGrowthFactor(int type_evol) // Apply Growth to real space // Using the correspondance between redshift and los comoving distance // describe in vector "zred_" "loscom_" // type_evol = 1 : evolution avec la distance a l'observateur // 2 : evolution avec la distance du plan Z // (tous les pixels d'un plan Z sont mis au meme redshift z que celui du milieu) { if(lp_>0) cout<<"--- ApplyGrowthFactor: evol="<2) { const char *bla = "GeneFluct3D::ApplyGrowthFactor_Error: bad type_evol value"; cout<0) cout<<"--- ApplyDerGrowthFactor: evol="<2) { const char *bla = "GeneFluct3D::ApplyGrowthFactor_Error: bad type_evol value"; cout<H(zpk) * growth_->DsDz(zpk,good_dzinc_) / (*growth_)(zpk); InterpFunc interpinv(loscom2zred_min_,loscom2zred_max_,loscom2zred_); InterpFunc interdpd(zredmin_dpsd_,zredmax_dpsd_,dpsdfrzred_); for(long i=0;i0) cout<<"--- ComputeReal ---"<0) cout<<"--- ReComputeFourier ---"< v((r_8)NRtot_,0.); for(long i=0;i0) cout<<"--- ComputeSpectrum ---"<0) cout<<"--- ComputeSpectrum2D ---"<0) cout<<"--- ComputeSpectrum: sigma="< vfz(NCz_); if(pixcor) // kz = l*Dkz_ for(long l=0;l0.) herr.Add(k,pk/f); } } } herr.ToVariance(); for(int i=0;i0) cout<<"--- ComputeSpectrum2D: sigma="< vfz(NCz_); if(pixcor) // kz = l*Dkz_ for(long l=0;l0.) herr.Add(kt,kz,pk/f); } } } herr.ToVariance(); for(int i=0;i)^2>/^2 // ou M = masse dans sphere de rayon R // --- ATTENTION: la variance calculee a une tres grande dispersion // (surtout si le volume du cube est petit). Pour verifier // que le sigmaR calcule par cette methode est en accord avec // le sigmaR en input, il faut faire plusieurs simulations (~100) // et regarder la moyenne des sigmaR reconstruits { if(lp_>0) cout<<"--- VarianceFrReal R="<0) cout<<"dnx="<="<="<)^2>="</^2 if(lp_>0) cout<<"...sigmaR^2 = <(M-)^2>/^2 = "< sigmaR = "< vmin and vmax are considered as bad { check_array_alloc(); int_8 nbad = 0; for(long i=0;i=vmax) nbad++; } if(lp_>0) cout<<"--- NumberOfBad "<=vmax)) continue; if(xxmax) xmax = x; n++; } if(lp_>0) cout<<" n="<vmin)? true: false; if(lp_>0) { cout<<"--- MeanSigma2"; if(tstval) cout<<" range=]"< vmin and vmax are set to val0 { check_array_alloc(); int_8 nbad = 0; for(long i=0;i=vmax) {data_[ip] = val0; nbad++;} } if(lp_>0) cout<<"--- SetToVal "<0) cout<<"--- ScaleCube scale="<0) cout<<"--- TurnFluct2MeanNumber : "<2) { sumall /= (double)nball; sumall2 = sumall2/(double)nball - sumall*sumall; if(lp_>0) cout<<"1+dRho/Rho: mean="< "<0.) {nbpos++; sumpos += v; sumpos2 += v*v;} } if(nbpos<1) { cout<<"TurnFluct2MeanNumber_Error: nbpos<1"<0) cout<<"1+dRho/Rho with v<0 set to zero: mean="< "<0) = "<0)="<0. // - Mise a zero des pixels <0 double dn = val_by_mpc3 * Vol_ / sumpos; if(lp_>0) cout<<"...density move from " <0) cout<<"...quantity put into survey "< let it as it is { if(lp_>0) cout<<"--- ApplyPoisson ---"<0.) { uint_8 dn = PoissonRand(v,10.); data_[ip] = (double)dn; sum += (double)dn; } } if(lp_>0) cout< let it as it is // INPUT: // massdist : distribution de masse (m*dn/dm) // axeslog = false : retourne la masse // = true : retourne le log10(mass) // RETURN la masse totale { if(lp_>0) cout<<"--- TurnNGal2Mass ---"<0.) { long ngal = long(v+0.1); data_[ip] = 0.; for(long i=0;i0) cout<0) cout<<"--- TurnNGal2MassQuick ---"<0.) { long ngal = long(v+0.1); data_[ip] = schmdist.TirMass(ngal); sum += data_[ip]; } } if(lp_>0) cout<0) cout<<"--- AddNoise2Real: snoise = "< correction; InterpFunc *intercor = NULL; if(type_evol>0) { // Sigma_Noise(en mass) : // Slim ~ 1/sqrt(DNu) * sqrt(nlobe) en W/m^2Hz // Flim ~ sqrt(DNu) * sqrt(nlobe) en W/m^2 // Mlim ~ sqrt(DNu) * (Dlum)^2 * sqrt(nlobe) en Msol // nlobe ~ 1/Dtrcom^2 // Mlim ~ sqrt(DNu) * (Dlum)^2 / Dtrcom if(cosmo_ == NULL || redsh_ref_<0. || loscom2zred_.size()<1) { const char *bla = "GeneFluct3D::AddNoise2Real_Error: set Observator and Cosmology first"; cout<10)? nsz/10: 1); for(long i=0;iDtrcom(zred); // pour variation angle solide double dlum = cosmo_->Dlum(zred); // pour variation conversion mass HI double dred = Dz_/(cosmo_->Dhubble()/cosmo_->E(zred)); double dnu = Fr_HyperFin_Par *dred/pow(1.+zred,2.); // pour variation dNu double corr = sqrt(dnu/dnu_ref_) * pow(dlum/dlum_ref_,2.) * dtrc_ref_/dtrc; if(lp_>0 && (i==0 || i==nsz-1 || i%nszmod==0)) cout<<"i="< cor="<0) { double dz = DZcom(l); if(type_evol==1) dz = sqrt(dx2+dy2+dz*dz); else dz = fabs(dz); // tous les plans Z au meme redshift corr = (*intercor)(dz); if(corrcorrlim[1]) corrlim[1]=corr; } int_8 ip = IndexR(i,j,l); data_[ip] += snoise*corr*NorRand(); } } } if(type_evol>0) cout<<"correction factor range: ["< cmvtstagn.ppf // 3. regarder l'histo "hlfang" et en deduire un equivalent gaussienne // cad une moyenne et un sigma "sig" // Attention: la distribution n'est pas gaussienne les "mean,sigma" // de l'histo ne sont pas vraiment ce que l'on veut // --- Limitations actuelle du code: // . les AGN sont supposes evoluer avec la meme loi de puissance pour tout theta,phi // . le flux des AGN est mis dans une colonne Oz (indice k) et pas sur la ligne de visee // . la distribution est approximee a une gaussienne // ... C'est une approximation pour un observateur loin du centre du cube // et pour un cube peu epais / distance observateur // --- Parametres de la routine: // llfy : c'est le du flux depose par les AGN // dans l'angle solide du pixel elementaire de reference du cube // lsigma : c'est le sigma de la distribution des log10(S) // powlaw : c'est la pente de la distribution cad que le flux "lmsol" // et considere comme le flux a 1.4GHz et qu'on suppose une loi // F(nu) = (1.4GHz/nu)^powlaw * F(1.4GHz) // - Comme on est en echelle log10(): // on tire log10(Msol) + X // ou X est une realisation sur une gaussienne de variance "sig^2" // La masse realisee est donc: Msol*10^X // - Pas de probleme de pixel negatif car on a une multiplication! { if(lp_>0) cout<<"--- AddAGN: = "<0) cout<<"Au pixel de ref: fagnref="<0) cout<<" powlaw="< change magnref to "< correction; InterpFunc interpinv(loscom2zred_min_,loscom2zred_max_,loscom2zred_); long nzmod = ((Nz_>10)?Nz_/10:1); for(long l=0;lDtrcom(zred); // pour variation angle solide double dlum = cosmo_->Dlum(zred); // pour variation conversion mass HI double dred = Dz_/(cosmo_->Dhubble()/cosmo_->E(zred)); double dnu = Fr_HyperFin_Par *dred/pow(1.+zred,2.); // pour variation dNu // on a: Mass ~ DNu * Dlum^2 / Dtrcom^2 double corr = dnu/dnu_ref_*pow(dtrc_ref_/dtrc*dlum/dlum_ref_,2.); // F(nu) = F(1.4GHz)*(nu GHz/1.4 Ghz)^p = F(1.4GHz)*(1/(1+z))^p , car nu = 1.4 GHz/(1+z) if(powlaw!=0.) corr *= pow((1.+redsh_ref_)/(1.+zred),powlaw); correction.push_back(corr); if(lp_>0 && (l==0 || l==Nz_-1 || l%nzmod==0)) { cout<<"l="< cor="<0 && nsum>1.) { sum /= nsum; sum2 = sum2/nsum - sum*sum; cout<<"...Mean mass="<