38 constexpr FTYPE_t
MPL = (FTYPE_t)1;
45 constexpr FTYPE_t
c_kms = (FTYPE_t)299792.458;
92 const size_t N_tot = grid.
get_Ntot();
93 const size_t N = grid.
get_N();
95 if (mesh.
N != N)
throw std::range_error(
"Mesh of a different size than Grid!");
97 #pragma omp parallel for private(ix, iy, iz) 98 for (
size_t i = 0; i < N_tot; ++i)
103 grid[i] = mesh(ix, iy, iz);
118 const size_t N_tot = grid.
get_Ntot();
119 const size_t N = grid.
get_N();
121 if (mesh.
N != N)
throw std::range_error(
"Mesh of a different size than Grid!");
123 #pragma omp parallel for private(ix, iy, iz) 124 for (
size_t i = 0; i < N_tot; ++i)
129 mesh(ix, iy, iz) = grid[i];
140 T min(
const std::vector<T>& data){
return *std::min_element(data.begin(), data.end()); }
168 size_t m_conv_stop = 0;
184 MultiGridSolver<3,
T>(N, Nmin, verbose), n(sim.chi_opt.n), beta(sim.chi_opt.beta), chi_0(2*beta*MPL*sim.chi_opt.phi),
191 phi_prefactor*
pow(sim.box_opt.box_size ,2) / sim.chi_opt.phi
193 fix_vals(this->get_Nlevel())
195 if ((n <= 0) || (n >= 1) || (chi_0 <= 0))
throw std::out_of_range(
"invalid values of chameleon power-law potential parameters");
202 return chi_0*
pow(a, 3/(1-n));
207 return beta/MPL*chi_a(a)/phi_prefactor;
213 const size_t N = rho_k.
N;
214 const size_t l_half = rho_k.
length/2;
215 const T mass_sq = (1-n)*chi_prefactor/
pow(2*
PI, 2);
216 const T chi_a_n = -1/(1-n);
220 #pragma omp parallel for private(k2, g_k) 221 for(
size_t i=0; i < l_half;i++){
230 g_k = chi_a_n/(k2+mass_sq)*mass_sq;
237 bool check_surr_dens(
T const*
const rho_grid, std::vector<size_t> index_list,
size_t i,
size_t N)
240 if (rho_grid[i] <= 0)
return false;
244 for(
size_t i_s : index_list)
if (rho_grid[i_s] > rho_grid[i])
return false;
252 chi_prefactor = chi_prefactor_0*
pow(a, -3.*(2.-n)/(1.-n));
258 T l_operator(
const T chi_i,
const size_t level,
const std::vector<size_t>& index_list,
const bool addsource,
const T h)
const 261 const size_t i = index_list[0];
262 T const*
const chi = this->get_y(level);
263 const T rho = this->get_external_field(level, 0)[i];
266 if (rho == MARK_CHI_BOUND_COND)
return 0;
269 T source = (1 + rho -
pow(chi_i - CHI_MIN, n - 1)) * chi_prefactor;
272 T kinetic = -2*chi_i*3;
274 for(
auto it = index_list.begin() + 1; it < index_list.end(); ++it) kinetic += chi[*it];
277 if( level > 0 && addsource ) source += this->get_multigrid_source(level, i);
280 return kinetic/(h*
h) - source;
283 T l_operator(
const size_t level,
const std::vector<size_t>& index_list,
const bool addsource,
const T h)
const override 286 const size_t i = index_list[0];
287 T const*
const chi = this->get_y(level);
288 const T chi_i = chi[i];
289 return l_operator(chi_i, level, index_list, addsource, h);
293 T dl_operator(
const size_t level,
const std::vector<size_t>& index_list,
const T h)
const override 296 const T chi = this->get_y(level)[ index_list[0] ];
299 const T dsource = chi_prefactor*(1-n)*
pow(chi - CHI_MIN, n-2);
302 const T dkinetic = -2.0*3;
304 return dkinetic/(h*
h) - dsource;
316 const size_t i = index_list[0];
317 const T rho = this->get_external_field(level, 0)[i];
322 l2 = l_operator(f2, level, index_list,
true, h);
323 if (l1*l2 <= 0)
return true;
330 return ((std::abs(l_new) < m_l_stop) || (std::abs(df_new) < m_dchi_stop));
333 T bisection_step(
T& f1,
T& l1,
T& f2,
T& l2,
const size_t level,
const std::vector<size_t>& index_list,
const T h)
const 339 const T f_new = (f1 + f2) / 2;
340 const T l_new = l_operator(f_new, level, index_list,
true, h);
342 if (check_bisection_convergence(f2 - f_new, l_new))
return f_new;
356 T bisection(
T f1,
T l1,
const T df,
const size_t level,
const std::vector<size_t>& index_list,
const T h)
const 361 if (!find_opposite_l_sign(f1, l1, df, f2, l2, level, index_list, h))
return f2;
364 for (
size_t i = 0; i < m_max_bisection_steps; ++i){
365 f_new = bisection_step(f1, l1, f2, l2, level, index_list, h);
366 if (f_new != CHI_MIN)
377 T upd_operator(
const T f,
const size_t level,
const std::vector<size_t>& index_list,
const T h)
const override 381 T l = l_operator(level, index_list,
true, h);
382 T dl = dl_operator(level, index_list, h);
384 T df_rel = std::abs(df/(f - CHI_MIN));
386 static_assert((SWITCH_BIS_NEW < 1),
"Newton`s method cannot be allowed with negative values. Adjust 'SWITCH_BIS_NEW < 1'.");
388 return df_rel < SWITCH_BIS_NEW ? f + df : bisection(f, l, df / 2, level, index_list, h);
396 const T *
const rho = this->get_external_field(level, 0);
399 const size_t N = this->get_N(level);
400 const T h = 1.0/
T( N );
401 std::vector<size_t> index_list;
403 #pragma omp parallel for private(index_list) 404 for(
size_t i = 0; i < Ntot; i++)
407 if (rho[i] == MARK_CHI_BOUND_COND)
continue;
408 else if (std::abs(corr[i]/(f[i] - CHI_MIN)) < SWITCH_BIS_NEW) f[i] += corr[i];
411 T l = l_operator(level, index_list,
true, h);
412 f[i] = bisection(f[i], l, corr[i] / 2, level, index_list, h);
425 const double _rms_res_i = this->_rms_res_i;
426 const double _rms_res = this->_rms_res;
427 const double _rms_res_old = this->_rms_res_old;
428 const double _verbose = this->_verbose;
429 const double _istep_vcycle = this->_istep_vcycle;
430 const double _eps_converge = this->_eps_converge;
431 const double _maxsteps = this->_maxsteps;
434 const double err = _rms_res_old != 0.0 ? _rms_res/_rms_res_old : 0.0;
435 ES converged = ES::ITERATE;
438 bool res_below_optimal_tresh = (_rms_res < _eps_converge) || (_eps_converge == 0.0);
439 bool res_below_minimal_tresh = (_rms_res < m_rms_stop_min) || (m_rms_stop_min == 0.0);
440 bool fast_convergence = err < m_err_stop_min;
441 bool slow_convergence = err > m_err_stop;
442 bool worse_solution = err > 1;
443 bool over_max_steps = _istep_vcycle >= _maxsteps;
446 auto print_success = [=](
size_t m_conv_stop){
447 BOOST_LOG_TRIVIAL(debug) <<
"\n\tSUCCESS: res = " << _rms_res <<
", err = " << err <<
", num_err = " << m_conv_stop <<
" (istep = " << _istep_vcycle <<
")";
449 auto print_failure = [=](
size_t m_conv_stop){
450 BOOST_LOG_TRIVIAL(debug) <<
"\tFAILURE: res = " << _rms_res <<
", err = " << err <<
", num_err = " << m_conv_stop <<
" (istep = " << _istep_vcycle <<
")";
453 auto print_iterate = [=](
size_t m_conv_stop){
454 BOOST_LOG_TRIVIAL(debug) <<
"\tITERATE: res = " << _rms_res <<
", err = " << err <<
", num_err = " << m_conv_stop <<
" (istep = " << _istep_vcycle <<
")";
459 BOOST_LOG_TRIVIAL(debug) <<
" Checking for convergence at step = " << _istep_vcycle;
460 BOOST_LOG_TRIVIAL(debug) <<
" Residual = " << _rms_res <<
" Residual_old = " << _rms_res_old;
461 BOOST_LOG_TRIVIAL(debug) <<
" Residual_i = " << _rms_res_i <<
" Err = " << err;
465 if (res_below_optimal_tresh && !fast_convergence){
466 print_success(m_conv_stop);
467 converged = ES::SUCCESS;
469 else if (worse_solution)
471 if(_verbose) print_failure(m_conv_stop);
473 converged = ES::ITERATE;
475 else if (slow_convergence)
477 if (res_below_minimal_tresh)
479 print_success(m_conv_stop);
480 converged = ES::SLOW;
485 if (m_conv_stop >= m_num_fail)
487 print_failure(m_conv_stop);
488 converged = ES::FAILURE;
492 if(_verbose) print_iterate(m_conv_stop);
493 converged = ES::ITERATE;
499 if (m_conv_stop >= m_num_fail)
501 print_failure(m_conv_stop);
502 converged = ES::FAILURE;
506 if(_verbose) print_iterate(m_conv_stop);
507 converged = ES::ITERATE;
513 print_failure(m_conv_stop);
514 converged = ES::MAX_STEPS;
517 if (converged != ES::ITERATE)
526 for (
auto fv : fix_vals[level]) chi[fv.first] = fv.second;
529 void set_convergence(
double eps,
double err_stop,
double err_stop_min,
double rms_stop_min,
size_t num_fail)
531 this->set_epsilon(eps);
532 m_err_stop = err_stop;
533 m_err_stop_min = err_stop_min;
534 m_rms_stop_min = rms_stop_min;
535 m_num_fail = num_fail;
540 m_max_bisection_steps = max_bi_step;
541 m_dchi_stop = dchi_stop;
547 const double err_mod = get_chi_prefactor();
548 set_convergence(err_mod*CONVERGENCE_RES, CONVERGENCE_ERR, CONVERGENCE_ERR_MIN, err_mod*CONVERGENCE_RES_MIN, CONVERGENCE_NUM_FAIL);
549 set_bisection_convergence(CONVERGENCE_BI_STEPS_INIT, CONVERGENCE_BI_DCHI, CONVERGENCE_BI_L);
555 if (!chi_prefactor)
throw std::out_of_range(
"invalid value of scale factor");
556 if (!this->get_external_field_size())
throw std::out_of_range(
"overdensity not set");
557 BOOST_LOG_TRIVIAL(debug) <<
"Setting initial guess for chameleon field...";
559 T*
const f = this->get_y();
560 T const*
const rho = this->get_external_field(0, 0);
561 const size_t N_tot = this->get_Ntot();
563 #pragma omp parallel for 564 for (
size_t i = 0; i < N_tot; ++i)
566 f[i] = chi_min(rho[i]);
573 if (this->get_N(level) != rho.
N)
throw std::range_error(
"Mesh of a different size than Grid at current level!");
594 if (level >= this->get_Nlevel())
return;
597 const size_t N = this->get_N(level);
608 set_linear_sol_at_level(rho, p_F, p_B, level);
611 set_linear_recursively(level + 1);
618 set_linear_sol_at_level(rho, p_F, p_B, 0);
621 set_linear_recursively(1);
626 if (level >= this->get_Nlevel())
return;
629 const size_t N_tot = this->get_Ntot(level);
630 const size_t N = this->get_N(level);
631 T*
const rho_grid = this->get_external_field(level, 0);
632 std::vector<size_t> index_list;
634 #pragma omp parallel for private(index_list) 635 for (
size_t i = 0; i < N_tot; ++i)
637 if (chi[i] <= CHI_MIN)
639 if (check_surr_dens(rho_grid, index_list, i, N)) chi[i] =
CHI_MIN;
640 else chi[i] = rho_grid[i] > 0 ? chi_min(rho_grid[i]) : 1/2. +
CHI_MIN;
644 fix_vals[level].clear();
647 for (
size_t i = 0; i < N_tot; ++i)
649 if (chi[i] == CHI_MIN)
652 chi[i] = chi_min(rho_grid[i]);
654 fix_vals[level].emplace(i, chi[i]);
658 size_t num_high_density = fix_vals[level].size();
659 BOOST_LOG_TRIVIAL(debug) <<
"Identified and fixed " << num_high_density <<
"(" << std::setprecision(2) << num_high_density*100.0/N_tot <<
"%) points at level " << level;
661 set_screened(level + 1);
667 else if (delta == -1)
return 1 +
CHI_MIN;
668 else throw std::range_error(
"invalid values of density: " + std::to_string(delta) +
" < -1)");
688 sol(sim.box_opt.mesh_num, sim, false), drho(sim.box_opt.mesh_num), N_level_orig(sol.get_Nlevel()), x_0(sim.x_0())
691 chi_force.reserve(3);
692 for(
size_t i = 0; i < 3; i++){
697 memory_alloc =
sizeof(FTYPE_t)*chi_force[0].length*chi_force.size();
698 memory_alloc +=
sizeof(
CHI_PREC_t)*8*(sol.get_Ntot()-1)/7
700 memory_alloc +=
sizeof(
CHI_PREC_t)*8*(sol.get_Ntot()-1)/7;
703 sol.add_external_grid(&drho);
708 ChiSolver<CHI_PREC_t>
sol;
717 sol.set_time(a, sim.
cosmo);
720 sol.set_def_convergence();
723 BOOST_LOG_TRIVIAL(debug) <<
"Storing density distribution...";
728 BOOST_LOG_TRIVIAL(debug) <<
"Setting linear guess for chameleon field...";
732 sol.set_linear_sol_at_level(chi_force[0], p_F, p_B, 0);
737 sol.set_linear(chi_force[0], p_F, p_B);
741 BOOST_LOG_TRIVIAL(debug) <<
"Solving equations of motion for chameleon field...";
765 const size_t Np = particles.size();
769 const FTYPE_t Om = cosmo.
Omega_m;
770 const FTYPE_t OLa = OL/(Om+OL);
773 const FTYPE_t f1 = 3/(2*a)*(1 + OLa);
774 const FTYPE_t f2 = 3/(2*a)*(1 - OLa)*D/a;
776 const FTYPE_t f3 = a/D*sol.chi_force_units(a)/
pow2(x_0);
778 #pragma omp parallel for private(force) 779 for (
size_t i = 0; i < Np; i++)
782 assign_from(force_field, particles[i].position, force);
783 assign_from(chi_force, particles[i].position, force, f3);
784 force = force*f2 - particles[i].velocity*f1;
785 particles[i].velocity += force*da;
791 const size_t Np = particles.size();
797 const FTYPE_t f3 = a/D*sol.chi_force_units(a)/
pow2(x_0);
799 #pragma omp parallel for private(vel) 800 for (
size_t i = 0; i < Np; i++)
803 assign_from(vel_field, particles[i].position, vel);
804 assign_from(chi_force, particles[i].position, vel, f3);
805 particles[i].velocity = vel*dDda;
815 sol.set_ngs_sweeps(3, 6);
816 sol.set_maxsteps(30);
817 ES status = sol.solve();
822 sol.set_ngs_sweeps(5, 0);
824 sol.set_maxsteps(30);
825 ES status = sol.solve();
826 sol.set_Nlevel(N_level_orig);
837 App_Var_Chi(sim,
"CHI",
"Chameleon gravity (FP)") {}
857 auto kick_step = [&]()
867 App_Var_Chi(sim,
"CHI_FF",
"Chameleon gravity (FF)") {}
871 auto kick_step = [&]()
double min(const MultiGrid< 3, T > &grid)
class containing core variables and methods for approximations
constexpr CHI_PREC_t CHI_MIN
minimum value of chameleon field, in chi_a units it is '0', in phi units it is '-1' ...
T dl_operator(const size_t level, const std::vector< size_t > &index_list, const T h) const override
Grid< NDIM, T > & get_grid(size_t level=0)
FFTW_COMPLEX_TYPE * complex()
get fftw_complex pointer to data
MultiGrid< 3, CHI_PREC_t > drho
void correct_sol(Grid< 3, T > &f, const Grid< 3, T > &corr, const size_t level) override
constexpr size_t CONVERGENCE_BI_STEPS_INIT
maximal number of steps inside bisection initialization method
void transform_MultiGridSolver_to_Mesh(Mesh &mesh, const MultiGridSolver< 3, T > &sol)
T l_operator(const T chi_i, const size_t level, const std::vector< size_t > &index_list, const bool addsource, const T h) const
void kick_step_w_chi_no_momentum(const Cosmo_Param &cosmo, const double a, const double da, std::vector< Particle_v< double >> &particles, const std::vector< Mesh > &vel_field)
void get_rho_from_par(const std::vector< T > &particles, Mesh &rho, const Sim_Param &sim)
functions handling output of the program
void set_screened(size_t level=0)
T get_phi_prefactor() const
void transform_MultiGrid_to_Mesh(Mesh &mesh, const MultiGrid< 3, T > &mltgrid)
double get_k_sq(size_t N, size_t index)
void stream_kick_stream(const double da, std::vector< Particle_v< double >> &particles, std::function< void()> kick_step, size_t per)
double CHI_PREC_t
accuracy of chameleon solver
class handling particles (position only)
handle cosmological functions like power spectrum, growth, etc.
constexpr double MPL
mass & chi in units of Planck mass
void set_linear_recursively(size_t level)
: class storing simulation parameters
bool check_bisection_convergence(const T df_new, const T l_new) const
void solve(double a, const std::vector< Particle_v< double >> &particles, const Sim_Param &sim, const FFTW_PLAN_TYPE &p_F, const FFTW_PLAN_TYPE &p_B)
void fftw_execute_dft_r2c(const FFTW_PLAN_TYPE &p_F, Mesh &rho)
compute forward (real to complex) FFT on mesh (inplace)
const T chi_prefactor_0
dimensionless prefactor to poisson equation at a = 1
size_t m_max_bisection_steps
T bisection(T f1, T l1, const T df, const size_t level, const std::vector< size_t > &index_list, const T h) const
: creates a mesh of N*N*(N+2) cells
void fftw_execute_dft_c2r_triple(const FFTW_PLAN_TYPE &p_B, std::vector< Mesh > &rho)
compute three backward (complex to real) FFTs on vector of meshes (inplace)
ChiSolver(size_t N, unsigned int Nmin, const Sim_Param &sim, bool verbose=true)
void print_pow_spec(const Data_Vec< double, 2 > &pwr_spec_binned, std::string out_dir, std::string suffix)
bool find_opposite_l_sign(const T f1, const T l1, T df, T &f2, T &l2, const size_t level, const std::vector< size_t > &index_list, const T h) const
void get_chi_k(Mesh &rho_k)
const T n
Hu-Sawicki paramater.
void transform_Grid_to_Mesh(Mesh &mesh, const Grid< 3, T > &grid)
void kick_step_w_chi(const Cosmo_Param &cosmo, const double a, const double da, std::vector< Particle_v< double >> &particles, const std::vector< Mesh > &force_field)
void set_time(T a, const Cosmo_Param &cosmo)
constexpr double CONVERGENCE_ERR_MIN
do not stop if solution is still improving
ES check_convergence() override
check if solution already converged
functions for integration of particle trajectories
void fftw_execute_dft_c2r(const FFTW_PLAN_TYPE &p_B, Mesh &rho)
compute backward (complex to real) FFT on mesh (inplace)
: class to solve chameleon equations of motion
void set_bisection_convergence(size_t max_bi_step, T dchi_stop, T l_stop)
const std::unique_ptr< ChiImpl > m_impl
void transform_Mesh_to_MultiGrid(const Mesh &mesh, MultiGrid< 3, T > &mltgrid)
std::vector< Mesh > app_field
Data_Vec< double, 2 > pwr_spec_binned
< end of anonymous namespace (private definitions)
const T beta
Chameleon coupling constant.
void gen_pow_spec_binned(const Sim_Param &sim, const Mesh &power_aux, Data_Vec< double, 2 > &pwr_spec_binned)
ChiSolver(size_t N, const Sim_Param &sim, bool verbose=true)
declaration in params.hpp
cosmological & CCL parameters
constexpr size_t CONVERGENCE_NUM_FAIL
stop when number of failed steps is over
std::string get_z_suffix() const
const std::vector< T > & get_vec() const
T l_operator(const size_t level, const std::vector< size_t > &index_list, const bool addsource, const T h) const override
T get_chi_prefactor() const
T upd_operator(const T f, const size_t level, const std::vector< size_t > &index_list, const T h) const override
interface for common functions for all types of approximations
void get_neighbor_gridindex(std::vector< size_t > &index_list, size_t i, size_t N)
constexpr CHI_PREC_t MARK_CHI_BOUND_COND
unphysical value of overdensity (< -1) used to indicate that chameleon filed at this point should not...
std::vector< Mesh > chi_force
std::string get_out_dir() const
void set_convergence(double eps, double err_stop, double err_stop_min, double rms_stop_min, size_t num_fail)
constexpr size_t CONVERGENCE_BI_STEPS
maximal number of steps inside bisection rootfindg method
constexpr double CONVERGENCE_RES
stop when total (rms) residual below
ChiSolver< CHI_PREC_t > sol
App_Var_Chi_FF(const Sim_Param &sim)
constexpr double CONVERGENCE_ERR
stop when improvements between steps slow below
constexpr CHI_PREC_t CONVERGENCE_BI_L
stop bisection method when residual below
various simulation parameters
std::vector< Particle_v< double > > particles
std::vector< std::map< size_t, T > > fix_vals
<index, value>
void set_linear_sol_at_level(Mesh &rho, const FFTW_PLAN_TYPE &p_F, const FFTW_PLAN_TYPE &p_B, size_t level)
constexpr CHI_PREC_t SWITCH_BIS_NEW
when the relative change in solution is less than this, use Newton`s method. Bisection method otherwi...
const T chi_0
2*beta*Mpl*phi_scr
T bisection_step(T &f1, T &l1, T &f2, T &l2, const size_t level, const std::vector< size_t > &index_list, const T h) const
bool check_surr_dens(T const *const rho_grid, std::vector< size_t > index_list, size_t i, size_t N)
basic functions to work with mesh
constexpr double c_kms
speed of light [km / s]
void print_output() override
const T phi_prefactor
prefactor for Poisson equation for gravitational potential
float pow(float base, unsigned long int exp)
void pwr_spec_k_init(const Mesh &rho_k, Mesh &power_aux)
App_Var_Chi(const Sim_Param &sim)
constexpr CHI_PREC_t CONVERGENCE_BI_DCHI
stop bisection method when chi doesn`t chanege
T chi_prefactor
time-dependent prefactor
void check_solution(size_t level, Grid< 3, T > &chi) override
ChiImpl(const Sim_Param &sim)
Grid< NDIM, T > & get_grid(size_t level=0)
void transform_Mesh_to_Grid(const Mesh &mesh, Grid< 3, T > &grid)
void get_chi_force(const FFTW_PLAN_TYPE &p_F, const FFTW_PLAN_TYPE &p_B)
MultiGridSolver< 3, CHI_PREC_t >::Exit_Status ES
acces Exit_Status namespace
void gen_displ_k_cic(std::vector< Mesh > &vel_field, const Mesh &pot_k)
void set_def_convergence()
constexpr double CONVERGENCE_RES_MIN
do not stop if solution didn`t converge below
void assign_from(const Mesh &field, const Vec_3D< double > &position, double &value, double mod)
T chi_force_units(T a) const
void gen_pow_spec_binned(const Sim_Param &sim, Data_Vec< double, 2 > &pwr_spec_binned, const FFTW_PLAN_TYPE &p_F)
chameleon model of gravity interface
void set_linear(Mesh &rho, const FFTW_PLAN_TYPE &p_F, const FFTW_PLAN_TYPE &p_B)
const size_t N_level_orig
double growth_change(double a, const Cosmo_Param &cosmo)