Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
test_chameleon.cpp
Go to the documentation of this file.
1 #include <catch.hpp>
2 #include "../test.hpp"
3 #include "chameleon.cpp"
4 
5 namespace{
6 
7 template<typename T>
8 T mean(const std::vector<T>& data)
9 {
10  T tmp(0);
11 
12  #pragma omp parallel for reduction(+:tmp)
13  for (auto it = data.begin(); it < data.end(); ++it) tmp += *it;
14 
15  return tmp / data.size();
16 }
17 
18 FTYPE_t mean(const Mesh& data){ return mean(data.data); }
19 
20 void get_neighbor_gridindex(std::vector<size_t>& index_list, size_t i, size_t N)
21 {
22  index_list = std::vector<size_t>(7);
23  index_list[0] = i;
24  for(size_t j = 0, n = 1; j < 3; j++, n *= N){
25  size_t ii = i/n % N;
26  size_t iminus = ii >= 1 ? ii - 1 : N - 1;
27  size_t iplus = ii <= N-2 ? ii + 1 : 0;
28  index_list[2*j+1] = i + (iminus - ii) * n;
29  index_list[2*j+2] = i + (iplus - ii) * n;
30  }
31 }
32 
34 {
35  const size_t N = sim.test_opt.N_grid;
36  const FTYPE_t R = sim.test_opt.R_sphere;
37  const FTYPE_t rho_0 = sim.test_opt.rho_sphere;
38  const size_t N_tot = rho.length;
39 
40  FTYPE_t mean_rho;
41  FTYPE_t R2_;
42  const FTYPE_t R2 = R*R;
43  size_t ix0 = N/2, iy0 = N/2, iz0 = N/2;
44 
45  #pragma omp parallel for private(R2_)
46  for (size_t ix = 0; ix < N; ++ix)
47  {
48  for (size_t iy = 0; iy < N; ++iy)
49  {
50  for (size_t iz = 0; iz < N; ++iz)
51  {
52  R2_ = pow2(ix - ix0) + pow2(iy - iy0) + pow2(iz - iz0);
53  rho(ix, iy, iz) = R2_ <= R2 ? rho_0 : 0;
54  }
55  }
56  }
57  mean_rho = mean(rho);
58 
59  if (mean_rho > 1) throw std::out_of_range("invalid values of sphere parameters (overdensity: " + std::to_string(-mean_rho) + " < -1)");
60 
61  rho -= mean_rho;
62  transform_Mesh_to_MultiGrid(rho, rho_grid);
63 
64  // check density
65  REQUIRE( mean(rho) == Approx(0.) );
66  REQUIRE( rho(ix0, iy0, iz0) == Approx(rho_0 - mean_rho) );
67  REQUIRE( rho(0, 0, 0) == Approx(-mean_rho) );
68 
69  // update background underdensity
70  sim.test_opt.rho_b = -mean_rho;
71 }
72 
73 void get_grav_pot(Mesh& rho, const FFTW_PLAN_TYPE& p_F, const FFTW_PLAN_TYPE& p_B, FTYPE_t box_size, FTYPE_t phi_prefactor)
74 {
75  fftw_execute_dft_r2c(p_F, rho);
76  gen_pot_k(rho);
77  fftw_execute_dft_c2r(p_B, rho);
78  rho *= pow(box_size / rho.N, 2) // computing units (laplace)
79  * phi_prefactor; // prefactor of poisson equation
80 }
81 
82 template <typename T> static int sgn(T val)
83 {
84  return (T(0) < val) - (val < T(0));
85 }
86 
87 void print_mesh(const std::string& file_name, const Mesh& pot, const FTYPE_t mod = -1 - CHI_MIN)
88 {
89  Ofstream File(file_name);
90  size_t N = pot.N;
91  int ix0 = N/2, iy0 = N/2, iz0 = N/2;
92 
93  auto print_r_chi = [&File, ix0, iy0, iz0,&pot, mod]
94  (int i, int j, int k)
95  {
96  Vec_3D<size_t> pos(i, j, k); //< to call periodic position on Mesh
97  FTYPE_t r = sqrt(pow2(i - ix0) + pow2(j - iy0) + pow2(k - iz0));
98  File << r << "\t" << pot(pos) + mod << "\n";
99  };
100 
101  for (size_t i = 0; i < N; ++i)
102  {
103  print_r_chi(i, i, i);
104  print_r_chi(i, i, i + 1);
105  print_r_chi(i, i + 1, i + 1);
106  }
107 }
108 
109 } // namespace <unique> end
110 
111 TEST_CASE( "UNIT TEST: create Multigrid and copy data to/from Mesh", "[multigrid]" )
112 {
113  print_unit_msg("create Multigrid and copy data to/from Mesh");
114 
115  constexpr size_t N = 32;
116  srand(time(0));
117  MultiGrid<3, FTYPE_t> grid(N);
118  Mesh mesh_from(N);
119  Mesh mesh_to(N);
120 
121  const std::vector<size_t> some_indices = // Mesh indices = N*N*(N+2)
122  {4, // (0, 0, 4)
123  (N+2)*2+5, // (0, 2, 5)
124  N*(N+2)*4+8*(N+2)+5}; // (4, 8, 5)
125  for(size_t i : some_indices) mesh_from[i] = 2.0*rand()/RAND_MAX - 1;
126 
127  transform_Mesh_to_MultiGrid(mesh_from, grid);
128  CHECK(min(mesh_from) == min(grid));
129  transform_MultiGrid_to_Mesh(mesh_to, grid);
130 
131  for(size_t i : some_indices) CHECK( mesh_from[i] == mesh_to[i] );
132  CHECK(min(mesh_from) == min(grid));
133  CHECK(min(mesh_to) == min(grid));
134 }
135 
136 TEST_CASE( "UNIT TEST: create and initialize ChiSolver, check bulk field", "[chameleon]" )
137 {
138  print_unit_msg("create and initialize ChiSolver, check bulk field");
139 
140  constexpr size_t N = 32;
141  constexpr FTYPE_t a = 0.5;
142  constexpr FTYPE_t rho_0 = 0.3;
143  const std::vector<size_t> some_indices = // Mesh indices = N*N*(N+2)
144  {4, // (0, 0, 4)
145  (N+2)*2+5, // (0, 2, 5)
146  N*(N+2)*4+8*(N+2)+5}; // (4, 8, 5)
147 
148  // initialize Sim_Param
149  const int argc = 1;
150  const char* const argv[1] = {"test"};
151  Sim_Param sim(argc, argv);
152 
153  // check thowing of exception with unphysical values of chameleon parameters
154  auto constructor = [&sim](){ ChiSolver<FTYPE_t> _sol(N, sim, false); };
155  sim.chi_opt.n = -1;
156  CHECK_THROWS_AS( constructor(), std::out_of_range );
157  sim.chi_opt.n = 0.5;
158  sim.chi_opt.beta = -1;
159  CHECK_THROWS_AS( constructor(), std::out_of_range );
160 
161  // initialize ChiSolver
162  sim.chi_opt.beta = 1/sqrt(6.);
163  ChiSolver<FTYPE_t> sol(N, sim, false);
164 
165  // check thowing of exceptions in uninitialised state
166  CHECK_THROWS_AS( sol.set_bulk_field(), std::out_of_range );
167 
168  // initialize overdensity -- constant density
169  MultiGrid<3, FTYPE_t> rho_grid(N);
170  {
171  Mesh rho(N);
172  rho.assign(rho_0);
173  transform_Mesh_to_MultiGrid(rho, rho_grid);
174  }
175 
176  // check density
177  for(size_t i : some_indices) CHECK( rho_grid[0][i] == rho_0 );
178 
179  // set ChiSolver -- bulk field
180  sol.set_time(a, sim.cosmo);
181  sol.add_external_grid(&rho_grid);
182  sol.set_bulk_field();
183 
184  // check bulk field
185  {
186  const FTYPE_t chi_bulk = sol.chi_min(rho_0);
187  FTYPE_t const* const chi = sol.get_y();
188  for(size_t i : some_indices) REQUIRE( chi[i] == Approx(chi_bulk));
189  }
190 
191  // check that EOM is satisfied
192  std::vector<size_t> index_list;
193  size_t level = 0;
194  const FTYPE_t h = 1.0/FTYPE_t( sol.get_N(level) );
195  for(size_t i : some_indices)
196  {
197  get_neighbor_gridindex(index_list, i, N);
198  CHECK( sol.l_operator(level, index_list, true, h) == Approx(0.));
199  }
200 }
201 
202 TEST_CASE( "UNIT TEST: create and initialize ChiSolver, solve sphere", "[chameleon]" )
203 {
204  print_unit_msg("create and initialize ChiSolver, solve sphere");
205 
206  // initialize Sim_Param
207  const char* const argv[1] = {"test"};
208  Sim_Param sim(1, argv);
209  const size_t N = sim.test_opt.N_grid;
210  const size_t N_min = sim.test_opt.N_min;
211  const bool verbose = sim.test_opt.verbose;
212 
213  // initialize ChiSolver
214  ChiSolver<CHI_PREC_t> sol(N, N_min, sim, verbose);
215 
216  // initialize overdensity -- constant density in sphere of radius R, center at x0, y0, z0
217  MultiGrid<3, CHI_PREC_t> rho_grid(N);
218  Mesh rho(N);
219  init_overdensity(sim, rho, rho_grid);
220 
221  // FFTW preparation
222  if (!FFTW_PLAN_OMP_INIT()){
223  throw std::runtime_error("Errors during multi-thread initialization");
224  }
225  FFTW_PLAN_OMP(sim.run_opt.nt);
226  const FFTW_PLAN_TYPE p_F = FFTW_PLAN_R2C(N, N, N, rho.real(), rho.complex(), FFTW_ESTIMATE);
227  const FFTW_PLAN_TYPE p_B = FFTW_PLAN_C2R(N, N, N, rho.complex(), rho.real(), FFTW_ESTIMATE);
228 
229  // set ChiSolver
230  sol.set_time(1, sim.cosmo);
231  sol.set_def_convergence();
232  sol.add_external_grid(&rho_grid);
233  sol.set_ngs_sweeps(sim.test_opt.fine_sweeps, sim.test_opt.coarse_sweeps); //< fine, coarse
234 
235  // compute gravitational potential
236  Mesh phi_pot(rho); //< copy density
237  get_grav_pot(phi_pot, p_F, p_B, sim.box_opt.box_size, sol.get_phi_prefactor());
238 
239  // get linear prediction
240  sol.set_linear(rho, p_F, p_B);
241  sol.set_screened();
242 
243  // full solution on Mesh
244  Mesh chi_full(N);
245 
246  // create directory structure
247  std::string out_dir = sim.out_opt.out_dir + "test_ChiSolver/";
248  remove_all_files(out_dir);
249  create_dir(out_dir);
250  sim.print_info(out_dir, "test");
251 
252  // print gravitational potential
253  print_mesh(out_dir + "grav_pot.dat", phi_pot, 0);
254 
255  // Solve the equation -- full V-cycles
256  BOOST_LOG_TRIVIAL(info) << "Starting V-cycles with intermediate output...\n";
257 
258  int istep = 0;
259  const size_t step_per_iter = sim.test_opt.step_per_iter;
260  while(1)
261  {
262  // istep, max_step (use int for the last iteration -- negative max_step)
263  istep += sol.get_istep();
264  int max_step = istep + step_per_iter > sim.test_opt.max_steps ? sim.test_opt.max_steps - istep : step_per_iter;
265 
266  // print chi_full
267  transform_MultiGridSolver_to_Mesh(chi_full, sol);
268  print_mesh(out_dir + "chi_istep_" + std::to_string(istep) + ".dat", chi_full);
269 
270  // check max_step and convergence
271  if ((max_step <= 0) || ((istep != 0) && (sol.get_istep() < step_per_iter))) break;
272 
273  // set & solve
274  sol.set_maxsteps(max_step);
275  sol.solve();
276  }
277 
278  // FFTW CLEANUP
279  FFTW_DEST_PLAN(p_F);
280  FFTW_DEST_PLAN(p_B);
282 }
Chi_Opt chi_opt
Definition: params.hpp:210
void print_mesh(const std::string &file_name, const Mesh &pot, const double mod=-1-CHI_MIN)
double box_size
Definition: params.hpp:59
constexpr CHI_PREC_t CHI_MIN
minimum value of chameleon field, in chi_a units it is &#39;0&#39;, in phi units it is &#39;-1&#39; ...
Definition: chameleon.cpp:66
FFTW_COMPLEX_TYPE * complex()
get fftw_complex pointer to data
Definition: class_mesh.hpp:111
#define CHECK_THROWS_AS(expr, exceptionType)
Definition: catch.hpp:13867
void transform_MultiGridSolver_to_Mesh(Mesh &mesh, const MultiGridSolver< 3, T > &sol)
Definition: chameleon.cpp:137
void transform_MultiGrid_to_Mesh(Mesh &mesh, const MultiGrid< 3, T > &mltgrid)
Definition: chameleon.cpp:134
Box_Opt box_opt
Definition: params.hpp:202
void init_overdensity(Sim_Param &sim, Mesh &rho, MultiGrid< 3, CHI_PREC_t > &rho_grid)
T * real()
Definition: class_mesh.hpp:36
void remove_all_files(const std::string &out_dir)
Definition: core_out.cpp:92
: class storing simulation parameters
Definition: params.hpp:193
void fftw_execute_dft_r2c(const FFTW_PLAN_TYPE &p_F, Mesh &rho)
compute forward (real to complex) FFT on mesh (inplace)
Definition: core_mesh.cpp:247
: creates a mesh of N*N*(N+2) cells
Definition: class_mesh.hpp:95
size_t step_per_iter
Definition: params.hpp:149
T pow2(T base)
Definition: precision.hpp:52
std::vector< T > data
Definition: class_mesh.hpp:33
double R_sphere
Definition: params.hpp:148
int iz
Definition: mfunc_bm.py:17
#define FFTW_PLAN_C2R
Definition: precision.hpp:30
void fftw_execute_dft_c2r(const FFTW_PLAN_TYPE &p_B, Mesh &rho)
compute backward (complex to real) FFT on mesh (inplace)
Definition: core_mesh.cpp:253
double n
Definition: params.hpp:185
void gen_pot_k(const Mesh &rho_k, Mesh &pot_k)
Definition: core_app.cpp:496
void transform_Mesh_to_MultiGrid(const Mesh &mesh, MultiGrid< 3, T > &mltgrid)
Definition: chameleon.cpp:108
#define REQUIRE(...)
Definition: catch.hpp:13849
double rho_sphere
Definition: params.hpp:148
Cosmo_Param cosmo
Definition: params.hpp:206
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
#define FFTW_PLAN_OMP_CLEAN
Definition: precision.hpp:33
void create_dir(const std::string &out_dir)
Definition: core_out.cpp:74
Test_Opt test_opt
Definition: params.hpp:211
void get_neighbor_gridindex(std::vector< size_t > &index_list, size_t i, size_t N)
Out_Opt out_opt
Definition: params.hpp:204
TEST_CASE("UNIT TEST: create Multigrid and copy data to/from Mesh","[multigrid]")
#define FFTW_PLAN_OMP
Definition: precision.hpp:31
size_t coarse_sweeps
Definition: params.hpp:149
size_t nt
Definition: params.hpp:134
size_t N
Definition: class_mesh.hpp:102
#define FFTW_PLAN_TYPE
Definition: precision.hpp:26
size_t length
Definition: class_mesh.hpp:32
Run_Opt run_opt
Definition: params.hpp:208
T min(const std::vector< T > &data)
Definition: chameleon.cpp:140
size_t N_grid
Definition: params.hpp:150
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
void get_grav_pot(Mesh &rho, const FFTW_PLAN_TYPE &p_F, const FFTW_PLAN_TYPE &p_B, double box_size, double phi_prefactor)
#define FFTW_PLAN_OMP_INIT
Definition: precision.hpp:32
void assign(T val)
Definition: class_mesh.hpp:38
double rho_b
Definition: params.hpp:154
void print_info(std::string out, std::string app) const
Definition: params.cpp:497
std::string out_dir
Definition: params.hpp:86
size_t fine_sweeps
Definition: params.hpp:149
size_t N_min
Definition: params.hpp:150
#define CHECK(...)
Definition: catch.hpp:13860
#define FFTW_DEST_PLAN
Definition: precision.hpp:27
double beta
Definition: params.hpp:185
chameleon model of gravity implementation
bool verbose
Definition: params.hpp:151
size_t max_steps
Definition: params.hpp:149
static int sgn(T val)
Definition: core_mesh.cpp:15
#define FFTW_PLAN_R2C
Definition: precision.hpp:29