// This file is part of monofonIC (MUSIC2) // A software package to generate ICs for cosmological simulations // Copyright (C) 2024 by Oliver Hahn // // monofonIC is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // monofonIC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "constraints.hh" double dsigma2_tophat( double k, void *params ); double dsigma2_gauss( double k, void *params ); double find_coll_z( const std::vector& z, const std::vector& sigma, double nu ); void compute_sigma_tophat( config_file& cf, transfer_function *ptf, double R, std::vector& z, std::vector& sigma ); void compute_sigma_gauss( config_file& cf, transfer_function *ptf, double R, std::vector& z, std::vector& sigma ); double dsigma2_tophat( double k, void *pparams ) { if( k<=0.0 ) return 0.0; char **params = reinterpret_cast (pparams); transfer_function *ptf = reinterpret_cast(params[0]); double x = k * *reinterpret_cast(params[1]); double nspect = *reinterpret_cast(params[2]); double w = 3.0*(sin(x)-x*cos(x))/(x*x*x); double tfk = ptf->compute(k,delta_matter); return k*k * w*w * pow(k,nspect) * tfk*tfk; } double dsigma2_gauss( double k, void *pparams ) { if( k<=0.0 ) return 0.0; char **params = reinterpret_cast (pparams); transfer_function *ptf = reinterpret_cast (params[0]); double x = k * *reinterpret_cast(params[1]); double nspect = *reinterpret_cast(params[2]); double w = exp(-x*x*0.5); double tfk = ptf->compute(k,delta_matter); return k*k * w*w * pow(k,nspect) * tfk*tfk; } double find_coll_z( const std::vector& z, const std::vector& sigma, double nu ) { double dcoll = 1.686/nu; double zcoll = 0.0; gsl_interp_accel *acc = gsl_interp_accel_alloc (); gsl_spline *spline = gsl_spline_alloc (gsl_interp_cspline, z.size()); gsl_spline_init (spline, &sigma[0], &z[0], z.size() ); zcoll = gsl_spline_eval(spline, dcoll, acc ); gsl_spline_free (spline); gsl_interp_accel_free (acc); return zcoll; } void compute_sigma_tophat( config_file& cf, transfer_function *ptf, double R, std::vector& z, std::vector& sigma ) { z.clear(); sigma.clear(); cosmology::parameters cosm( cf ); cosmology::calculator ccalc( cf ); double zmin = 0.0, zmax = 200.0; int nz = 100; for( int i=0; i ("cosmology","sigma_8"); double nspec = cf.get_value("cosmology","nspec"); double sigma0 = 0.0; { double eight=8.0; char *params[3]; params[0] = reinterpret_cast (ptf); params[1] = reinterpret_cast (&eight); params[2] = reinterpret_cast (&nspec); sigma0 = sqrt(4.0*M_PI*integrate( &dsigma2_tophat, 1e-4, 1e4, reinterpret_cast(params) )); } for( int i=0; i (ptf); params[1] = reinterpret_cast (&R); params[2] = reinterpret_cast (&nspec); double sig = sqrt(4.0*M_PI*integrate( &dsigma2_tophat, 1e-4, 1e4, reinterpret_cast(params) )); double Dz = ccalc.get_growth_factor(1./(1.+z[i])); sigma.push_back( sig*sigma8/sigma0*Dz/D0 ); } } void compute_sigma_gauss( config_file& cf, transfer_function *ptf, double R, std::vector& z, std::vector& sigma ) { z.clear(); sigma.clear(); cosmology::parameters cosm( cf ); cosmology::calculator ccalc( cf ); double zmin = 0.0, zmax = 200.0; int nz = 100; for( int i=0; i ("cosmology","sigma_8"); double nspec = cf.get_value("cosmology","nspec"); double sigma0 = 0.0; { double eight=8.0; char *params[3]; params[0] = reinterpret_cast (ptf); params[1] = reinterpret_cast (&eight); params[2] = reinterpret_cast (&nspec); sigma0 = sqrt(4.0*M_PI*integrate( &dsigma2_tophat, 1e-4, 1e4, reinterpret_cast(params) )); } for( int i=0; i (ptf); params[1] = reinterpret_cast (&R); params[2] = reinterpret_cast (&nspec); double sig = sqrt(4.0*M_PI*integrate( &dsigma2_gauss, 1e-4, 1e4, reinterpret_cast(params) )); double Dz = ccalc.get_growth_factor(1./(1.+z[i])); //std::cerr << z[i] << " " << sig << std::endl; sigma.push_back( sig*sigma8/sigma0*Dz/D0 ); } } constraint_set::constraint_set( config_file& cf, transfer_function *ptf ) : pcf_( &cf ), ptf_( ptf ) { pcosmo_ = new cosmology::parameters( cf ); pccalc_ = new cosmology::calculator( cf ); dplus0_ = 1.0;//pccalc_->CalcGrowthFactor( 1.0 ); unsigned i=0; double astart = 1.0/(1.0+pcf_->get_value("setup","zstart")); unsigned levelmin = pcf_->get_value("setup","levelmin"); unsigned levelmin_TF = pcf_->get_value_safe("setup","levelmin_TF",levelmin); constr_level_ = pcf_->get_value_safe("constraints","level",levelmin_TF); constr_level_ = std::max(constr_level_,levelmin_TF); double omegam = pcf_->get_value("cosmology","Omega_m"); double rhom = omegam*2.77519737e11; //... mean matter density in Msun/Mpc^3 //... use EdS density for estimation //double rhom = 2.77519737e11; std::map< std::string, constr_type> constr_type_map; constr_type_map.insert( std::pair("halo",halo) ); constr_type_map.insert( std::pair("peak",peak) ); while(true) { char temp1[128]; std::string temp2; snprintf(temp1,128,"constraint[%u].type",i); if( cf.contains_key( "constraints", temp1 ) ) { std::string str_type = cf.get_value( "constraints", temp1 ); if( constr_type_map.find(str_type) == constr_type_map.end() ) throw std::runtime_error("Unknown constraint type!\n"); //... parse a new constraint constraint new_c; new_c.type = constr_type_map[ str_type ]; //... read position of constraint snprintf(temp1,128,"constraint[%u].pos",i); temp2 = cf.get_value( "constraints", temp1 ); sscanf(temp2.c_str(), "%lf,%lf,%lf", &new_c.x, &new_c.y, &new_c.z); if( new_c.type == halo) { //.. halo type constraints take mass and collapse redshift snprintf(temp1,128,"constraint[%u].mass",i); double mass = cf.get_value( "constraints", temp1 ); snprintf(temp1,128,"constraint[%u].zform",i); double zcoll = cf.get_value( "constraints", temp1 ); new_c.Rg = pow((mass/pow(2.*M_PI,1.5)/rhom),1./3.); new_c.sigma = 1.686/(pccalc_->get_growth_factor(1./(1.+zcoll))/pccalc_->get_growth_factor(1.0)); music::ilog.Print("sigma of constraint : %g", new_c.sigma ); new_c.sigma *=pccalc_->get_growth_factor(astart)/pccalc_->get_growth_factor(1.0); music::ilog.Print("Constraint %d : halo with %g h-1 M_o",i,pow(2.*M_PI,1.5)*rhom*pow(new_c.Rg,3)); } else if( new_c.type == peak ) { //... peak type constraints take a scale and a peak height //snprintf(temp1,128,"constraint[%u].Rg",i); //new_c.Rg = cf.get_value( "constraints", temp1 ); //double mass = pow(new_c.Rg,3.0)*rhom*pow(2.*M_PI,1.5); snprintf(temp1,128,"constraint[%u].mass",i); double mass = cf.get_value( "constraints", temp1 ); new_c.Rg = pow((mass/pow(2.*M_PI,1.5)/rhom),1./3.); double Rtophat = pow(mass/4.0*3.0/M_PI/rhom,1./3.); snprintf(temp1,128,"constraint[%u].nu",i); double nu = cf.get_value( "constraints", temp1 ); std::vector z,sigma; compute_sigma_tophat( cf, ptf, Rtophat, z, sigma ); double zcoll = find_coll_z( z, sigma, nu ); //music::ilog.Print("Probable collapse redshift for constraint %d : z = %f @ M = %g", i, zcoll,mass ); compute_sigma_gauss( cf, ptf, new_c.Rg, z, sigma ); new_c.sigma = nu*sigma.back(); //music::ilog.Print("Constraint %d : peak with Rg=%g h-1 Mpc and nu = %g",i,new_c.Rg,new_c.sigma); music::ilog.Print("Constraint %3d : peak",i); music::ilog.Print(" M = %g h-1 M_o, nu = %.2f sigma", mass, nu ); music::ilog.Print(" estimated z_coll = %f, sigma = %f", zcoll, new_c.sigma ); } new_c.Rg2 = new_c.Rg*new_c.Rg; cset_.push_back( new_c ); }else break; ++i; } music::ilog.Print("Found %d density constraint(s) to be obeyed.",cset_.size()); } void constraint_set::wnoise_constr_corr( double dx, size_t nx, size_t ny, size_t nz, std::vector& g0, matrix& cinv, complex_t* cw ) { double lsub = nx*dx; double dk = 2.0*M_PI/lsub, d3k=dk*dk*dk; double pnorm = pcf_->get_value("cosmology","pnorm"); double nspec = pcf_->get_value("cosmology","nspec"); pnorm *= dplus0_*dplus0_; size_t nconstr = cset_.size(); size_t nzp=nz/2+1; /*for( size_t i=0; i sigma(nconstr,0.0); #pragma omp parallel { std::vector sigma_loc(nconstr,0.0); #pragma omp for for( int ix=0; ix<(int)nx; ++ix ) { double iix(ix); if( iix > nx/2 ) iix-=nx; iix *= 2.0*M_PI/nx; for( size_t iy=0; iy ny/2 ) iiy-=ny; iiy *= 2.0*M_PI/nx; for( size_t iz=0; izcompute(k,delta_matter); double Pk = pnorm*T*T*pow(k,nspec)*d3k; size_t q = ((size_t)ix*ny+(size_t)iy)*nzp+(size_t)iz; double fac = sqrt(Pk); for( unsigned i=0; i ci = eval_constr(i,iix,iiy,iiz), cj = eval_constr(j,iix,iiy,iiz); RE(cw[q]) += (cset_[j].sigma-g0[j])*cinv(i,j) * std::real(ci)*fac; IM(cw[q]) += (cset_[j].sigma-g0[j])*cinv(i,j) * std::imag(ci)*fac; if( i!=j ) { RE(cw[q]) += (cset_[i].sigma-g0[i])*cinv(j,i) * std::real(cj)*fac; IM(cw[q]) += (cset_[i].sigma-g0[i])*cinv(j,i) * std::imag(cj)*fac; } else { if( iz>0&&iz(RE(cw[q]),IM(cw[q])))*fac; else sigma_loc[i] += std::real(std::conj(ci)*std::complex(RE(cw[q]),IM(cw[q])))*fac; } } } } } //.. 'critical' section for the global reduction #pragma omp critical { for(int i=0; i<(int)nconstr; ++i ) sigma[i] += sigma_loc[i]; } } for(int i=0; i<(int)nconstr; ++i ) music::ilog.Print("Constraint %3d : sigma = %+6f (%+6f)",i,sigma[i],cset_[i].sigma); } void constraint_set::wnoise_constr_corr( double dx, complex_t* cw, size_t nx, size_t ny, size_t nz, std::vector& g0 ) { size_t nconstr = cset_.size(); size_t nzp=nz/2+1; g0.assign(nconstr,0.0); double pnorm = pcf_->get_value("cosmology","pnorm"); double nspec = pcf_->get_value("cosmology","nspec"); pnorm *= dplus0_*dplus0_; double lsub = nx*dx; double dk = 2.0*M_PI/lsub, d3k=dk*dk*dk; for( size_t i=0; i nx/2 ) iix-=nx; iix *= 2.0*M_PI/nx; for( size_t iy=0; iy ny/2 ) iiy-=ny; iiy *= 2.0*M_PI/nx; for( size_t iz=0; izcompute(k,delta_matter); std::complex v(std::conj(eval_constr(i,iix,iiy,iiz))); v *= sqrt(pnorm*pow(k,nspec)*T*T*d3k); if( iz>0&&iz ccw(RE(cw[q]),IM(cw[q])); gg += std::real(v*ccw); } } } g0[i] = gg; } } void constraint_set::icov_constr( double dx, size_t nx, size_t ny, size_t nz, matrix& cij ) { size_t nconstr = cset_.size(); size_t nzp=nz/2+1; double pnorm = pcf_->get_value("cosmology","pnorm"); double nspec = pcf_->get_value("cosmology","nspec"); pnorm *= dplus0_*dplus0_; cij = matrix(nconstr,nconstr); double lsub = nx*dx; double dk = 2.0*M_PI/lsub, d3k=dk*dk*dk; //... compute lower triangle of covariance matrix //... and fill in upper triangle for( unsigned i=0; i nx/2 ) iix-=nx; iix *= 2.0*M_PI/nx; for( size_t iy=0; iy ny/2 ) iiy-=ny; iiy *= 2.0*M_PI/nx; for( size_t iz=0; izcompute(k,delta_matter); std::complex v(std::conj(eval_constr(i,iix,iiy,iiz))); v *= eval_constr(j,iix,iiy,iiz); v *= pnorm * pow(k,nspec) * T * T * d3k; if( iz>0&&iz