Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
core_app.cpp
Go to the documentation of this file.
1 
9 #include <algorithm>
10 #include "core_app.h"
11 #include "core_mesh.h"
12 #include "CBRNG_Random.h"
13 
14 #ifndef ORDER
15 #define ORDER 1
16 #endif
17 
18 template<typename T>
19 static T mean(const std::vector<T>& data)
20 {
21  T tmp(0);
22 
23  #pragma omp parallel for reduction(+:tmp)
24  for (auto it = data.begin(); it < data.end(); ++it) tmp += *it;
25 
26  return tmp / data.size();
27 }
28 
29 static FTYPE_t mean(const Mesh& data)
30 {
31  return mean(data.data);
32 }
33 
34 template<typename T>
35 static T std_dev(const std::vector<T>& data, T mean)
36 {
37  T tmp(0);
38 
39  #pragma omp parallel for reduction(+:tmp)
40  for (auto it = data.begin(); it < data.end(); ++it) tmp += pow2(*it-mean);
41 
42  return sqrt(tmp / data.size());
43 }
44 
45 static FTYPE_t std_dev(const Mesh& data, FTYPE_t mean)
46 {
47  return std_dev(data.data, mean);
48 }
49 
50 template<typename T>
51 static T min(const std::vector<T>& data)
52 {
53  return *std::min_element(data.begin(), data.end());
54 }
55 
56 static FTYPE_t min(const Mesh& data){
57  return min(data.data);
58 }
59 
60 template<typename T>
61 static T max(const std::vector<T>& data)
62 {
63  return *std::max_element(data.begin(), data.end());
64 }
65 
66 static FTYPE_t max(const Mesh& data){
67  return max(data.data);
68 }
69 
70 static void set_unpert_pos_one_par(Vec_3D<size_t>& unpert_pos, const size_t par_index, const size_t par_per_dim, const size_t Ng)
71 {
72  unpert_pos[0] = (par_index / (par_per_dim * par_per_dim)) * Ng;
73  unpert_pos[1] = ((par_index / par_per_dim) % par_per_dim) * Ng;
74  unpert_pos[2] = (par_index % par_per_dim) * Ng;
75 }
76 
77 static void set_velocity_one_par(const Vec_3D<size_t>& unpert_pos, Vec_3D<FTYPE_t>& displ_field, const std::vector<Mesh> &vel_field)
78 {
79  for (size_t i = 0; i < 3; i++) displ_field[i] = vel_field[i](unpert_pos);
80 }
81 
82 void set_unpert_pos(const Sim_Param &sim, std::vector<Particle_x<FTYPE_t>>& particles)
83 {
84  Vec_3D<size_t> unpert_pos;
85  const size_t par_per_dim = sim.box_opt.par_num_1d;
86  const size_t Ng = sim.box_opt.Ng;
87  const size_t Np = sim.box_opt.par_num;
88 
89  #pragma omp parallel for private(unpert_pos)
90  for(size_t i=0; i< Np; i++)
91  {
92  set_unpert_pos_one_par(unpert_pos, i, par_per_dim, Ng);
93  particles[i] = Particle_x<FTYPE_t>(unpert_pos);
94  }
95 }
96 
97 void set_unpert_pos_w_vel(const Sim_Param &sim, std::vector<Particle_v<FTYPE_t>>& particles, const std::vector<Mesh> &vel_field)
98 {
99  Vec_3D<size_t> unpert_pos;
100  Vec_3D<FTYPE_t> velocity;
101  const size_t par_per_dim = sim.box_opt.par_num_1d;
102  const size_t Ng = sim.box_opt.Ng;
103 
104  const size_t Np = sim.box_opt.par_num;
105  #pragma omp parallel for private(unpert_pos, velocity)
106  for(size_t i=0; i< Np; i++)
107  {
108  set_unpert_pos_one_par(unpert_pos, i, par_per_dim, Ng);
109  set_velocity_one_par(unpert_pos, velocity, vel_field);
110  particles[i] = Particle_v<FTYPE_t>(unpert_pos, velocity);
111  }
112 }
113 
114 void set_pert_pos(const Sim_Param &sim, const FTYPE_t a, std::vector<Particle_x<FTYPE_t>>& particles, const std::vector< Mesh> &vel_field)
115 {
116  BOOST_LOG_TRIVIAL(debug) << "Setting initial positions of particles...";
117  Vec_3D<size_t> unpert_pos;
118  Vec_3D<FTYPE_t> velocity;
119  Vec_3D<FTYPE_t> pert_pos;
120 
121  const size_t par_per_dim = sim.box_opt.par_num_1d;
122  const size_t Ng = sim.box_opt.Ng;
123  const size_t Nm = sim.box_opt.mesh_num;
124  const size_t Np = sim.box_opt.par_num;
125 
126  const FTYPE_t D = growth_factor(a, sim.cosmo); // growth factor
127 
128  #pragma omp parallel for private(unpert_pos, velocity, pert_pos)
129  for(size_t i=0; i< Np; i++)
130  {
131  set_unpert_pos_one_par(unpert_pos, i, par_per_dim, Ng);
132  set_velocity_one_par(unpert_pos, velocity, vel_field);
133  pert_pos = velocity*D + unpert_pos;
134  get_per(pert_pos, Nm);
135  particles[i] = Particle_x<FTYPE_t>(pert_pos);
136  }
137 }
138 
139 void set_pert_pos(const Sim_Param &sim, const FTYPE_t a, std::vector<Particle_v<FTYPE_t>>& particles, const std::vector< Mesh> &vel_field)
140 {
141  BOOST_LOG_TRIVIAL(debug) << "Setting initial positions and velocitis of particles...";
142  Vec_3D<size_t> unpert_pos;
143  Vec_3D<FTYPE_t> velocity;
144  Vec_3D<FTYPE_t> pert_pos;
145 
146  const size_t par_per_dim = sim.box_opt.par_num_1d;
147  const size_t Ng = sim.box_opt.Ng;
148  const size_t Nm = sim.box_opt.mesh_num;
149  const size_t Np = sim.box_opt.par_num;
150 
151  const FTYPE_t D = growth_factor(a, sim.cosmo); // growth factor
152  const FTYPE_t dDda = growth_change(a, sim.cosmo); // dD / da
153 
154  #pragma omp parallel for private(unpert_pos, velocity, pert_pos)
155  for(size_t i=0; i< Np; i++)
156  {
157  set_unpert_pos_one_par(unpert_pos, i, par_per_dim, Ng);
158  set_velocity_one_par(unpert_pos, velocity, vel_field);
159  pert_pos = velocity*D + unpert_pos;
160  get_per(pert_pos, Nm);
161  particles[i] = Particle_v<FTYPE_t>(pert_pos, velocity*dDda);
162  }
163 }
164 
165 static void gen_gauss_white_noise(const Sim_Param &sim, Mesh& rho)
166 {
167  // Get keys for each slab in the x axis that this rank contains
168  std::vector<size_t> slab_keys;
169  slab_keys.resize(rho.N1);
170  GetSlabKeys(slab_keys.data(), 0, rho.N1, sim.run_opt.seed);
171 
172  size_t ikey, index;
173  FTYPE_t rn1, rn2, rn, tmp;
174  const size_t N = rho.N;
175 
176  #pragma omp parallel for private(ikey, index, rn1, rn2, rn, tmp)
177  for(size_t i=0; i < N; ++i)
178  {
179  ikey = slab_keys[i];
180  for(size_t j=0; j < N; ++j)
181  {
182  #ifndef NOISE_HALF
183  for(size_t k=0; k< N; ++k)
184  {
185  index = j*N + k;
186  GetRandomDoublesWhiteNoise(rn1, rn2, rn, ikey, index);
187  tmp = sqrt(-2*log(rn)/rn);
188  rho(i, j, k) = rn2 * tmp;
189  }
190  #else
191  for(size_t k=0; k < N/2; ++k) // go over half, use both random numbers
192  {
193  index = j*N + k;
194  GetRandomDoublesWhiteNoise(rn1, rn2, rn, ikey, index);
195  tmp = sqrt(-2*log(rn)/rn);
196  rho(i, j, 2*k) = rn2 * tmp;
197  rho(i, j, 2*k+1) = rn1 * tmp;
198  }
199  #endif
200  }
201  }
202  FTYPE_t t_mean;
203  #ifdef CORR
204  t_mean = mean(rho);
205  FTYPE_t t_std_dev = std_dev(rho, t_mean);
206  BOOST_LOG_TRIVIAL(debug) << "\t[mean = " << t_mean << ", stdDev = " << t_std_dev << "]\t-->";
207  rho-=t_mean;
208  rho/=t_std_dev;
209  #endif
210 
211  t_mean = mean(rho);
212  BOOST_LOG_TRIVIAL(debug) << "\t[mean = " << t_mean << ", stdDev = " << std_dev(rho, t_mean) << "]\t<--";
213  BOOST_LOG_TRIVIAL(debug) << "\t[min = " << min(rho) << ", max = " << max(rho) << "]";
214 }
215 
216 static FTYPE_t truncation_fce(FTYPE_t k, FTYPE_t k2_G)
217 {
218  return exp(-k*k/k2_G);
219 }
220 
221 static void gen_rho_w_pow_k(const Sim_Param &sim, Mesh& rho)
222 {
223  // extract const variables
224  const FTYPE_t L = sim.box_opt.box_size;
225  const FTYPE_t k0 = 2*PI/L;
226  const int phase = sim.run_opt.phase ? 1 : -1;
227  const size_t N = rho.N;
228  const size_t len = rho.length / 2;
229  const FTYPE_t mod = phase * pow(N / L, 3/2.); // pair sim, gaussian real -> fourier factor, dimension trans. Pk -> Pk*
230  const bool truncation = sim.cosmo.truncated_pk;
231 
232  if(truncation)
233  {
234  const FTYPE_t k2_G = sim.cosmo.k2_G;
235  #pragma omp parallel for
236  for(size_t i=0; i < len; i++)
237  {
238  FTYPE_t k = k0*sqrt(get_k_sq(N, i));
239  FTYPE_t tr = truncation_fce(k, k2_G);
240  rho[2*i] *= mod*sqrt(lin_pow_spec(1, k, sim.cosmo))*tr;
241  rho[2*i+1] *= mod*sqrt(lin_pow_spec(1, k, sim.cosmo))*tr;
242  }
243  }
244  else
245  {
246  #pragma omp parallel for
247  for(size_t i=0; i < len; i++)
248  {
249  FTYPE_t k = k0*sqrt(get_k_sq(N, i));
250  rho[2*i] *= mod*sqrt(lin_pow_spec(1, k, sim.cosmo));
251  rho[2*i+1] *= mod*sqrt(lin_pow_spec(1, k, sim.cosmo));
252  }
253  }
254 
255 }
256 
267 void gen_rho_dist_k(const Sim_Param &sim, Mesh& rho, const FFTW_PLAN_TYPE &p_F)
268 {
269  BOOST_LOG_TRIVIAL(debug) << "Generating gaussian white noise...";
270  gen_gauss_white_noise(sim, rho);
271  fftw_execute_dft_r2c(p_F, rho);
272 
273  BOOST_LOG_TRIVIAL(debug) << "Generating density distributions with given power spectrum...";
274  gen_rho_w_pow_k(sim, rho);
275 }
276 
277 template <class T>
278 void get_rho_from_par(const std::vector<T>& particles, Mesh& rho, const Sim_Param &sim)
279 {
280  BOOST_LOG_TRIVIAL(debug) << "Computing the density field from particle positions...";
281 
282  const size_t Np = sim.box_opt.par_num;
283  if (particles.size() != Np){
284  std::string msg = "Number of particles (" + std::to_string(particles.size()) + ") does not correspond with simulation parameters (" + std::to_string(Np) + ")!";
285  throw std::range_error(msg);
286  }
287  const FTYPE_t m = pow((FTYPE_t)rho.N, 3) / Np;
288  const FTYPE_t mesh_mod = (FTYPE_t)rho.N/sim.box_opt.mesh_num;
289 
290 
291  rho.assign(-1.);
292 
293  #pragma omp parallel for
294  for (size_t i = 0; i < Np; i++)
295  {
296  assign_to(rho, particles[i].position*mesh_mod, m);
297  }
298 }
299 
300 bool get_vel_from_par(const std::vector<Particle_v<FTYPE_t>>& particles, std::vector<Mesh>& vel_field, const Sim_Param &sim)
301 {
302  BOOST_LOG_TRIVIAL(debug) << "Computing the velocity field from particle positions...";
303  const FTYPE_t mesh_mod = (FTYPE_t)sim.box_opt.mesh_num_pwr/sim.box_opt.mesh_num;
304  const FTYPE_t m = pow((FTYPE_t)sim.box_opt.Ng_pwr, 3);
305  const size_t Np = sim.box_opt.par_num;
306 
307  for(Mesh& field : vel_field){
308  field.assign(0.);
309  }
310  #pragma omp parallel for
311  for (size_t i = 0; i < Np; i++)
312  {
313  assign_to(vel_field, particles[i].position*mesh_mod, particles[i].velocity*(m*mesh_mod));
314  }
315  return true;
316 }
317 
318 bool get_vel_from_par(const std::vector<Particle_x<FTYPE_t>>& particles, std::vector<Mesh>& vel_field, const Sim_Param &sim)
319 {
320  BOOST_LOG_TRIVIAL(debug) << "WARNING! Trying to compute velocity divergence with particle positions only! Skipping...";
321  return false;
322 }
323 
324 void pwr_spec_k(const Mesh &rho_k, Mesh& power_aux)
325 {
326  /* Computing the power spectrum P(k)/L^3 -- dimensionLESS!
327 
328  > in real part [even] of power_aux is stored pk, in imaginary [odd] dimensionLESS k
329  > preserve values in rho_k
330  > as power_aux can be Mesh of different (bigger) size than rho_k, all sizes / lengths are taken from rho_k
331  */
332 
333  FTYPE_t w_k;
334  Vec_3D<int> k_vec;
335  const size_t NM = rho_k.N;
336  const size_t half_length = rho_k.length / 2;
337 
338  #pragma omp parallel for private(w_k, k_vec)
339  for(size_t i=0; i < half_length;i++)
340  {
341  w_k = 1.;
342  get_k_vec(NM, i, k_vec);
343  for (unsigned int j = 0; j < 3; j++) if (k_vec[j] != 0) w_k *= pow(sin(k_vec[j]*PI/NM)/(k_vec[j]*PI/NM), ORDER + 1);
344  power_aux[2*i] = (rho_k[2*i]*rho_k[2*i] + rho_k[2*i+1]*rho_k[2*i+1])/(w_k*w_k);
345  power_aux[2*i+1] = k_vec.norm();
346  }
347 }
348 
349 void pwr_spec_k_init(const Mesh &rho_k, Mesh& power_aux)
350 {
351  /* same as above but now there is NO w_k correction */
352 
353  Vec_3D<int> k_vec;
354  const size_t NM = rho_k.N;
355  const size_t half_length = rho_k.length / 2;
356 
357  #pragma omp parallel for private(k_vec)
358  for(size_t i=0; i < half_length;i++)
359  {
360  get_k_vec(NM, i, k_vec);
361  power_aux[2*i] = pow2(rho_k[2*i]) + pow2(rho_k[2*i+1]);
362  power_aux[2*i+1] = k_vec.norm();
363  }
364 }
365 
366 void vel_pwr_spec_k(const std::vector<Mesh> &vel_field, Mesh& power_aux)
367 {
368  /* Computing the velocity power spectrum divergence P(k)/L^3 -- dimensionLESS!
369 
370  > in real part [even] of power_aux is stored pk, in imaginary [odd] dimensionLESS k
371  > preserve values in rho_k
372  > as power_aux can be Mesh of different (bigger) size than rho_k, all sizes / lengths are taken from rho_k
373  */
374 
375  FTYPE_t w_k;
376  Vec_3D<int> k_vec;
377 
378  const size_t NM = vel_field[0].N;
379  const size_t half_length = vel_field[0].length / 2;
380 
381  FTYPE_t vel_div_re, vel_div_im, k; // temporary store of Pk in case vel_field[0] = power_aux
382 
383  #pragma omp parallel for private(w_k, k_vec, k, vel_div_re, vel_div_im)
384  for(size_t i=0; i < half_length; i++)
385  {
386  w_k = 1.;
387  vel_div_re = vel_div_im = 0;
388  get_k_vec(NM, i, k_vec);
389  for (unsigned int j = 0; j < 3; j++){
390  k = k_vec[j]*2*PI / NM;
391  if (k != 0) w_k *= pow(sin(k/2)/(k/2), ORDER + 1);
392  vel_div_re += vel_field[j][2*i]*k; // do not care about Re <-> Im in 2*PI*i/N, norm only
393  vel_div_im += vel_field[j][2*i+1]*k;
394  }
395 
396  power_aux[2*i] = (vel_div_re*vel_div_re + vel_div_im*vel_div_im)/(w_k*w_k);
397  power_aux[2*i+1] = k_vec.norm();
398  }
399 }
400 
401 void gen_cqty_binned(const FTYPE_t x_min, const FTYPE_t x_max, const size_t bins_per_decade,
402  const Mesh &qty_mesh, const size_t half_length, Data_Vec<FTYPE_t,2>& qty_binned, const FTYPE_t mod_q, const FTYPE_t mod_x)
403 {
404  /* bin some complex quantity on mesh in logarithmic bins, assuming:
405  Q(x) = mod_q*qty_mesh[2*i]
406  x = mod_x*qty_mesh[2*i+1]
407  [mesh[2*i+1]] = [x_min] = [x_max]
408 
409  return binned data in qty_binned {x, <Q(x)>}
410 
411  Note: passing length of the array for case when my mesh is bigger than data stored in there
412  overloaded function exists when this is not the case
413  */
414 
415  size_t req_size = (size_t)ceil(bins_per_decade*log10(x_max/x_min));
416  qty_binned.resize(req_size);
417  qty_binned.fill(0);
418  std::vector<size_t> tmp(req_size, 0); // for counts in bins
419 
420  FTYPE_t x;
421  size_t bin;
422 
423  /* compute sum x, Q(x), Q^2(x) in bins */
424  #pragma omp parallel for private(x, bin)
425  for (size_t i = 0; i < half_length; i++){
426  x = qty_mesh[2*i+1];
427  if ((x <x_max) && (x>=x_min)){
428  bin = (size_t)((log10(x) - log10(x_min)) * bins_per_decade);
429  #pragma omp atomic
430  qty_binned[0][bin] += x;
431  #pragma omp atomic
432  qty_binned[1][bin] += qty_mesh[2*i];
433  #pragma omp atomic
434  tmp[bin]++;
435  }
436  }
437 
438  /* compute average x, Q(x) in bins */
439  size_t count;
440  for (size_t j = 0; j < qty_binned.size(); ){
441  count = tmp[j];
442  if (count){
443  qty_binned[0][j] *= mod_x / count;
444  qty_binned[1][j] *= mod_q / count;
445  j++;
446  }else{
447  qty_binned.erase(j);
448  tmp.erase(tmp.begin() + j);
449  }
450  }
451 }
452 
453 
454 void gen_cqty_binned(const FTYPE_t x_min, const FTYPE_t x_max, const size_t bins_per_decade,
455  const Mesh &qty_mesh, Data_Vec<FTYPE_t, 2>& qty_binned, const FTYPE_t mod_q, const FTYPE_t mod_x)
456 {
457  gen_cqty_binned(x_min, x_max, bins_per_decade, qty_mesh, qty_mesh.length / 2, qty_binned, mod_q, mod_x);
458 }
459 
460 void gen_pow_spec_binned(const Sim_Param &sim, const Mesh &power_aux, Data_Vec<FTYPE_t, 2>& pwr_spec_binned)
461 {
462  const FTYPE_t mod_pk = pow(sim.box_opt.box_size, 3); // P(k) -> dimensionFULL!
463  const FTYPE_t mod_k = 2*PI/sim.box_opt.box_size;
464  BOOST_LOG_TRIVIAL(debug) << "Computing binned power spectrum...";
465  gen_cqty_binned(1, sim.box_opt.mesh_num_pwr, sim.out_opt.bins_per_decade, power_aux, pwr_spec_binned, mod_pk, mod_k);
466 }
467 
468 void gen_pow_spec_binned_init(const Sim_Param &sim, const Mesh &power_aux, const size_t half_length, Data_Vec<FTYPE_t, 2>& pwr_spec_binned)
469 {
470  /* same as above but now power_aux is storing only data [0...mesh_num], NOT mesh_num_pwr */
471  const FTYPE_t mod_pk = pow(sim.box_opt.box_size, 3); // P(k) -> dimensionFULL!
472  const FTYPE_t mod_k = 2*PI/sim.box_opt.box_size;
473  BOOST_LOG_TRIVIAL(debug) << "Computing binned initial power spectrum...";
474  gen_cqty_binned(1, sim.box_opt.mesh_num, sim.out_opt.bins_per_decade, power_aux, half_length, pwr_spec_binned, mod_pk, mod_k);
475 }
476 
477 template<class P, typename T, size_t N> // P = everything callable P_k(k), T = float-type, N = number
478 void gen_pow_spec_binned_from_extrap(const Sim_Param &sim, const P &P_k, Data_Vec<T, N>& pwr_spec_binned)
479 {
480  const T k_max = sim.other_par.k_print.upper;
481  const T k_min = sim.other_par.k_print.lower;
482  const T log_bin = T(1) / sim.out_opt.bins_per_decade;
483  T k;
484  size_t req_size = (size_t)ceil( sim.out_opt.bins_per_decade*log10(k_max/k_min));
485  pwr_spec_binned.resize(req_size);
486 
487  #pragma omp parallel for private(k)
488  for (size_t j = 0; j < pwr_spec_binned.size(); j++){
489  k = k_min*pow(T(10), j*log_bin);
490  pwr_spec_binned[0][j] = k;
491  pwr_spec_binned[1][j] = P_k(k);
492  }
493 }
494 
495 
496 void gen_pot_k(const Mesh& rho_k, Mesh& pot_k)
497 { /*
498  pot_k can be Mesh of differen (bigger) size rho_k,
499  !!!> ALL physical FACTORS ARE therefore TAKEN FROM rho_k <!!!
500  */
501  BOOST_LOG_TRIVIAL(debug) << "Computing potential in k-space...";
502  FTYPE_t k2;
503  const size_t N = rho_k.N; // for case when pot_k is different mesh than vel_field
504  const FTYPE_t d2_k = pow2(2*PI/N); // factor from second derivative with respect to the mesh coordinates
505  const size_t l_half = rho_k.length/2;
506 
507  #pragma omp parallel for private(k2)
508  for(size_t i=0; i < l_half;i++){
509  k2 = get_k_sq(N, i);
510  if (k2 == 0){
511  pot_k[2*i] = 0;
512  pot_k[2*i+1] = 0;
513  } else{
514  pot_k[2*i] = -rho_k[2*i]/(k2*d2_k);
515  pot_k[2*i+1] = -rho_k[2*i+1]/(k2*d2_k);
516  }
517  }
518 }
519 
520 void gen_pot_k(Mesh& rho_k){ gen_pot_k(rho_k, rho_k); }
521 
522 static FTYPE_t S2_shape(const FTYPE_t k2, const FTYPE_t a)
523 {
524  if (a == 0) return 1.;
525 
526  FTYPE_t t = sqrt(k2)*a / 2;
527  if (t == 0) return 1.;
528  return 12 / pow(t, 4)*(2 - 2 * cos(t) - t*sin(t));
529 }
530 
531 static FTYPE_t CIC_opt(Vec_3D<FTYPE_t> k_vec, const FTYPE_t a)
532 {
533 #define N_MAX 1
534 #ifndef N_MAX
535  FTYPE_t s2 = pow2(S2_shape(k_vec.norm2(), a));
536  for(unsigned int j=0; j<3; j++)
537  {
538  if (k_vec[j] != 0) s2 /= pow2(sin(k_vec[j] / 2) / (k_vec[j] / 2)); //W (k) for CIC (order 1)
539  }
540  return s2;
541 #else
542  FTYPE_t k_n[3];
543  FTYPE_t U2, U_n, G_n, k2n;
544 
545  G_n = 0;
546  U2 = 1;
547  for (unsigned int j = 0; j < 3; j++) U2 *= (1+2*pow2(cos(k_vec[j]/2)))/3; // inf sum of U_n^2 for CIC
548  for (int n1 = -N_MAX; n1 < N_MAX + 1; n1++)
549  {
550  k_n[0] = k_vec[0] + 2 * PI*n1;
551  for (int n2 = -N_MAX; n2 < N_MAX + 1; n2++)
552  {
553  k_n[1] = k_vec[1] + 2 * PI*n2;
554  for (int n3 = -N_MAX; n3 < N_MAX + 1; n3++)
555  {
556  k_n[2] = k_vec[2] + 2 * PI*n3;
557  U_n = 1.;
558  k2n = 0;
559  for(unsigned int j=0; j<3; j++)
560  {
561  if (k_n[j] != 0) U_n *= sin(k_n[j] / 2) / (k_n[j] / 2);
562  k2n += pow2(k_n[j]);
563  }
564  U_n = pow2(U_n); // W(k) for CIC (order 1)
565  if (k2n != 0)
566  {
567  for(unsigned int j=0; j<3; j++)
568  {
569  G_n += k_vec[j]* // i.D(k)
570  k_n[j]/k2n*pow2(S2_shape(k2n, a))* // R*(k_n) /i
571  U_n; // U_n
572  }
573  }
574  }
575  }
576  }
577  if ((G_n != G_n) || (U2 != U2))
578  {
579  BOOST_LOG_TRIVIAL(warning) << "Gn = " << G_n << "\tU2 = " << U2 << ", k = (" << k_vec[0] << ", " << k_vec[1] << ", " << k_vec[2] << ")";
580  return 1.;
581  }
582  return G_n/U2;
583 #endif
584 }
585 
586 void gen_displ_k_S2(std::vector<Mesh>& vel_field, const Mesh& pot_k, const FTYPE_t a)
587 { /*
588  pot_k can be Mesh of differen (bigger) size than each vel_field,
589  !!!> ALL physical FACTORS ARE therefore TAKEN FROM vel_field[0] <!!!
590  */
591  if (a == -1) BOOST_LOG_TRIVIAL(debug) << "Computing displacement in k-space...";
592  else if (a == 0) BOOST_LOG_TRIVIAL(debug) << "Computing displacement in k-space with CIC opt...";
593  else BOOST_LOG_TRIVIAL(debug) << "Computing force in k-space for S2 shaped particles with CIC opt...";
594 
595  FTYPE_t opt;
596  Vec_3D<int> k_vec;
597  Vec_3D<FTYPE_t> k_vec_phys;
598  FTYPE_t potential_tmp[2];
599 
600  const size_t N = vel_field[0].N; // for case when pot_k is different mesh than vel_field
601  const FTYPE_t d_k = 2*PI/N; // 2*PI/N comes from derivative WITH RESPECT to the mesh coordinates
602  const size_t l_half = vel_field[0].length/2;
603 
604  #pragma omp parallel for private(opt, k_vec, k_vec_phys, potential_tmp)
605  for(size_t i=0; i < l_half;i++)
606  {
607  potential_tmp[0] = pot_k[2*i]; // prevent overwriting if vel_field[0] == pot_k
608  potential_tmp[1] = pot_k[2*i+1]; // prevent overwriting if vel_field[0] == pot_k
609  get_k_vec(N, i, k_vec);
610  k_vec_phys = d_k*k_vec;
611  // no optimalization
612  if (a == -1) opt = 1.;
613  // optimalization for CIC and S2 shaped particle
614  else opt = CIC_opt(k_vec_phys, a);
615  for(size_t j=0; j<3;j++)
616  {
617  vel_field[j][2*i] = k_vec_phys[j]*potential_tmp[1]*opt;
618  vel_field[j][2*i+1] = -k_vec_phys[j]*potential_tmp[0]*opt;
619  }
620  }
621 }
622 
623 void gen_displ_k(std::vector<Mesh>& vel_field, const Mesh& pot_k) {gen_displ_k_S2(vel_field, pot_k, -1);}
624 
625 void gen_displ_k_cic(std::vector<Mesh>& vel_field, const Mesh& pot_k) {gen_displ_k_S2(vel_field, pot_k, 0.);}
626 
627 void gen_dens_binned(const Mesh& rho, std::vector<size_t> &dens_binned, const Sim_Param &sim)
628 {
629  BOOST_LOG_TRIVIAL(debug) << "Computing binned density field...";
630  size_t bin;
631  FTYPE_t rho_avg;
632  const size_t Ng_pwr = sim.box_opt.Ng_pwr;
633  const size_t N = rho.N;
634 
635  dens_binned.assign(dens_binned.size(), 0);
636 
637  #pragma omp parallel for private(bin, rho_avg)
638  for (size_t i = 0; i < N; i+=Ng_pwr)
639  {
640  for (size_t j = 0; j < N; j+=Ng_pwr)
641  {
642  for (size_t k = 0; k < N; k+=Ng_pwr)
643  {
644  // Need to go through all mesh cells [i, i+Ng-1]*[j, j+Ng-1], [k, k+Ng, -1]
645  rho_avg = 0;
646  for (size_t ii = i; ii < i+Ng_pwr; ii++)
647  {
648  for (size_t jj = j; jj < j+Ng_pwr; jj++)
649  {
650  for (size_t kk = k; kk < k+Ng_pwr; kk++)
651  {
652  rho_avg+=rho(ii, jj, kk);
653  }
654  }
655  }
656  rho_avg /= pow((FTYPE_t)Ng_pwr, 3);
657  bin = (size_t)((rho_avg+1)/0.1);
658  if (bin >= dens_binned.size()) bin = dens_binned.size() - 1;
659  // if (bin >= dens_binned.capacity()) dens_binned.resize(bin+1);
660  #pragma omp atomic
661  dens_binned[bin]++;
662  //dens_binned[bin] += pow(sim.box_opt.Ng_pwr, 3);
663  }
664  }
665  }
666 }
667 
668 template void get_rho_from_par(const std::vector<Particle_x<FTYPE_t>>&, Mesh&, const Sim_Param&);
669 template void get_rho_from_par(const std::vector<Particle_v<FTYPE_t>>&, Mesh&, const Sim_Param&);
void gen_pow_spec_binned_from_extrap(const Sim_Param &sim, const P &P_k, Data_Vec< T, N > &pwr_spec_binned)
Definition: core_app.cpp:478
double box_size
Definition: params.hpp:59
static double S2_shape(const double k2, const double a)
Definition: core_app.cpp:522
bool get_vel_from_par(const std::vector< Particle_v< double >> &particles, std::vector< Mesh > &vel_field, const Sim_Param &sim)
Definition: core_app.cpp:300
size_t par_num
Definition: params.hpp:61
void get_rho_from_par(const std::vector< T > &particles, Mesh &rho, const Sim_Param &sim)
Definition: core_app.cpp:278
void gen_rho_dist_k(const Sim_Param &sim, Mesh &rho, const FFTW_PLAN_TYPE &p_F)
Generate density distributions in k-space.
Definition: core_app.cpp:267
double get_k_sq(size_t N, size_t index)
Definition: core_mesh.cpp:38
double lin_pow_spec(double a, double k, const Cosmo_Param &cosmo)
Definition: core_power.cpp:474
static void set_velocity_one_par(const Vec_3D< size_t > &unpert_pos, Vec_3D< double > &displ_field, const std::vector< Mesh > &vel_field)
Definition: core_app.cpp:77
class handling particles (position only)
Box_Opt box_opt
Definition: params.hpp:202
bool phase
Definition: params.hpp:138
size_t Ng_pwr
Definition: params.hpp:61
void set_pert_pos(const Sim_Param &sim, const double a, std::vector< Particle_x< double >> &particles, const std::vector< Mesh > &vel_field)
Definition: core_app.cpp:114
void gen_cqty_binned(const double x_min, const double x_max, const size_t bins_per_decade, const Mesh &qty_mesh, const size_t half_length, Data_Vec< double, 2 > &qty_binned, const double mod_q, const double mod_x)
Definition: core_app.cpp:401
void gen_displ_k(std::vector< Mesh > &vel_field, const Mesh &pot_k)
Definition: core_app.cpp:623
: class storing simulation parameters
Definition: params.hpp:193
static double CIC_opt(Vec_3D< double > k_vec, const double a)
Definition: core_app.cpp:531
size_t size() const noexcept
void erase(size_t index)
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
size_t mesh_num_pwr
Definition: params.hpp:58
size_t count(InputIterator first, InputIterator last, T const &item)
Definition: catch.hpp:2747
: creates a mesh of N*N*(N+2) cells
Definition: class_mesh.hpp:95
void assign_to(Mesh &field, const Vec_3D< double > &position, const double value)
Definition: core_mesh.cpp:201
#define N_MAX
#define ORDER
Definition: core_app.cpp:15
void set_unpert_pos_w_vel(const Sim_Param &sim, std::vector< Particle_v< double >> &particles, const std::vector< Mesh > &vel_field)
Definition: core_app.cpp:97
T pow2(T base)
Definition: precision.hpp:52
void resize(size_t n)
std::vector< T > data
Definition: class_mesh.hpp:33
size_t Ng
Definition: params.hpp:61
void fill(T val)
static T std_dev(const std::vector< T > &data, T mean)
Definition: core_app.cpp:35
void gen_pot_k(const Mesh &rho_k, Mesh &pot_k)
Definition: core_app.cpp:496
static void set_unpert_pos_one_par(Vec_3D< size_t > &unpert_pos, const size_t par_index, const size_t par_per_dim, const size_t Ng)
Definition: core_app.cpp:70
size_t par_num_1d
Definition: params.hpp:58
class handling particles (position only)
void gen_pow_spec_binned(const Sim_Param &sim, const Mesh &power_aux, Data_Vec< double, 2 > &pwr_spec_binned)
Definition: core_app.cpp:460
declaration in params.hpp
Definition: core_power.h:19
Cosmo_Param cosmo
Definition: params.hpp:206
double upper
Definition: params.hpp:163
size_t N1
Definition: class_mesh.hpp:32
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
interface for common functions for all types of approximations
static CCL_BEGIN_DECLS double x[111][8]
Range k_print
range in which compute the correlation function
Definition: params.hpp:174
static T max(const std::vector< T > &data)
Definition: core_app.cpp:61
static double truncation_fce(double k, double k2_G)
Definition: core_app.cpp:216
Out_Opt out_opt
Definition: params.hpp:204
void gen_dens_binned(const Mesh &rho, std::vector< size_t > &dens_binned, const Sim_Param &sim)
Definition: core_app.cpp:627
void vel_pwr_spec_k(const std::vector< Mesh > &vel_field, Mesh &power_aux)
Definition: core_app.cpp:366
double lower
Definition: params.hpp:163
size_t N
Definition: class_mesh.hpp:102
void pwr_spec_k(const Mesh &rho_k, Mesh &power_aux)
Definition: core_app.cpp:324
static std::enable_if< std::is_integral< T >::value, T >::type get_per(T vec, size_t per)
Definition: core_mesh.cpp:48
constexpr double PI
Definition: precision.hpp:37
#define FFTW_PLAN_TYPE
Definition: precision.hpp:26
double k2_G
Definition: params.hpp:35
void gen_pow_spec_binned_init(const Sim_Param &sim, const Mesh &power_aux, const size_t half_length, Data_Vec< double, 2 > &pwr_spec_binned)
Definition: core_app.cpp:468
size_t length
Definition: class_mesh.hpp:32
: linear interpolation of data [k, P(k)] within &#39;useful&#39; range fit to primordial P_i(k) below the &#39;us...
Definition: core_power.h:122
size_t seed
Definition: params.hpp:135
Run_Opt run_opt
Definition: params.hpp:208
void get_k_vec(size_t N, size_t index, int *k_vec)
Definition: core_mesh.cpp:20
basic functions to work with mesh
size_t bins_per_decade
Definition: params.hpp:85
bool truncated_pk
Definition: params.hpp:41
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
static void gen_gauss_white_noise(const Sim_Param &sim, Mesh &rho)
Definition: core_app.cpp:165
void pwr_spec_k_init(const Mesh &rho_k, Mesh &power_aux)
Definition: core_app.cpp:349
static int m[2]
Definition: ccl_emu17.c:25
void assign(T val)
Definition: class_mesh.hpp:38
size_t mesh_num
Definition: params.hpp:58
void set_unpert_pos(const Sim_Param &sim, std::vector< Particle_x< double >> &particles)
Definition: core_app.cpp:82
static T mean(const std::vector< T > &data)
Definition: core_app.cpp:19
void gen_displ_k_cic(std::vector< Mesh > &vel_field, const Mesh &pot_k)
Definition: core_app.cpp:625
static T min(const std::vector< T > &data)
Definition: core_app.cpp:51
Other_par other_par
Definition: params.hpp:209
void gen_displ_k_S2(std::vector< Mesh > &vel_field, const Mesh &pot_k, const double a)
Definition: core_app.cpp:586
static void gen_rho_w_pow_k(const Sim_Param &sim, Mesh &rho)
Definition: core_app.cpp:221
double growth_change(double a, const Cosmo_Param &cosmo)
Definition: core_power.cpp:447