FML
Simulation.h
Go to the documentation of this file.
1#ifndef SIMULATION_HEADER
2#define SIMULATION_HEADER
3
9#include <FML/Global/Global.h>
12#include <FML/NBody/NBody.h>
17#include <FML/Spline/Spline.h>
18#include <FML/Timing/Timings.h>
19
20#include "AnalyzeOutput.h"
21#include "COLA.h"
22#include "Cosmology.h"
23#include "GravityModel.h"
24
25#include <array>
26#include <cmath>
27#include <iostream>
28#include <memory>
29#include <sstream>
30#include <string>
31#include <utility>
32#include <vector>
33
34//=============================================================================
35// Type alises we use below
36//=============================================================================
43template <int N>
45template <class T1>
50template <int N>
52
53template <int NDIM, class T>
55 protected:
56 //=============================================================================
57 /// Everything related to the background evolution
58 //=============================================================================
59 std::shared_ptr<Cosmology> cosmo;
60
61 //=============================================================================
62 /// Everything related to gravity: growth factors, computing forces
63 //=============================================================================
64 std::shared_ptr<GravityModel<NDIM>> grav;
65
66 //=============================================================================
67 /// Everything related to linear perturbations, transfer functions, initial pofk
68 /// This is only used if ic_type_of_input == transferinfofile
69 //=============================================================================
70 std::shared_ptr<LinearTransferData> transferdata;
71
72 //=============================================================================
73 /// A copy of the simulation parameters just to have it. All parameters
74 /// *should* be read in from this during read_parameters
75 //=============================================================================
76 std::shared_ptr<ParameterMap> parameters;
77
78 //=============================================================================
79 /// All the particles
80 //=============================================================================
82
83 //=============================================================================
84 /// The initial density field delta_cb(zini,k) computed with the same Nmesh
85 /// as the forces (used for linear massive neutrinos - not allocated otherwise)
86 /// NB: we cannot use phi_1LPT_ini_fourier below as it might have a different gridsize
87 //=============================================================================
89
90 //=============================================================================
91 // LPT potentials NB: these grids will only get allocated if they are required!
92 //=============================================================================
97
98 // Do timings of the code
100
101 // Splines used to generate the IC
102 Spline power_primordial_spline{"P_primordial(k)"}; // Spline of primordial power-spectrum (h/Mpc) vs (Mpc/h)^3
103 Spline power_initial_spline{"P(k,zini)"}; // Spline of baryon-CDM power-spectrum (h/Mpc) vs (Mpc/h)^3
104 Spline transfer_initial_spline{"T(k,zini)"}; // Spline of baryon-CDM transfer function (h/Mpc) vs Mpc^2
105
106 //=============================================================================
107 // Parameters of the simulation
108 //=============================================================================
109
110 std::string simulation_name; // The name of sim used for outputs
111 double simulation_boxsize; // The boxsize in Mpc/h
112 bool simulation_use_cola; // Use the cola method?
113 bool simulation_use_scaledependent_cola; // If cola, use cola with scaledependent growth?
114
115 // Force and density assignment
116 int force_nmesh; // The gridsize to bin particles to and compute PM forces
117 std::string force_density_assignment_method; // Density assignment (NGP,CIC,TSC,PCS,PQS)
118 std::string force_kernel; // The force kernel (see relevant files)
119 bool force_linear_massive_neutrinos; // Include the effects of massive neutrinos using linear theory
120
121 // Initial conditions
122 std::string ic_random_field_type; // gaussian, nongaussian, reconstruct_from_particles, read_particles
123 double ic_initial_redshift; // The initial redshift of the sim
124 int ic_nmesh; // The Nmesh used to generate the IC (use particle_Npart_1D)
125 int ic_random_seed; // The random seed
126 std::string ic_random_generator; // The generator: GSL or MT19937 (fiducial)
127 int ic_LPT_order; // The LPT order to use to make IC (1,2,3)
128
129 // Initial conditions: input file (power-spectrum / transfer functions)
130 std::string ic_type_of_input; // Type of input (powerspectrum, transferfuntion, transferinfofile)
131 std::string ic_input_filename; // The filename
132 double ic_input_redshift; // The redshift of P(k,z) / T(k,z) that we read in
133 bool ic_use_gravity_model_GR; // Input power-spectrum is for LCDM so if MG use LCDM to set the IC
134
135 // Initial conditions: Ampitude fixed IC
136 bool ic_fix_amplitude; // Fix amplitude of delta(k,zini) to that of P(k)
137 bool ic_reverse_phases; // Set delta(k,zini) -> -delta(k,zini)
138
139 // Initial conditions: Non-gaussianity (ic_random_field_type = nongaussian)
140 std::string ic_fnl_type; // local, equilateral, orthogonal
141 double ic_fnl; // fNL
142 double ic_fnl_redshift; // Redshift of which to generate the primordial potential
143
144 // Initial conditions: Normalization using sigma8?
145 bool ic_sigma8_normalization; // Normalize wrt to a sigma8 value?
146 double ic_sigma8_redshift; // The redshift of which to normalize
147 double ic_sigma8; // The value of sigma8 at this redshift we want
148
149 // Initial conditions: Read IC from file and reconstruct the LPT fields if COLA
150 std::string ic_reconstruct_gadgetfilepath; // /path/to/gadget
151 std::string ic_reconstruct_assigment_method; // Density assignment method (NGP, CIC, ...)
152 std::string ic_reconstruct_smoothing_filter; // Smoothing filter (tophat, sharpk, gaussian)
153 double ic_reconstruct_dimless_smoothing_scale; // Smoothing scales R/boxsize
154 bool ic_reconstruct_interlacing; // Use interlacing (probably not)?
155
156 // Particles
157 int particle_Npart_1D; // Number of particles per dimension (total is N^3)
158 double particle_allocation_factor; // Allocation this many more particles
159
160 // Time-stepping
161 std::vector<int> timestep_nsteps; // Steps between the outputs (if just 1 number the total amount of steps)
162 std::string timestep_method; // The method of Quinn or the method of Tassev (for COLA mainly)
163 std::string timestep_algorithm; // KDK - Kick-Drift-Kick is the main method we use
164 double timestep_cola_nLPT; // nLPT. For timestep_method = Tassev
165 std::string timestep_scalefactor_spacing; // linear, logarithmic, powerlaw
166 double timestep_spacing_power; // For timestep_scalefactor_spacing = powerlaw
167
168 // FoF halofinding
169 bool fof; // Locate halos when we output
170 int fof_nmin_per_halo; // Minimum particles per halo
171 int fof_nmesh_max; // For speeding it up: the maximum gridsize to bin particle to
172 double fof_linking_length; // The linking length in units of the mean partice separation (i.e. ~0.2)
173 double fof_buffer_length_mpch; // The buffer region (from nbor tasks) we use in the FoF finding
174
175 // Power-spectrum
176 bool pofk; // Compute power-spectrum when we output
177 int pofk_nmesh; // The grid size to use for this
178 bool pofk_interlacing; // Use interlacing for alias reduction?
179 bool pofk_subtract_shotnoise; // Subtract shotnoise?
180 std::string pofk_density_assignment_method; // Density assignment method (NGP, CIC, ...)
181
182 // Power-spectrum multipoles
183 bool pofk_multipole; // Compute power-spectrum multipoles when we output
184 int pofk_multipole_nmesh; // The grid size to use for this
185 bool pofk_multipole_interlacing; // Use interlacing for alias reduction?
186 bool pofk_multipole_subtract_shotnoise; // Subtract shotnoise for P0?
187 int pofk_multipole_ellmax; // Compute P_ell for ell=0,2,4,...,ellmax
188 std::string pofk_multipole_density_assignment_method; // Density assignment method (NGP, CIC, ...)
189
190 // Bispectrum
191 bool bispectrum; // Compute bispectrum when we output
192 int bispectrum_nmesh; // The grid size to use for this
193 int bispectrum_nbins; // The number of bins in k to use (memory req. scales as nbins^3)
194 std::string bispectrum_density_assignment_method; // Density assignment method (NGP, CIC, ...)
195 bool bispectrum_interlacing; // Use interlacing for alias reduction?
196 bool bispectrum_subtract_shotnoise; // Subtract shotnoise?
197
198 // Output
199 std::vector<double> output_redshifts; // List of output redshift from large to small
200 bool output_particles; // Output particles?
201 std::string output_fileformat; // Fileformat for particles (GADGET)
202 std::string output_folder; // Folder to store output
203
204 //=============================================================================
205 // Some of the stuff we compute and output is small so we also keep it
206 // in the class in case one wants to process it later
207 //=============================================================================
208 // A list of (z, P(k)) for the particles at every step (naive binning - not using the same pofk_* setting!)
209 std::vector<std::pair<double, PowerSpectrumBinning<NDIM>>> pofk_cb_every_step;
210 std::vector<std::pair<double, PowerSpectrumBinning<NDIM>>> pofk_total_every_step;
211 // A list of (z, P(k)) for the particles that we compute if pofk = true
212 std::vector<std::pair<double, PowerSpectrumBinning<NDIM>>> pofk_every_output;
213 // A list of (z, P_ell(k)) for the particles that we compute every output if pofk_multipoles = true
214 std::vector<std::pair<double, std::vector<PowerSpectrumBinning<NDIM>>>> pofk_multipoles_every_output;
215
216 public:
217 NBodySimulation() = default;
218 NBodySimulation(std::shared_ptr<Cosmology> cosmo, std::shared_ptr<GravityModel<NDIM>> grav)
219 : cosmo(cosmo), grav(grav) {
220 timer.StartTiming("The whole simulation");
221 }
222
223 // Move in particles from an external source
224 NBodySimulation(std::shared_ptr<Cosmology> cosmo,
225 std::shared_ptr<GravityModel<NDIM>> grav,
226 MPIParticles<T> && _part)
228 part = std::move(_part);
229 }
230
231 // Compute the time-steps for updates of position and velocity
232 std::pair<std::vector<double>, std::vector<double>> compute_scalefactors_KDK(double amin, double amax, int nsteps);
233 // Compute the delta_t to use for each of the steps
234 std::pair<std::vector<double>, std::vector<double>> compute_deltatime_KDK(double amin, double amax, int nsteps);
235
236 /// Read in and set parameters we need
237 void read_parameters(ParameterMap & param);
238
239 /// Initialize simulation. Create initial conditions. Make it ready to run
240 void init();
241
242 /// This method simply read particles and uses them for the simulation
243 void read_ic();
244
245 /// Run simulation
246 void run();
247
248 /// From particles to density field
249 void compute_density_field_fourier(FFTWGrid<NDIM> & density_grid_fourier, double a);
250
251 /// Compute stuff on the fly and output
252 void analyze_and_output(int ioutput, double redshift);
253
254 // Generation of IC (to be separated out in own file)
255 template <int _NDIM, class _T>
257
258 // On the fly analysis methods
259 template <int _NDIM, class _T>
260 friend void compute_fof_halos(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
261 template <int _NDIM, class _T>
262 friend void compute_power_spectrum(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
263 template <int _NDIM, class _T>
264 friend void
265 compute_power_spectrum_multipoles(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
266 template <int _NDIM, class _T>
267 friend void compute_bispectrum(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
268 template <int _NDIM, class _T>
269 friend void output_gadget(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
270 template <int _NDIM, class _T>
271 friend void output_fml(NBodySimulation<_NDIM, _T> & sim, double redshift, std::string snapshot_folder);
272 template <int _NDIM, class _T>
274
275 // Free all memory
276 void free();
277};
278
279template <int NDIM, class T>
281 -> std::pair<std::vector<double>, std::vector<double>> {
282
283 if (nsteps == 0)
284 return {{}, {}};
285
286 // The explicit timeevolution of the prefactor to the force (1.5*OmegaM*a in GR)
287 // (In general this will depend on scale, but we are not that crazy that we compute
288 // a factor per scale. Probably perfectly fine to simply use the GR expression in general)
289 auto poisson_factor = [&](double a) { return 1.5 * cosmo->get_OmegaM() * grav->GeffOverG(a) * a; };
290
291 //=====================================================
292 // Timestep for a kick-step: Tassev et al.
293 //=====================================================
294 auto compute_kick_timestep_tassev = [&](double alow, double ahigh, int istep, int nsteps) {
295 double amid = (ahigh + alow) / 2.;
296
297 if (istep == 0)
298 amid = alow;
299 else if (istep == nsteps)
300 amid = ahigh;
301
302 const double da = (std::pow(ahigh, timestep_cola_nLPT) - std::pow(alow, timestep_cola_nLPT)) /
303 (timestep_cola_nLPT * std::pow(amid, timestep_cola_nLPT - 1.0));
304 return da / (amid * amid * amid * cosmo->HoverH0_of_a(amid));
305 };
306
307 //=====================================================
308 // Timestep for a kick-step: Quinn et al.
309 //=====================================================
310 auto compute_kick_timestep_quinn = [&](double alow, double ahigh, int istep, int nsteps) {
311 double amid = (ahigh + alow) / 2.;
312
313 if (istep == 0)
314 amid = alow;
315 else if (istep == nsteps)
316 amid = ahigh;
317
318 ODEFunction deriv = [&](double a, [[maybe_unused]] const double * t, double * dtda) {
319 dtda[0] = 1.0 / (a * a * a * cosmo->HoverH0_of_a(a)) * poisson_factor(a) / poisson_factor(amid);
320 return GSL_SUCCESS;
321 };
322
323 // Solve the integral
324 DVector tini{0.0};
325 DVector avec{alow, ahigh};
326 ODESolver ode;
327 ode.solve(deriv, avec, tini);
328 return ode.get_final_data()[0];
329 };
330
331 //=====================================================
332 // Timestep for a drift-step: Tassev et al.
333 //=====================================================
334 auto compute_drift_timestep_tassev =
335 [&](double alow, double ahigh, [[maybe_unused]] int istep, [[maybe_unused]] int nsteps) {
336 double amid = (ahigh + alow) / 2.;
337
338 ODEFunction deriv = [&](double a, [[maybe_unused]] const double * t, double * dtda) {
339 dtda[0] = 1.0 / (a * a * a * cosmo->HoverH0_of_a(a));
340 dtda[0] *= std::pow(a / amid, timestep_cola_nLPT);
341 return GSL_SUCCESS;
342 };
343
344 // Solve the integral
345 DVector tini{0.0};
346 DVector avec{alow, ahigh};
347 ODESolver ode;
348 ode.solve(deriv, avec, tini);
349 return ode.get_final_data()[0];
350 };
351
352 //=====================================================
353 // Timestep for a drift-step: Quinn et al.
354 //=====================================================
355 auto compute_drift_timestep_quinn =
356 [&](double alow, double ahigh, [[maybe_unused]] int istep, [[maybe_unused]] int nsteps) {
357 ODEFunction deriv = [&](double a, [[maybe_unused]] const double * t, double * dtda) {
358 dtda[0] = 1.0 / (a * a * a * cosmo->HoverH0_of_a(a));
359 return GSL_SUCCESS;
360 };
361
362 // Solve the integral
363 DVector tini{0.0};
364 DVector avec{alow, ahigh};
365 ODESolver ode;
366 ode.solve(deriv, avec, tini);
367 return ode.get_final_data()[0];
368 };
369
370 //=====================================================
371 // Select the method to use
372 //=====================================================
373 auto compute_drift_timestep = [&](double alow, double ahigh, int istep, int nsteps) {
374 if (timestep_method == "Quinn") {
375 return compute_drift_timestep_quinn(alow, ahigh, istep, nsteps);
376 } else if (timestep_method == "Tassev") {
377 return compute_drift_timestep_tassev(alow, ahigh, istep, nsteps);
378 } else {
379 throw std::runtime_error("Unknown timestep_method [" + timestep_method + "]");
380 }
381 };
382 auto compute_kick_timestep = [&](double alow, double ahigh, int istep, int nsteps) {
383 if (timestep_method == "Quinn") {
384 return compute_kick_timestep_quinn(alow, ahigh, istep, nsteps);
385 } else if (timestep_method == "Tassev") {
386 return compute_kick_timestep_tassev(alow, ahigh, istep, nsteps);
387 } else {
388 throw std::runtime_error("Unknown timestep_method [" + timestep_method + "]");
389 }
390 };
391
392 //=====================================================
393 // Select the spacing between steps
394 //=====================================================
395 auto scale_factor_of_step = [&](double i) {
396 if (timestep_scalefactor_spacing == "linear") {
397 return amin + (amax - amin) * i / double(nsteps);
398 } else if (timestep_scalefactor_spacing == "logarithmic") {
399 return std::exp(std::log(amin) + std::log(amax / amin) * i / double(nsteps));
400 } else if (timestep_scalefactor_spacing == "powerlaw") {
401 double n = timestep_spacing_power;
402 return amin * std::pow(1.0 + (std::pow(amax / amin, n) - 1.0) * i / double(nsteps), 1.0 / n);
403 } else {
404 throw std::runtime_error("Unknown timestep_scalefactor_spacing [" + timestep_scalefactor_spacing + "]");
405 }
406 };
407
408 //=====================================================
409 // Timesteps: first step we displace pos and vel by 1/2 timestep to do leapfrog
410 // Last time-step we synchronize back by only moving vel
411 //=====================================================
412 std::vector<double> delta_time_drift;
413 std::vector<double> delta_time_kick;
414 std::vector<double> pos_timestep;
415 std::vector<double> vel_timestep;
416 pos_timestep.push_back(amin);
417 vel_timestep.push_back(amin);
418 for (int i = 0; i <= nsteps; i++) {
419 double apos_old = scale_factor_of_step(i);
420 double apos_new = (i == nsteps) ? amax : scale_factor_of_step(i + 1.0);
421 double avel_old = (i == 0) ? amin : scale_factor_of_step(i - 0.5);
422 double avel_new = (i == 0) ? scale_factor_of_step(0.5) : (i == nsteps ? amax : scale_factor_of_step(i + 0.5));
423 delta_time_drift.push_back(compute_drift_timestep(apos_old, apos_new, i, nsteps));
424 delta_time_kick.push_back(compute_kick_timestep(avel_old, avel_new, i, nsteps));
425 pos_timestep.push_back(apos_new);
426 vel_timestep.push_back(avel_old);
427 }
428 return {delta_time_drift, delta_time_kick};
429}
430
431template <int NDIM, class T>
432std::pair<std::vector<double>, std::vector<double>>
434
435 //=====================================================
436 // Select the spacing between steps
437 //=====================================================
438 auto scale_factor_of_step = [&](double i) {
439 if (nsteps == 0)
440 return amin;
441 if (timestep_scalefactor_spacing == "linear") {
442 return amin + (amax - amin) * i / double(nsteps);
443 } else if (timestep_scalefactor_spacing == "logarithmic") {
444 return std::exp(std::log(amin) + std::log(amax / amin) * i / double(nsteps));
445 } else if (timestep_scalefactor_spacing == "powerlaw") {
446 return amin + (amax - amin) * std::pow(i / double(nsteps), timestep_spacing_power);
447 } else {
448 throw std::runtime_error("Unknown timestep_scalefactor_spacing [" + timestep_scalefactor_spacing + "]");
449 }
450 };
451
452 std::vector<double> scalefactor_pos;
453 std::vector<double> scalefactor_vel;
454 scalefactor_pos.push_back(amin);
455 scalefactor_vel.push_back(amin);
456 for (int i = 0; i <= nsteps; i++) {
457 double apos_new = (i == nsteps) ? amax : scale_factor_of_step(i + 1.0);
458 double avel_new = (i == 0) ? scale_factor_of_step(0.5) : (i == nsteps ? amax : scale_factor_of_step(i + 0.5));
459 scalefactor_pos.push_back(apos_new);
460 scalefactor_vel.push_back(avel_new);
461 }
462 return {scalefactor_pos, scalefactor_vel};
463}
464
465template <int NDIM, class T>
467
468 parameters = std::make_shared<ParameterMap>(param);
469
470 if (FML::ThisTask == 0) {
471 std::cout << "\n";
472 std::cout << "#=====================================================\n";
473 std::cout << "# NBodySimulation::read_parameters\n";
474 std::cout << "#=====================================================\n\n";
475 }
476
477 // General parameters
478 simulation_name = param.get<std::string>("simulation_name");
479 simulation_boxsize = param.get<double>("simulation_boxsize");
480 simulation_use_cola = param.get<bool>("simulation_use_cola");
481 simulation_use_scaledependent_cola = param.get<bool>("simulation_use_scaledependent_cola");
482
483 if (FML::ThisTask == 0) {
484 std::cout << "simulation_name : " << simulation_name << "\n";
485 std::cout << "simulation_boxsize : " << simulation_boxsize << "\n";
486 std::cout << "simulation_use_cola : " << simulation_use_cola << "\n";
487 std::cout << "simulation_use_scaledependent_cola : " << simulation_use_scaledependent_cola << "\n";
488
489 // We cannot use COLA if the particle type is not compatible with it
490 if (simulation_use_cola and not FML::PARTICLE::has_get_D_1LPT<T>()) {
491 throw std::runtime_error("Set to use COLA, but particle-type does not even have 1LPT growthfactors!");
492 }
493 }
494
495 // Computing forces
496 force_nmesh = param.get<int>("force_nmesh");
497 force_density_assignment_method = param.get<std::string>("force_density_assignment_method");
498 force_kernel = param.get<std::string>("force_kernel");
499 force_linear_massive_neutrinos = param.get<bool>("force_linear_massive_neutrinos");
500
501 if (FML::ThisTask == 0) {
502 std::cout << "force_nmesh : " << force_nmesh << "\n";
503 std::cout << "force_kernel : " << force_kernel << "\n";
504 std::cout << "force_density_assignment_method : " << force_density_assignment_method << "\n";
505 std::cout << "force_linear_massive_neutrinos : " << force_linear_massive_neutrinos << "\n";
506 }
507
508 // Initial conditions
509 ic_type_of_input = param.get<std::string>("ic_type_of_input");
510 ic_input_filename = param.get<std::string>("ic_input_filename");
511 ic_random_field_type = param.get<std::string>("ic_random_field_type");
512 ic_input_redshift = param.get<double>("ic_input_redshift");
513 ic_use_gravity_model_GR = param.get<bool>("ic_use_gravity_model_GR");
514 ic_initial_redshift = param.get<double>("ic_initial_redshift");
515 ic_nmesh = param.get<int>("ic_nmesh");
516 ic_random_seed = param.get<int>("ic_random_seed");
517 ic_random_generator = param.get<std::string>("ic_random_generator");
518 ic_LPT_order = param.get<int>("ic_LPT_order");
519 ic_fix_amplitude = param.get<bool>("ic_fix_amplitude");
520 ic_reverse_phases = param.get<bool>("ic_reverse_phases");
521 if (ic_random_field_type == "nongaussian") {
522 ic_fnl_type = param.get<std::string>("ic_fnl_type");
523 ic_fnl = param.get<double>("ic_fnl");
524 ic_fnl_redshift = param.get<double>("ic_fnl_redshift");
525 }
526 ic_sigma8_normalization = param.get<bool>("ic_sigma8_normalization");
527 if (ic_sigma8_normalization) {
528 ic_sigma8_redshift = param.get<double>("ic_sigma8_redshift");
529 ic_sigma8 = param.get<double>("ic_sigma8");
530 }
531 if (ic_random_field_type == "read_particles") {
532 ic_reconstruct_gadgetfilepath = param.get<std::string>("ic_reconstruct_gadgetfilepath");
533 ic_reconstruct_assigment_method = param.get<std::string>("ic_reconstruct_assigment_method");
534 ic_reconstruct_smoothing_filter = param.get<std::string>("ic_reconstruct_smoothing_filter");
535 ic_reconstruct_dimless_smoothing_scale = param.get<double>("ic_reconstruct_dimless_smoothing_scale");
536 ic_reconstruct_interlacing = param.get<bool>("ic_reconstruct_interlacing");
537 }
538
539 if (FML::ThisTask == 0) {
540 std::cout << "ic_type_of_input : " << ic_type_of_input << "\n";
541 std::cout << "ic_input_filename : " << ic_input_filename << "\n";
542 std::cout << "ic_random_field_type : " << ic_random_field_type << "\n";
543 std::cout << "ic_input_redshift : " << ic_input_redshift << "\n";
544 std::cout << "ic_nmesh : " << ic_nmesh << "\n";
545 std::cout << "ic_random_seed : " << ic_random_seed << "\n";
546 std::cout << "ic_random_generator : " << ic_random_generator << "\n";
547 std::cout << "ic_LPT_order : " << ic_LPT_order << "\n";
548 std::cout << "ic_fix_amplitude : " << ic_fix_amplitude << "\n";
549 std::cout << "ic_reverse_phases : " << ic_reverse_phases << "\n";
550 if (ic_random_field_type == "nongaussian") {
551 std::cout << "ic_fnl_type : " << ic_fnl_type << "\n";
552 std::cout << "ic_fnl : " << ic_fnl << "\n";
553 }
554 if (ic_sigma8_normalization) {
555 std::cout << "ic_sigma8 : " << ic_sigma8 << "\n";
556 std::cout << "ic_sigma8_redshift : " << ic_sigma8_redshift << "\n";
557 }
558 if (ic_random_field_type == "read_particles") {
559 std::cout << "ic_reconstruct_gadgetfilepath : " << ic_reconstruct_gadgetfilepath << "\n";
560 std::cout << "ic_reconstruct_assigment_method : " << ic_reconstruct_assigment_method << "\n";
561 std::cout << "ic_reconstruct_smoothing_filter : " << ic_reconstruct_smoothing_filter << "\n";
562 std::cout << "ic_reconstruct_dimless_smoothing_scale : " << ic_reconstruct_dimless_smoothing_scale
563 << "\n";
564 std::cout << "ic_reconstruct_interlacing : " << ic_reconstruct_interlacing << "\n";
565 }
566 }
567
568 // Particles
569 particle_Npart_1D = param.get<int>("particle_Npart_1D");
570 particle_allocation_factor = param.get<double>("particle_allocation_factor");
571
572 if (FML::ThisTask == 0) {
573 std::cout << "ic_type_of_input : " << ic_type_of_input << "\n";
574 std::cout << "particle_Npart_1D : " << particle_Npart_1D << "\n";
575 std::cout << "particle_allocation_factor : " << particle_allocation_factor << "\n";
576 }
577
578 // Timestepping
579 timestep_nsteps = param.get<std::vector<int>>("timestep_nsteps");
580 timestep_method = param.get<std::string>("timestep_method");
581 timestep_algorithm = param.get<std::string>("timestep_algorithm");
582 timestep_cola_nLPT = param.get<double>("timestep_cola_nLPT");
583 timestep_scalefactor_spacing = param.get<std::string>("timestep_scalefactor_spacing");
584 if (timestep_scalefactor_spacing == "powerlaw") {
585 timestep_spacing_power = param.get<double>("timestep_spacing_power");
586 }
587
588 if (FML::ThisTask == 0) {
589 std::cout << "timestep_nsteps : ";
590 for (auto & n : timestep_nsteps)
591 std::cout << n << " ";
592 std::cout << "\n";
593 std::cout << "timestep_method : " << timestep_method << "\n";
594 std::cout << "timestep_algorithm : " << timestep_algorithm << "\n";
595 std::cout << "timestep_scalefactor_spacing : " << timestep_scalefactor_spacing << "\n";
596 if (timestep_method == "Tassev") {
597 std::cout << "timestep_cola_nLPT : " << timestep_cola_nLPT << "\n";
598 }
599 if (timestep_scalefactor_spacing == "powerlaw") {
600 std::cout << "timestep_spacing_power : " << timestep_spacing_power << "\n";
601 }
602 }
603
604 // FoF halofinding
605 fof = param.get<bool>("fof");
606 if (fof) {
607 fof_nmin_per_halo = param.get<int>("fof_nmin_per_halo");
608 fof_linking_length = param.get<double>("fof_linking_length");
609 fof_nmesh_max = param.get<int>("fof_nmesh_max");
610 fof_buffer_length_mpch = param.get<double>("fof_buffer_length_mpch");
611
612 if (FML::ThisTask == 0) {
613 std::cout << "fof : " << fof << "\n";
614 std::cout << "fof_nmin_per_halo : " << fof_nmin_per_halo << "\n";
615 std::cout << "fof_linking_length : " << fof_linking_length << "\n";
616 std::cout << "fof_nmesh_max : " << fof_nmesh_max << "\n";
617 std::cout << "fof_buffer_length_mpch : " << fof_buffer_length_mpch << "\n";
618 }
619 }
620
621 // Powerspectrum
622 pofk = param.get<bool>("pofk");
623 if (pofk) {
624 pofk_nmesh = param.get<int>("pofk_nmesh");
625 pofk_interlacing = param.get<bool>("pofk_interlacing");
626 pofk_subtract_shotnoise = param.get<bool>("pofk_subtract_shotnoise");
627 pofk_density_assignment_method = param.get<std::string>("pofk_density_assignment_method");
628
629 if (FML::ThisTask == 0) {
630 std::cout << "pofk : " << pofk << "\n";
631 std::cout << "pofk_nmesh : " << pofk_nmesh << "\n";
632 std::cout << "pofk_interlacing : " << pofk_interlacing << "\n";
633 std::cout << "pofk_subtract_shotnoise : " << pofk_subtract_shotnoise << "\n";
634 std::cout << "pofk_density_assignment_method : " << pofk_density_assignment_method << "\n";
635 }
636 }
637
638 // Powerspectrum multipoles
639 pofk_multipole = param.get<bool>("pofk_multipole");
640 if (pofk_multipole) {
641 pofk_multipole_nmesh = param.get<int>("pofk_multipole_nmesh");
642 pofk_multipole_interlacing = param.get<bool>("pofk_multipole_interlacing");
643 pofk_multipole_subtract_shotnoise = param.get<bool>("pofk_multipole_subtract_shotnoise");
644 pofk_multipole_ellmax = param.get<int>("pofk_multipole_ellmax");
645 pofk_multipole_density_assignment_method = param.get<std::string>("pofk_multipole_density_assignment_method");
646
647 if (FML::ThisTask == 0) {
648 std::cout << "pofk_multipole : " << pofk_multipole << "\n";
649 std::cout << "pofk_multipole_nmesh : " << pofk_multipole_nmesh << "\n";
650 std::cout << "pofk_multipole_interlacing : " << pofk_multipole_interlacing << "\n";
651 std::cout << "pofk_multipole_subtract_shotnoise : " << pofk_multipole_subtract_shotnoise << "\n";
652 std::cout << "pofk_multipole_ellmax : " << pofk_multipole_ellmax << "\n";
653 std::cout << "pofk_multipole_density_assignment_method : " << pofk_multipole_density_assignment_method
654 << "\n";
655 }
656 }
657
658 // Bispectrum
659 bispectrum = param.get<bool>("bispectrum");
660 if (bispectrum) {
661 bispectrum_nmesh = param.get<int>("bispectrum_nmesh");
662 bispectrum_nbins = param.get<int>("bispectrum_nbins");
663 bispectrum_density_assignment_method = param.get<std::string>("bispectrum_density_assignment_method");
664 bispectrum_interlacing = param.get<bool>("bispectrum_interlacing");
665 bispectrum_subtract_shotnoise = param.get<bool>("bispectrum_subtract_shotnoise");
666
667 if (FML::ThisTask == 0) {
668 std::cout << "bispectrum : " << bispectrum << "\n";
669 std::cout << "bispectrum_nmesh : " << bispectrum_nmesh << "\n";
670 std::cout << "bispectrum_nbins : " << bispectrum_nbins << "\n";
671 std::cout << "bispectrum_density_assignment_method : " << bispectrum_density_assignment_method << "\n";
672 std::cout << "bispectrum_interlacing : " << bispectrum_interlacing << "\n";
673 std::cout << "bispectrum_subtract_shotnoise : " << bispectrum_subtract_shotnoise << "\n";
674 }
675 }
676
677 // Output
678 output_redshifts = param.get<std::vector<double>>("output_redshifts");
679 output_particles = param.get<bool>("output_particles");
680 output_fileformat = param.get<std::string>("output_fileformat");
681 output_folder = param.get<std::string>("output_folder");
682
683 if (FML::ThisTask == 0) {
684 std::cout << "output_particles : " << output_particles << "\n";
685 std::cout << "output_redshifts : ";
686 for (auto & z : output_redshifts)
687 std::cout << z << " , ";
688 std::cout << "\n";
689 std::cout << "output_fileformat : " << output_fileformat << "\n";
690 std::cout << "output_folder : " << output_folder << "\n";
691 }
692}
693
694template <int NDIM, class T>
696
697 if (FML::ThisTask == 0) {
698 std::cout << "\n";
699 std::cout << "#=====================================================\n";
700 std::cout << "# Create initial conditions\n";
701 std::cout << "#=====================================================\n";
702 }
703
704 // Empty output_folder means to output to current directory. Otherwise make folder
705 if (output_folder != "") {
706 if (not FML::create_folder(output_folder)) {
707 throw std::runtime_error("Cannot create output directory [" + output_folder + "]");
708 }
709 }
710
711 //=============================================================
712 // Output the cosmology and growth functions
713 //=============================================================
714 if (FML::ThisTask == 0) {
715 std::string cosmoprefix = output_folder;
716 std::string gravprefix = output_folder;
717 cosmoprefix = cosmoprefix + (cosmoprefix == "" ? "" : "/") + "cosmology_" + simulation_name;
718 gravprefix = gravprefix + (gravprefix == "" ? "" : "/") + "gravitymodel_" + simulation_name;
719 cosmo->output(cosmoprefix + ".txt");
720 grav->output(gravprefix + "_k0.00001.txt", 1e-5 / grav->H0_hmpc);
721 grav->output(gravprefix + "_k0.0001.txt", 1e-4 / grav->H0_hmpc);
722 grav->output(gravprefix + "_k0.001.txt", 1e-3 / grav->H0_hmpc);
723 grav->output(gravprefix + "_k0.01.txt", 1e-2 / grav->H0_hmpc);
724 grav->output(gravprefix + "_k0.1.txt", 1e-1 / grav->H0_hmpc);
725 grav->output(gravprefix + "_k1.0.txt", 1e+0 / grav->H0_hmpc);
726 grav->output(gravprefix + "_k10.0.txt", 1e+1 / grav->H0_hmpc);
727 }
728
729 //=============================================================
730 // Read in power-spectra / transfer function
731 // Make spline of P(k,zini) and T(k,zini)
732 // If the input it at a different redshift we use growth-factor
733 // to bring it to the initial time
734 //=============================================================
735
736 DVector karr;
738 DVector power_primordial;
739 DVector transfer;
740
741 // If we have a MG model and want exactly the same IC as for LCDM
742 // we can supply LCDM P(k) and use the GR growth factors to scale it back
743 std::shared_ptr<GravityModel<NDIM>> grav_ic;
744 if (ic_use_gravity_model_GR) {
745 grav_ic = std::make_shared<GravityModelGR<NDIM>>(cosmo);
746 grav_ic->read_parameters(*parameters);
747 grav_ic->init();
748 } else {
749 grav_ic = grav;
750 }
751
752 if (ic_type_of_input == "powerspectrum") {
753
754 // Fileformat: [k (h/Mpc) P(k) (Mpc/h)^3]
755 const int ncols = 2;
756 const int col_k = 0;
757 const int col_pofk = 1;
758 std::vector<int> cols_to_keep{col_k, col_pofk};
759 const int nheaderlines = 1;
760 auto pofkdata = FML::FILEUTILS::read_regular_ascii(ic_input_filename, ncols, cols_to_keep, nheaderlines);
761
762 karr.resize(pofkdata.size());
763 power.resize(pofkdata.size());
764 transfer.resize(pofkdata.size());
765 power_primordial.resize(pofkdata.size());
766
767 // Read in power-spectrum, compute transfer function
768 // And use growth functions to translate it to initial redshift
769 const double ainput = 1.0 / (1.0 + ic_input_redshift);
770 const double aini = 1.0 / (1.0 + ic_initial_redshift);
771 for (size_t i = 0; i < karr.size(); i++) {
772 karr[i] = pofkdata[i][0];
773 double k_hmpc = karr[i];
774 double k_mpc = karr[i] * cosmo->get_h();
775 double DinioverDinput = grav_ic->get_D_1LPT(aini, k_hmpc / grav_ic->H0_hmpc) /
776 grav_ic->get_D_1LPT(ainput, k_hmpc / grav_ic->H0_hmpc);
777 power_primordial[i] = cosmo->get_primordial_pofk(k_hmpc);
778 power[i] = DinioverDinput * DinioverDinput * pofkdata[i][1];
779 transfer[i] = std::sqrt(power[i] / power_primordial[i]) / (k_mpc * k_mpc);
780 }
781
782 if (FML::ThisTask == 0) {
783 std::cout << "\n";
784 std::cout << "#=====================================================\n";
785 std::cout << "# Reading power-spectrum from ascii file [" << ic_input_filename << "]\n";
786 std::cout << "# The P(k) is at the redshift: " << ic_input_redshift << "\n";
787 std::cout << "# Using growth factors we scaled it to redshift: " << ic_initial_redshift << "\n";
788 std::cout << "# Found n: " << power.size() << " lines in file (sample of it below):\n";
789 std::cout << "#=====================================================\n";
790 std::cout << "# k (h/Mpc) P(k,zini) (Mpc/h)^3 T(k,zini) (Mpc)^2\n";
791 for (size_t i = 0; i < karr.size(); i++) {
792 if (i % (karr.size() / 10) == 0) {
793 std::cout << std::setw(15) << karr[i] << " ";
794 std::cout << std::setw(15) << power[i] << " ";
795 std::cout << std::setw(15) << transfer[i] << "\n";
796 }
797 }
798 }
799
800 } else if (ic_type_of_input == "transferfunction") {
801
802 // Fileformat: [k (h/Mpc) T(k) (Mpc)^2] (change below)
803 const int ncols = 2;
804 const int col_k = 0;
805 const int col_tofk = 1;
806 std::vector<int> cols_to_keep{col_k, col_tofk};
807 const int nheaderlines = 1;
808 auto tofkdata = FML::FILEUTILS::read_regular_ascii(ic_input_filename, ncols, cols_to_keep, nheaderlines);
809
810 karr.resize(tofkdata.size());
811 power.resize(tofkdata.size());
812 transfer.resize(tofkdata.size());
813 power_primordial.resize(tofkdata.size());
814
815 // Read in transfer function, compute power-spectrum
816 // And use growth functions to translate it to initial redshift
817 const double ainput = 1.0 / (1.0 + ic_input_redshift);
818 const double aini = 1.0 / (1.0 + ic_initial_redshift);
819 for (size_t i = 0; i < karr.size(); i++) {
820 karr[i] = tofkdata[i][0];
821 double k_hmpc = karr[i];
822 double k_mpc = karr[i] * cosmo->get_h();
823 double DinioverDinput = grav_ic->get_D_1LPT(aini, k_hmpc / grav_ic->H0_hmpc) /
824 grav_ic->get_D_1LPT(ainput, k_hmpc / grav_ic->H0_hmpc);
825 power_primordial[i] = cosmo->get_primordial_pofk(k_hmpc);
826 transfer[i] = DinioverDinput * tofkdata[i][1];
827 power[i] = power_primordial[i] * std::pow(transfer[i] * k_mpc * k_mpc, 2);
828 }
829
830 if (FML::ThisTask == 0) {
831 std::cout << "\n";
832 std::cout << "#=====================================================\n";
833 std::cout << "# Reading transfer function from ascii file [" << ic_input_filename << "]\n";
834 std::cout << "# The T(k) is at the redshift: " << ic_input_redshift << "\n";
835 std::cout << "# Using growth factors we scaled it to redshift: " << ic_initial_redshift << "\n";
836 std::cout << "# Found n: " << power.size() << " lines in file (sample of it below)\n";
837 std::cout << "#=====================================================\n";
838 std::cout << "# k (h/Mpc) P(k,zini) (Mpc/h)^3 T(k,zini) (Mpc)^2:\n";
839 for (size_t i = 0; i < karr.size(); i++) {
840 if (i % (karr.size() / 10) == 0) {
841 std::cout << std::setw(15) << karr[i] << " ";
842 std::cout << std::setw(15) << power[i] << " ";
843 std::cout << std::setw(15) << transfer[i] << "\n";
844 }
845 }
846 }
847
848 } else if (ic_type_of_input == "transferinfofile") {
849
850 // Read in all transfer functions T_i(k,z) unless we already have done so in the gravity-model
851 // and in that case fetch it from there
852 transferdata = grav->get_transferdata();
853 if (not transferdata) {
854 transferdata = std::make_shared<LinearTransferData>(cosmo->get_Omegab(),
855 cosmo->get_OmegaCDM(),
856 cosmo->get_kpivot_mpc(),
857 cosmo->get_As(),
858 cosmo->get_ns(),
859 cosmo->get_h());
860 transferdata->read_transfer(ic_input_filename);
861
862 // Make sure the gravity model also gets a pointer to this
863 grav->set_transferdata(transferdata);
864 }
865
866 // Create the arrays. For consistency we generate them at ic_input_redshift
867 // and use growth-factors to the initial time (this way we can pick backscaling or not
868 // by selecting ic_input_redshift)
869 const int nk = 1000;
870 const double kmin = transferdata->get_kmin_hmpc_splines();
871 const double kmax = transferdata->get_kmax_hmpc_splines();
872 const double ainput = 1.0 / (1.0 + ic_input_redshift);
873 const double aini = 1.0 / (1.0 + ic_initial_redshift);
874 karr.resize(nk);
875 power.resize(nk);
876 power_primordial.resize(nk);
877 transfer.resize(nk);
878 for (size_t i = 0; i < karr.size(); i++) {
879 const double k_hmpc = std::exp(std::log(kmin) + std::log(kmax / kmin) * i / double(nk));
880 karr[i] = k_hmpc;
881 transfer[i] = transferdata->get_cdm_baryon_transfer_function(karr[i], ainput);
882 power[i] = transferdata->get_cdm_baryon_power_spectrum(karr[i], ainput);
883 double DinioverDinput = grav_ic->get_D_1LPT(aini, k_hmpc / grav_ic->H0_hmpc) /
884 grav_ic->get_D_1LPT(ainput, k_hmpc / grav_ic->H0_hmpc);
885 power_primordial[i] = cosmo->get_primordial_pofk(k_hmpc);
886 transfer[i] *= DinioverDinput;
887 power[i] *= DinioverDinput * DinioverDinput;
888 }
889
890 } else {
891 throw std::runtime_error("Unknown ic type[" + ic_type_of_input + "]");
892 }
893 power_initial_spline.create(karr, power, "P(k,zini)");
894 power_primordial_spline.create(karr, power_primordial, "P_primordial(k)");
895 transfer_initial_spline.create(karr, transfer, "T(k,zini)");
896
897 if (FML::ThisTask == 0) {
898 std::cout << "\n";
899 std::cout << "#=====================================================\n";
900 std::cout << "# Testing splines: \n";
901 std::cout << "#=====================================================\n";
902 std::cout << "k = 0.01: P(k,zini) = " << power_initial_spline(0.01) << " (Mpc/h)^3\n";
903 std::cout << "k = 0.10: P(k,zini) = " << power_initial_spline(0.1) << " (Mpc/h)^3\n";
904 std::cout << "k = 1.00: P(k,zini) = " << power_initial_spline(1.0) << " (Mpc/h)^3\n";
905 std::cout << "k = 10.00: P(k,zini) = " << power_initial_spline(10.0) << " (Mpc/h)^3\n";
906
907 // Check for NaN
908 FML::assert_mpi(power_initial_spline(0.01) == power_initial_spline(0.01), "NaN detected");
909 }
910
911 // Make some functions we need below to compute sigma(R,z)
912 auto pofk_today_over_volume = [&](double kBox) {
913 double D_today = grav_ic->get_D_1LPT(1.0, kBox / simulation_boxsize / grav_ic->H0_hmpc);
914 double D_initial =
915 grav_ic->get_D_1LPT(1.0 / (1.0 + ic_initial_redshift), kBox / simulation_boxsize / grav_ic->H0_hmpc);
916 return std::pow(D_today / D_initial, 2) * power_initial_spline(kBox / simulation_boxsize) /
917 std::pow(simulation_boxsize, NDIM);
918 };
919 auto pofk_atnormtime_over_volume = [&](double kBox) {
920 double D_normtime =
921 grav_ic->get_D_1LPT(1.0 / (1.0 + ic_sigma8_redshift), kBox / simulation_boxsize / grav_ic->H0_hmpc);
922 double D_initial =
923 grav_ic->get_D_1LPT(1.0 / (1.0 + ic_initial_redshift), kBox / simulation_boxsize / grav_ic->H0_hmpc);
924 return std::pow(D_normtime / D_initial, 2) * power_initial_spline(kBox / simulation_boxsize) /
925 std::pow(simulation_boxsize, NDIM);
926 };
927
928 // Compute sigma8 today and at the redshift we want to normalize
929 const double sigma8_today = FML::NBODY::compute_sigma_of_R(pofk_today_over_volume, 8.0, simulation_boxsize);
930 const double sigma8 = FML::NBODY::compute_sigma_of_R(pofk_atnormtime_over_volume, 8.0, simulation_boxsize);
931
932 // If we are to normalize P(k) according to a given sigma8 value
933 const double pofk_norm_factor = ic_sigma8_normalization ? std::pow(ic_sigma8 / sigma8, 2) : 1.0;
934
935 // If we normalize wrt sigma8 we need to update the splines, the transfer data and the cosmology
936 if (pofk_norm_factor != 1.0) {
937 for (auto & p : power) {
938 p *= pofk_norm_factor;
939 }
940 for (auto & p : power_primordial) {
941 p *= pofk_norm_factor;
942 }
943 for (auto & t : transfer) {
944 t *= std::sqrt(pofk_norm_factor);
945 }
946 power_initial_spline.create(karr, power, "P(k,zini) sigma8 normalized");
947 power_primordial_spline.create(karr, power_primordial, "P_primordial(k,zini) sigma8 normalized");
948 transfer_initial_spline.create(karr, transfer, "T(k,zini) sigma8 normalized");
949
950 // Update transfer data. This also updates data in gravity model (as its the same object)
951 if (transferdata) {
952 transferdata->set_As(transferdata->get_As() * pofk_norm_factor);
953 }
954 // Update this value in the cosmology
955 cosmo->set_As(cosmo->get_As() * pofk_norm_factor);
956
957 // Print updated info
958 if (FML::ThisTask == 0) {
959 std::cout << "\n";
960 std::cout << "#=====================================================\n";
961 std::cout << "Updated cosmology and gravitymodel to reflect change of As:\n";
962 std::cout << "#=====================================================\n";
963 cosmo->info();
964 grav->info();
965 }
966 }
967
968 // Compute sigma(R) today. Also good to compute deltac. Then use this to estimate mass-function
969 // which we can output together with the result from the FoF
970 auto make_sigma_spline = [&]() {
971 const int nr = 30;
972 const double Rmin_mpch = 0.01;
973 const double Rmax_mpch = 100.0;
974 DVector R_mpch(nr);
975 DVector sigma(nr);
976 for (int i = 0; i < nr; i++) {
977 R_mpch[i] = std::exp(std::log(Rmin_mpch) + std::log(Rmax_mpch / Rmin_mpch) * i / double(nr));
978 sigma[i] = FML::NBODY::compute_sigma_of_R(pofk_today_over_volume, R_mpch[i], simulation_boxsize);
979 }
980 return Spline(R_mpch, sigma, "sigma(R_mpch,z=0.0)");
981 };
982 auto sigma_spline = make_sigma_spline();
983
984 if (FML::ThisTask == 0) {
985 std::cout << "\n";
986 std::cout << "#=====================================================\n";
987 std::cout << "# Sigma(R = 8 Mpc/h, z = 0.0 ) : " << std::setw(15) << sigma8_today << "\n";
988 if (ic_sigma8_normalization) {
989 std::cout << "# We will normalize to Sigma8 = " << std::setw(15) << ic_sigma8 << " at z = " << std::setw(15)
990 << ic_sigma8_redshift << "\n";
991 std::cout << "# New Sigma(R = 8 Mpc/h, z = 0.0 ) : " << std::setw(15)
992 << sigma8_today * std::sqrt(pofk_norm_factor) << "\n";
993 std::cout << "# <delta^2> = "
994 << sigma_spline(simulation_boxsize / ic_nmesh) *
995 grav_ic->get_D_1LPT(1.0 / (1.0 + ic_initial_redshift)) /
996 grav_ic->get_D_1LPT(1.0 / (1.0 + 0.0))
997 << "\n";
998 }
999 std::cout << "#=====================================================\n";
1000 }
1001
1002 //=============================================================
1003 // Generate initial conditions
1004 //=============================================================
1005
1006 // Set up random generator
1007 std::shared_ptr<RandomGenerator> rng;
1008 if (ic_random_generator == "GSL")
1009 rng = std::make_shared<GSLRandomGenerator>();
1010 else if (ic_random_generator == "MT19937")
1011 rng = std::make_shared<RandomGenerator>();
1012 else
1013 throw std::runtime_error("Unknown random generator " + ic_random_generator);
1014 rng->set_seed(ic_random_seed);
1015
1016 // Make a grid for holding the initial density field
1018 FFTWGrid<NDIM> delta_ini_fourier(ic_nmesh, nextra.first, nextra.second);
1019 delta_ini_fourier.add_memory_label("delta_ini_fourier(k)");
1020 delta_ini_fourier.set_grid_status_real(false);
1021
1022 // Make a gaussian or non-local non-gaussian random field in fourier space
1023 // We generate it at the initial redshift
1024 timer.StartTiming("InitialDensityField");
1025 if (ic_random_field_type == "gaussian") {
1026
1027 auto Pofk_of_kBox_over_volume = [&](double kBox) {
1028 return power_initial_spline(kBox / simulation_boxsize) / std::pow(simulation_boxsize, NDIM);
1029 };
1030 FML::RANDOM::GAUSSIAN::generate_gaussian_random_field_fourier<NDIM>(
1031 delta_ini_fourier, rng.get(), Pofk_of_kBox_over_volume, ic_fix_amplitude);
1032
1033 } else if (ic_random_field_type == "nongaussian") {
1034
1035 // The power-spectrum of the Bardeen potential (-Phi) at the given redshift
1036 const double afnl = 1.0 / (1.0 + ic_fnl_redshift);
1037 const double H0Box = simulation_boxsize * grav_ic->H0_hmpc;
1038 const double factor = 1.5 * cosmo->get_OmegaM() / afnl;
1039 auto Pofk_of_kBox_over_volume_primordial = [&](double kBox) {
1040 return power_primordial_spline(kBox / simulation_boxsize) / std::pow(simulation_boxsize, NDIM) *
1041 std::pow(factor * grav_ic->get_D_1LPT(afnl, kBox / H0Box) / grav_ic->get_D_1LPT(1.0, kBox / H0Box),
1042 2);
1043 };
1044 // The product of this and the function above is the initial power-spectrum for delta
1045 auto Pofk_of_kBox_over_Pofk_primordal = [&](double kBox) {
1046 return power_initial_spline(kBox / simulation_boxsize) / std::pow(simulation_boxsize, NDIM) /
1047 Pofk_of_kBox_over_volume_primordial(kBox);
1048 };
1050 delta_ini_fourier,
1051 rng.get(),
1052 Pofk_of_kBox_over_Pofk_primordal,
1053 Pofk_of_kBox_over_volume_primordial,
1054 ic_fix_amplitude,
1055 ic_fnl,
1056 ic_fnl_type);
1057
1058 } else if (ic_random_field_type == "read_particles") {
1059 // Do nothing, we read in particles below this below
1060 } else {
1061 throw std::runtime_error("Unknown ic_random_field_type [" + ic_random_field_type + "]");
1062 }
1063 timer.EndTiming("InitialDensityField");
1064
1065 // Reverse the phases? For doing pair-fixed simulations
1066 if (ic_reverse_phases) {
1067 auto Local_nx = delta_ini_fourier.get_local_nx();
1068#ifdef USE_OMP
1069#pragma omp parallel for
1070#endif
1071 for (int islice = 0; islice < Local_nx; islice++) {
1072 for (auto && fourier_index : delta_ini_fourier.get_fourier_range(islice, islice + 1)) {
1073 delta_ini_fourier.set_fourier_from_index(fourier_index,
1074 FML::GRID::FloatType(-1.0) *
1075 delta_ini_fourier.get_fourier_from_index(fourier_index));
1076 }
1077 }
1078 }
1079
1080 // If we simply read IC from file (useful for testing)
1081 if (ic_random_field_type == "read_particles") {
1082 read_ic();
1083 } else {
1084
1085 // Generate IC from a given fourier grid. The growth rate is used to generate the velocities
1086 const double aini = 1.0 / (1.0 + ic_initial_redshift);
1087 const double fac = aini * aini * cosmo->HoverH0_of_a(std::exp(std::log(aini)));
1088 std::vector<double> velocity_norms{fac * grav_ic->get_f_1LPT(aini),
1089 fac * grav_ic->get_f_2LPT(aini),
1090 fac * grav_ic->get_f_3LPTa(aini),
1091 fac * grav_ic->get_f_3LPTb(aini)};
1092 timer.StartTiming("InitialConditions");
1093
1094 // Store the LPT potentials we need from the IC (max 2LPT)
1095 // We store 2LPT, 3LPTa, 3LPTb depending on the size of the vector we send in
1096 std::vector<FFTWGrid<NDIM>> phi_nLPT_potentials;
1097 if (simulation_use_cola and simulation_use_scaledependent_cola) {
1098 if (FML::PARTICLE::has_get_D_2LPT<T>())
1099 phi_nLPT_potentials.resize(1);
1100 if (FML::PARTICLE::has_get_D_3LPTa<T>() and FML::PARTICLE::has_get_D_3LPTb<T>())
1101 phi_nLPT_potentials.resize(3);
1102 }
1103
1104 FML::NBODY::NBodyInitialConditions<NDIM, T>(part,
1105 particle_Npart_1D,
1106 particle_allocation_factor,
1107 delta_ini_fourier,
1108 phi_nLPT_potentials,
1109 ic_LPT_order,
1110 simulation_boxsize,
1111 ic_initial_redshift,
1112 velocity_norms);
1113
1114 // Store potential in the class
1115 if (simulation_use_cola and simulation_use_scaledependent_cola) {
1116 if (FML::PARTICLE::has_get_D_1LPT<T>()) {
1117 // Store phi_1LPT (D^2 phi_1LPT = -delta)
1118 phi_1LPT_ini_fourier = delta_ini_fourier;
1119 phi_1LPT_ini_fourier.add_memory_label("phi_1LPT(k,zini)");
1120 auto Local_x_start = phi_1LPT_ini_fourier.get_local_x_start();
1121 auto Local_nx = phi_1LPT_ini_fourier.get_local_nx();
1122#ifdef USE_OMP
1123#pragma omp parallel for
1124#endif
1125 for (int islice = 0; islice < Local_nx; islice++) {
1126 double kmag2;
1127 std::array<double, NDIM> kvec;
1128 for (auto && fourier_index : phi_1LPT_ini_fourier.get_fourier_range(islice, islice + 1)) {
1129 if (Local_x_start == 0 and fourier_index == 0)
1130 continue; // DC mode k = 0
1131 phi_1LPT_ini_fourier.get_fourier_wavevector_and_norm2_by_index(fourier_index, kvec, kmag2);
1132 auto value =
1133 phi_1LPT_ini_fourier.get_fourier_from_index(fourier_index) / FML::GRID::FloatType(kmag2);
1134 phi_1LPT_ini_fourier.set_fourier_from_index(fourier_index, value);
1135 }
1136 }
1137 // Deal with DC mode
1138 if (Local_x_start == 0)
1139 phi_1LPT_ini_fourier.set_fourier_from_index(0, 0.0);
1140 }
1141 if (FML::PARTICLE::has_get_D_2LPT<T>()) {
1142 if (FML::ThisTask == 0)
1143 std::cout << "Storing initial 2LPT potential \n";
1144 phi_2LPT_ini_fourier = phi_nLPT_potentials[0];
1145 phi_2LPT_ini_fourier.add_memory_label("phi_2LPT(k,zini)");
1146 }
1147 if (FML::PARTICLE::has_get_D_3LPTa<T>() and FML::PARTICLE::has_get_D_3LPTb<T>()) {
1148 if (FML::ThisTask == 0)
1149 std::cout << "Storing initial 3LPT potentials \n";
1150 phi_3LPTa_ini_fourier = phi_nLPT_potentials[1];
1151 phi_3LPTb_ini_fourier = phi_nLPT_potentials[2];
1152 phi_3LPTa_ini_fourier.add_memory_label("phi_3LPTa(k,zini)");
1153 phi_3LPTb_ini_fourier.add_memory_label("phi_3LPTb(k,zini)");
1154 }
1155 }
1156
1157 timer.EndTiming("InitialConditions");
1158 }
1159
1160 //============================================================
1161 // In the COLA frame v=0 so reset velocities
1162 //============================================================
1163 if (simulation_use_cola) {
1164 cola_initialize_velocities<NDIM, T>(part);
1165 }
1166}
1167
1168template <int NDIM, class T>
1170 timer.StartTiming("Timestepping");
1171
1172 // Number of extra slices we need for density assignement
1173 const auto nleftright =
1175
1176 //================================================================
1177 // Check that the first output redshift is not larger than the initial redshift
1178 //================================================================
1179 if (std::fabs(output_redshifts[0] - ic_initial_redshift) < 1e-3)
1180 output_redshifts[0] = ic_initial_redshift;
1181 FML::assert_mpi(output_redshifts[0] <= ic_initial_redshift,
1182 "The first output cannot be before the simulation starts");
1183
1184 //================================================================
1185 // If we only give the total number of steps then compute how many steps between outputs
1186 //================================================================
1187 if (timestep_nsteps.size() == 1) {
1188 std::vector<int> nsteps_between_outputs;
1189 auto as = compute_scalefactors_KDK(
1190 1.0 / (1.0 + ic_initial_redshift), 1.0 / (1.0 + output_redshifts.back()), timestep_nsteps[0]);
1191 int icount = 0;
1192 for (size_t ioutput = 0; ioutput < output_redshifts.size(); ioutput++) {
1193 int i = 0;
1194 while (1) {
1195 double z = 1.0 / as.first[icount + i] - 1.0;
1196 if (z < output_redshifts[ioutput] + 1e-3)
1197 break;
1198 i++;
1199 }
1200 nsteps_between_outputs.push_back(i);
1201 icount += i;
1202 }
1203 timestep_nsteps = nsteps_between_outputs;
1204 }
1205
1206 //================================================================
1207 // Print all the steps we will take
1208 //================================================================
1209 if (FML::ThisTask == 0) {
1210 std::cout << "\n";
1211 std::cout << "#=====================================================\n";
1212 std::cout << "# The time-steps and outputs we plan to take\n";
1213 std::cout << "#=====================================================\n\n";
1214 for (size_t ioutput = 0; ioutput < output_redshifts.size(); ioutput++) {
1215 std::cout << "Next output z = " << output_redshifts[ioutput] << " nsteps: " << timestep_nsteps[ioutput]
1216 << "\n";
1217 double zmin = (ioutput == 0) ? ic_initial_redshift : output_redshifts[ioutput - 1];
1218 double zmax = output_redshifts[ioutput];
1219 auto as = compute_scalefactors_KDK(1.0 / (1.0 + zmin), 1.0 / (1.0 + zmax), timestep_nsteps[ioutput]);
1220 for (size_t i = 0; i < as.first.size() - 1; i++) {
1221 std::cout << "Step: " << std::setw(4) << i << " / " << std::setw(4) << timestep_nsteps[ioutput] << "\n";
1222 std::cout << "Positions from z = " << std::setw(15) << 1.0 / as.first[i] - 1.0 << " -> "
1223 << std::setw(15) << 1.0 / as.first[i + 1] - 1.0 << "\n";
1224 std::cout << "Velocities from z = " << std::setw(15) << 1.0 / as.second[i] - 1.0 << " -> "
1225 << std::setw(15) << 1.0 / as.second[i + 1] - 1.0 << "\n";
1226 }
1227 std::cout << "\n";
1228 }
1229 }
1230
1231 //=============================================================
1232 // Main time-stepping loop
1233 //=============================================================
1234
1235 if (FML::ThisTask == 0) {
1236 std::cout << "\n";
1237 std::cout << "#=====================================================\n";
1238 std::cout << "# Starting main time-stepping loop\n";
1239 std::cout << "#=====================================================\n\n";
1240 }
1241
1242 int istep_total = 0;
1243 for (size_t ioutput = 0; ioutput < output_redshifts.size(); ioutput++) {
1244
1245 // Fetch the list of steps to take
1246 const double amin =
1247 (ioutput == 0) ? 1.0 / (1.0 + ic_initial_redshift) : 1.0 / (1.0 + output_redshifts[ioutput - 1]);
1248 const double amax = 1.0 / (1.0 + output_redshifts[ioutput]);
1249 const auto asteps = compute_scalefactors_KDK(amin, amax, timestep_nsteps[ioutput]);
1250
1251 //=============================================================
1252 // Set up time-steps between output times
1253 //=============================================================
1254 auto delta_time = compute_deltatime_KDK(amin, amax, timestep_nsteps[ioutput]);
1255
1256 //=============================================================
1257 // Time-step till the next output
1258 //=============================================================
1259 if (timestep_nsteps[ioutput] > 0)
1260 for (int istep = 0; istep <= timestep_nsteps[ioutput]; istep++) {
1261
1262 const double apos = asteps.first[istep];
1263 const double avel = asteps.second[istep];
1264 const double apos_new = asteps.first[istep + 1];
1265 const double avel_new = asteps.second[istep + 1];
1266 const double delta_time_drift = delta_time.first[istep];
1267 const double delta_time_kick = delta_time.second[istep];
1268
1269 if (FML::ThisTask == 0) {
1270 std::cout << "\n";
1271 std::cout << "Taking substep: " << istep << " / " << timestep_nsteps[ioutput]
1272 << " Total steps taken: " << istep_total << "\n";
1273 std::cout << "Positions from z = " << std::setw(15) << 1.0 / apos - 1.0 << " -> " << std::setw(15)
1274 << 1.0 / apos_new - 1.0 << "\n";
1275 std::cout << "Velocities from z = " << std::setw(15) << 1.0 / avel - 1.0 << " -> " << std::setw(15)
1276 << 1.0 / avel_new - 1.0 << "\n";
1277 std::cout << "deltatime_pos = " << std::setw(15) << delta_time_drift
1278 << " deltatime_vel = " << std::setw(15) << delta_time_kick << "\n";
1279 }
1280
1281 // The last step is just a sync step so don't count towards the total
1282 if (istep < timestep_nsteps[ioutput])
1283 istep_total++;
1284
1285 // Compute total density field
1286 FFTWGrid<NDIM> density_grid_fourier(force_nmesh, nleftright.first, nleftright.second);
1287 if (delta_time_kick != 0.0) {
1288 timer.StartTiming("ComputeDensityField");
1289 compute_density_field_fourier(density_grid_fourier, apos);
1290 timer.EndTiming("ComputeDensityField");
1291 }
1292
1293 // Compute forces
1294 std::array<FFTWGrid<NDIM>, NDIM> force_real;
1295 if (delta_time_kick != 0.0) {
1296 timer.StartTiming("ComputeForce");
1297 grav->compute_force(apos,
1298 grav->H0_hmpc * simulation_boxsize,
1299 density_grid_fourier,
1300 force_density_assignment_method,
1301 force_real);
1302 timer.EndTiming("ComputeForce");
1303 }
1304
1305 // Kick particles (updates velocity)
1306 if (delta_time_kick != 0.0) {
1307 timer.StartTiming("Kick");
1308 FML::NBODY::KickParticles<NDIM>(force_real, part, delta_time_kick, force_density_assignment_method);
1309 timer.EndTiming("Kick");
1310 }
1311
1312 // For COLA we can do the kick and drift at the same time
1313 if (simulation_use_cola) {
1314 timer.StartTiming("COLA");
1315 // If the growth factors are scaledependent then we use the scaledependent version
1316 // unless simulation_use_scaledependent_cola is set to false
1317 const double aini = 1.0 / (1.0 + ic_initial_redshift);
1318 if (simulation_use_scaledependent_cola and grav->scaledependent_growth) {
1319 cola_kick_drift_scaledependent<NDIM, T>(part,
1320 grav,
1321 phi_1LPT_ini_fourier,
1322 phi_2LPT_ini_fourier,
1323 phi_3LPTa_ini_fourier,
1324 phi_3LPTb_ini_fourier,
1325 grav->H0_hmpc * simulation_boxsize,
1326 aini,
1327 apos,
1328 apos_new,
1329 delta_time_kick,
1330 delta_time_drift);
1331 } else {
1332 cola_kick_drift<NDIM, T>(part, grav, aini, apos, apos_new, delta_time_kick, delta_time_drift);
1333 }
1334 timer.EndTiming("COLA");
1335 }
1336
1337 // Drift particles (updates positions)
1338 if (delta_time_drift != 0.0) {
1339 timer.StartTiming("Drift");
1340 FML::NBODY::DriftParticles<NDIM, T>(part, delta_time_drift);
1341 timer.EndTiming("Drift");
1342 }
1343
1344 // Show info about particles
1345 part.info();
1346
1347 // Show info about system memory use
1349 }
1350
1351 //=============================================================
1352 // Analyze data and output
1353 //=============================================================
1354 analyze_and_output(ioutput, output_redshifts[ioutput]);
1355 }
1356 timer.EndTiming("Timestepping");
1357
1358 //=============================================================
1359 // Print all timings
1360 //=============================================================
1361 timer.EndTiming("The whole simulation");
1362 if (FML::ThisTask == 0) {
1363 timer.PrintAllTimings();
1364 }
1365
1366#ifdef MEMORY_LOGGING
1367 // Simulation is over, output the memory usage (of what we log)
1369#endif
1370}
1371
1372template <int NDIM, class T>
1374
1375 if (FML::ThisTask == 0) {
1376 std::cout << "Adding particles (baryons+CDM) to the densityfield\n";
1377 }
1378
1379 //=============================================================
1380 // Particles to grid
1381 //=============================================================
1382 FML::INTERPOLATION::particles_to_grid(part.get_particles_ptr(),
1383 part.get_npart(),
1384 part.get_npart_total(),
1385 density_grid_fourier,
1386 force_density_assignment_method);
1387
1388 //=============================================================
1389 // Fourier transform
1390 //=============================================================
1391 density_grid_fourier.fftw_r2c();
1392
1393 //=============================================================
1394 // Bin up power-spectrum (its basically free as we have the density field)
1395 // NB: Subtracting shot-noise if the parameter is set
1396 //=============================================================
1397 const double redshift = 1.0 / a - 1.0;
1398 PowerSpectrumBinning<NDIM> pofk_particles(density_grid_fourier.get_nmesh() / 2);
1399 pofk_particles.subtract_shotnoise = pofk_subtract_shotnoise;
1401 density_grid_fourier, pofk_particles, force_density_assignment_method);
1402 pofk_particles.scale(simulation_boxsize);
1403 pofk_cb_every_step.push_back({redshift, pofk_particles});
1404
1405 //=============================================================
1406 // Add on contribution from massive neutrinos, radiation etc.
1407 // We need to have transfer functions for what follows and for that we
1408 // check [transferdata] which is created if "transferinfofile" is used
1409 //=============================================================
1410 if (force_linear_massive_neutrinos and cosmo->get_OmegaMNu() > 0.0 and transferdata) {
1411
1412 // First step we store the initial density field
1413 if (not initial_density_field_fourier) {
1414 initial_density_field_fourier = density_grid_fourier;
1415 initial_density_field_fourier.add_memory_label("density(k,zini)");
1416 FML::assert_mpi(std::fabs(redshift - ic_initial_redshift) < 1e-3, "This should not happen");
1417 }
1418
1419 if (FML::ThisTask == 0) {
1420 std::cout << "Adding linear massive neutrinos to the densityfield\n";
1421 }
1422
1423 // Function to translate delta_cb(zini,k) -> delta_nu(z,k) using transfer functions
1424 const double aini = 1.0 / (1.0 + ic_initial_redshift);
1425 const double koverkBox = 1.0 / simulation_boxsize;
1426 auto norm = [&](double kBox) {
1427 double T_mnu = transferdata->get_massive_neutrino_transfer_function(kBox * koverkBox, a);
1428 double T_cb_ini = transferdata->get_cdm_baryon_transfer_function(kBox * koverkBox, aini);
1429 return (T_mnu / T_cb_ini);
1430 };
1431
1432 // We compute the total matter density-field deltaM = (OmegaCB deltaCB + OmegaMNu deltaMNu)/OmegaM
1433 const double OmegaM = cosmo->get_OmegaM();
1434 const double OmegaMNu = cosmo->get_OmegaMNu();
1435 const double fMNu = OmegaMNu / OmegaM;
1436
1437 auto Local_nx = initial_density_field_fourier.get_local_nx();
1438#ifdef USE_OMP
1439#pragma omp parallel for
1440#endif
1441 for (int islice = 0; islice < Local_nx; islice++) {
1442 [[maybe_unused]] double kmag;
1443 [[maybe_unused]] std::array<double, NDIM> kvec;
1444 for (auto && fourier_index : density_grid_fourier.get_fourier_range(islice, islice + 1)) {
1445 density_grid_fourier.get_fourier_wavevector_and_norm_by_index(fourier_index, kvec, kmag);
1446 auto delta_ini = initial_density_field_fourier.get_fourier_from_index(fourier_index);
1447 auto deltaCB = density_grid_fourier.get_fourier_from_index(fourier_index);
1448 auto deltaM =
1449 deltaCB * FML::GRID::FloatType(1.0 - fMNu) + delta_ini * FML::GRID::FloatType(norm(kmag) * fMNu);
1450 density_grid_fourier.set_fourier_from_index(fourier_index, deltaM);
1451 }
1452 }
1453
1454 //=============================================================
1455 // Bin up total power-spectrum (its basically free)
1456 // XXX: the density field is here the sum of W*deltaCB + deltaNu
1457 // so the last part is going to be added up as deltaNu/W^2 so
1458 // its not fully correct for large k, but this is not a high
1459 // quality P(k) anyway... should improve this at some point
1460 // One way is to bin up <(W*deltaCB)^2>, <deltaNu^2> and the cross
1461 // <(W*deltaCB) deltaNu> and deconvolve them seperately
1462 //=============================================================
1463 PowerSpectrumBinning<NDIM> pofk_total(density_grid_fourier.get_nmesh() / 2);
1464 pofk_total.subtract_shotnoise = pofk_subtract_shotnoise;
1466 density_grid_fourier, pofk_total, force_density_assignment_method);
1467 pofk_total.scale(simulation_boxsize);
1468 pofk_total_every_step.push_back({redshift, pofk_total});
1469 }
1470}
1471
1472template <int NDIM, class T>
1473void NBodySimulation<NDIM, T>::analyze_and_output(int ioutput, double redshift) {
1474
1475 std::stringstream stream;
1476 stream << std::fixed << std::setprecision(3) << redshift;
1477 std::string redshiftstring = stream.str();
1478 std::string snapshot_folder = output_folder;
1479
1480 //=============================================================
1481 // Create snapshotfolder
1482 //=============================================================
1483 snapshot_folder =
1484 output_folder + (output_folder == "" ? "" : "/") + "snapshot_" + simulation_name + "_z" + redshiftstring;
1485 if (not FML::create_folder(snapshot_folder)) {
1486 throw std::runtime_error("Failed to create snapshot folder [" + snapshot_folder + "]");
1487 }
1488
1489 if (FML::ThisTask == 0) {
1490 std::cout << "\n";
1491 std::cout << "#=====================================================\n";
1492 std::cout << "# Analyze and output\n";
1493 std::cout << "#=====================================================\n";
1494 std::cout << "Doing output " << ioutput << " at redshift z = " << redshift << "\n";
1495 std::cout << "Snapshot will be stored in folder " << snapshot_folder << "\n";
1496 }
1497
1498 auto add_on_LPT_velocity = [&](double addsubtract_sign) {
1499 const double aini = 1.0 / (1.0 + ic_initial_redshift);
1500 const double a = 1.0 / (1.0 + redshift);
1501 if (simulation_use_scaledependent_cola and grav->scaledependent_growth) {
1502 cola_add_on_LPT_velocity_scaledependent<NDIM, T>(part,
1503 grav,
1504 phi_1LPT_ini_fourier,
1505 phi_2LPT_ini_fourier,
1506 phi_3LPTa_ini_fourier,
1507 phi_3LPTb_ini_fourier,
1508 grav->H0_hmpc * simulation_boxsize,
1509 aini,
1510 a,
1511 addsubtract_sign);
1512 } else {
1513 cola_add_on_LPT_velocity<NDIM, T>(part, grav, aini, a, addsubtract_sign);
1514 }
1515 };
1516
1517 //=============================================================
1518 // Change velocities to true velocities
1519 // In the COLA frame the initial velocity is zero, i.e. we have subtracted the
1520 // velocity predicted by LPT. Here we add on the LPT velocity to the particles
1521 //=============================================================
1522 if (simulation_use_cola) {
1523 timer.StartTiming("COLA output");
1524 add_on_LPT_velocity(+1.0);
1525 timer.EndTiming("COLA output");
1526 }
1527
1528 //=============================================================
1529 // Every step we (might) have computed Pcb(k) and possibly Ptotal(k)
1530 // and stored this. Output these to file
1531 //=============================================================
1532 if (pofk_cb_every_step.size() > 0 or pofk_total_every_step.size() > 0) {
1534 }
1535
1536 //=============================================================
1537 // Power-spectrum
1538 //=============================================================
1539 if (pofk) {
1540 timer.StartTiming("Power-spectrum");
1541 compute_power_spectrum(*this, redshift, snapshot_folder);
1542 timer.EndTiming("Power-spectrum");
1543 }
1544
1545 //=============================================================
1546 // Power-spectrum multipoles
1547 //=============================================================
1548 if (pofk_multipole) {
1549 timer.StartTiming("Power-spectrum multipoles");
1550 compute_power_spectrum_multipoles(*this, redshift, snapshot_folder);
1551 timer.EndTiming("Power-spectrum multipoles");
1552 }
1553
1554 //=============================================================
1555 // Halo finding
1556 //=============================================================
1557 if (fof) {
1558 timer.StartTiming("FOF");
1559 compute_fof_halos(*this, redshift, snapshot_folder);
1560 timer.EndTiming("FOF");
1561 }
1562
1563 //=============================================================
1564 // Bispectrum
1565 //=============================================================
1566 if (bispectrum) {
1567 timer.StartTiming("Bispectrum");
1568 compute_bispectrum(*this, redshift, snapshot_folder);
1569 timer.EndTiming("Bispectrum");
1570 }
1571
1572 //=============================================================
1573 // Write particles to file
1574 //=============================================================
1575 if (output_particles) {
1576 timer.StartTiming("Output particles");
1577 if (output_fileformat == "GADGET")
1578 output_gadget(*this, redshift, snapshot_folder);
1579 if (output_fileformat == "FML") {
1580 output_fml(*this, redshift, snapshot_folder);
1581 }
1582 timer.EndTiming("Output particles");
1583 }
1584
1585 //=============================================================
1586 // Change velocities back to true COLA velocities
1587 //=============================================================
1588 if (simulation_use_cola) {
1589 timer.StartTiming("COLA output");
1590 add_on_LPT_velocity(-1.0);
1591 timer.EndTiming("COLA output");
1592 }
1593}
1594
1595template <int NDIM, class T>
1597 part.free();
1598 initial_density_field_fourier.free();
1599 phi_1LPT_ini_fourier.free();
1600 phi_2LPT_ini_fourier.free();
1601 phi_3LPTa_ini_fourier.free();
1602 phi_3LPTb_ini_fourier.free();
1603}
1604
1605template <int NDIM, class T>
1607
1608 if (FML::ThisTask == 0) {
1609 std::cout << "\n";
1610 std::cout << "#=====================================================\n";
1611 std::cout << "# Reading initial conditions from GADGET files [" + ic_reconstruct_gadgetfilepath + "]\n";
1612 std::cout << "#=====================================================\n";
1613 }
1614
1615 // Read in gadget files (all tasks reads the same files)
1616 // Using FML::Vector in case we have memory logging on to allow us to
1617 // move the data into mpiparticles
1618 GadgetReader g;
1619 FML::Vector<T> externalpart;
1620 const std::string fileprefix = ic_reconstruct_gadgetfilepath;
1621 const bool only_keep_part_in_domain = true;
1622 const bool verbose = false;
1623 g.read_gadget(fileprefix, externalpart, particle_allocation_factor, only_keep_part_in_domain, verbose);
1624
1625 auto header = g.get_header();
1627
1628 const double scale_factor = header.time;
1629
1630 // Check that the redshift in the file matched the initial redshift
1631 FML::assert_mpi(std::fabs(scale_factor - 1.0 / (1.0 + ic_initial_redshift)) < 1e-3,
1632 "[read_ic] The redshift in the gadgetfile we read does not match the initial redshift of "
1633 "the simulation");
1634
1635 // Velocities we get from the gadget reader is peculiar km/s
1636 // so scale to code units
1637 const double vel_norm = scale_factor / (100 * simulation_boxsize);
1638#ifdef USE_OMP
1639#pragma omp parallel for
1640#endif
1641 for (size_t i = 0; i < externalpart.size(); i++) {
1642 auto * vel = FML::PARTICLE::GetVel(externalpart[i]);
1643 for (int idim = 0; idim < NDIM; idim++)
1644 vel[idim] *= vel_norm;
1645 }
1646
1647 // Move them into MPIParticles
1648 part.move_from(std::move(externalpart));
1649
1650 // Assign particles to grid
1651 const auto nleftright =
1653 FFTWGrid<NDIM> delta_fourier(ic_nmesh, nleftright.first, nleftright.second);
1654 FML::INTERPOLATION::particles_to_fourier_grid(part.get_particles_ptr(),
1655 part.get_npart(),
1656 part.get_npart_total(),
1657 delta_fourier,
1658 ic_reconstruct_assigment_method,
1659 ic_reconstruct_interlacing);
1660
1661 // Deconvolve window function
1662 FML::INTERPOLATION::deconvolve_window_function_fourier<NDIM>(delta_fourier, ic_reconstruct_assigment_method);
1663
1664 // Smoothing (should just use a sharpk filter to set modes beyond Nmesh used to generate the IC to zero)
1665 // If we use a larger grid then the highest frequency modes, beyond knyuist of the grid used to
1666 // generate the IC, will just be noise and will lead to problems so these modes needs to be killed
1668 delta_fourier, ic_reconstruct_dimless_smoothing_scale, ic_reconstruct_smoothing_filter);
1669
1670 // In case of COLA we need to assign displacement fields to particles
1671 if (simulation_use_cola) {
1672
1673 // Has only implemented this for 1LPT and 2LPT
1674 FML::assert_mpi(FML::PARTICLE::has_get_D_3LPTa<T>() == false and FML::PARTICLE::has_get_D_3LPTb<T>() == false,
1675 "3LPT not implemented for read_ic");
1676
1677 // Doing 1LPT displacementfields
1678 // For scaledependent we also set the Lagrangian position
1679 if constexpr (FML::PARTICLE::has_get_D_1LPT<T>()) {
1680
1681 if (FML::ThisTask == 0) {
1682 std::cout << "Reconstructing 1LPT potential...\n";
1683 }
1684
1685 FFTWGrid<NDIM> temp;
1686 FFTWGrid<NDIM> & phi_1LPT_fourier = simulation_use_scaledependent_cola ? phi_1LPT_ini_fourier : temp;
1687
1688 FML::COSMOLOGY::LPT::compute_1LPT_potential_fourier(delta_fourier, phi_1LPT_fourier);
1689
1690 // For scaleindependent we need to store the Psi's in the particles so compute that
1691 std::array<FFTWGrid<NDIM>, NDIM> psi_1LPT_vector;
1692 FML::COSMOLOGY::LPT::from_LPT_potential_to_displacement_vector<NDIM>(phi_1LPT_fourier, psi_1LPT_vector);
1693 for (int idim = 0; idim < NDIM; idim++) {
1694 psi_1LPT_vector[idim].communicate_boundaries();
1695 }
1696 std::array<std::vector<FML::GRID::FloatType>, NDIM> displacements;
1697 FML::INTERPOLATION::interpolate_grid_vector_to_particle_positions<NDIM, T>(
1698 psi_1LPT_vector, part.get_particles_ptr(), part.get_npart(), displacements, "CIC");
1699
1700 // Assign displacement field to particles
1701 auto * part_ptr = part.get_particles_ptr();
1702#ifdef USE_OMP
1703#pragma omp parallel for
1704#endif
1705 for (size_t ind = 0; ind < part.get_npart(); ind++) {
1706 auto * pos = FML::PARTICLE::GetPos(part_ptr[ind]);
1707 auto * D = FML::PARTICLE::GetD_1LPT(part_ptr[ind]);
1708 for (int idim = 0; idim < NDIM; idim++) {
1709 D[idim] = displacements[idim][ind];
1710 }
1711
1712 // Set (approximate) Lagrangian position
1713 if constexpr (FML::PARTICLE::has_get_q<T>()) {
1714 auto * q = FML::PARTICLE::GetLagrangianPos(part_ptr[ind]);
1715 for (int idim = 0; idim < NDIM; idim++) {
1716 q[idim] = pos[idim] - D[idim];
1717 }
1718 }
1719 }
1720 }
1721
1722 // Doing 2LPT displacementfields
1723 if constexpr (FML::PARTICLE::has_get_D_2LPT<T>()) {
1724
1725 if (FML::ThisTask == 0) {
1726 std::cout << "Reconstructing 2LPT potential...\n";
1727 }
1728
1729 FFTWGrid<NDIM> temp;
1730 FFTWGrid<NDIM> & phi_2LPT_fourier = simulation_use_scaledependent_cola ? phi_2LPT_ini_fourier : temp;
1731
1732 FML::COSMOLOGY::LPT::compute_2LPT_potential_fourier(delta_fourier, phi_2LPT_fourier);
1733
1734 // For scaleindependent we need to store the Psi's in the particles
1735 if (not simulation_use_scaledependent_cola) {
1736 std::array<FFTWGrid<NDIM>, NDIM> psi_2LPT_vector;
1737 FML::COSMOLOGY::LPT::from_LPT_potential_to_displacement_vector<NDIM>(phi_2LPT_fourier, psi_2LPT_vector);
1738 for (int idim = 0; idim < NDIM; idim++) {
1739 psi_2LPT_vector[idim].communicate_boundaries();
1740 }
1741 std::array<std::vector<FML::GRID::FloatType>, NDIM> displacements;
1742 FML::INTERPOLATION::interpolate_grid_vector_to_particle_positions<NDIM, T>(
1743 psi_2LPT_vector, part.get_particles_ptr(), part.get_npart(), displacements, "CIC");
1744
1745 // Assign displacement field to particles
1746 auto * part_ptr = part.get_particles_ptr();
1747#ifdef USE_OMP
1748#pragma omp parallel for
1749#endif
1750 for (size_t ind = 0; ind < part.get_npart(); ind++) {
1751 auto * D = FML::PARTICLE::GetD_2LPT(part_ptr[ind]);
1752 for (int idim = 0; idim < NDIM; idim++) {
1753 D[idim] = displacements[idim][ind];
1754 }
1755 }
1756 }
1757 }
1758 }
1759}
1760
1761#endif
void compute_fof_halos(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
void output_fml(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
Definition: AnalyzeOutput.h:99
void compute_power_spectrum_multipoles(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
void output_pofk_for_every_step(NBodySimulation< NDIM, T > &sim)
Definition: AnalyzeOutput.h:24
void compute_power_spectrum(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
void output_gadget(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
void compute_bispectrum(NBodySimulation< NDIM, T > &sim, double redshift, std::string snapshot_folder)
const int NDIM
float FloatType
Definition: FFTWGlobal.h:29
const int nsteps
Definition: Main.cpp:43
const double OmegaM
Definition: Main.cpp:65
const double aini
Definition: Main.cpp:41
FML::UTILS::ParameterMap ParameterMap
Definition: Simulation.h:47
FML::INTERPOLATION::SPLINE::Spline Spline
Definition: Simulation.h:40
FML::RANDOM::GSLRandomGenerator GSLRandomGenerator
Definition: Simulation.h:38
FML::FILEUTILS::GADGET::GadgetReader GadgetReader
Definition: Simulation.h:48
FML::FILEUTILS::LinearTransferData LinearTransferData
Definition: Simulation.h:49
FML::INTERPOLATION::SPLINE::DVector DVector
Definition: Simulation.h:39
FML::SOLVERS::ODESOLVER::ODESolver ODESolver
Definition: Simulation.h:41
FML::SOLVERS::ODESOLVER::ODEFunction ODEFunction
Definition: Simulation.h:42
FML::RANDOM::RandomGenerator RandomGenerator
Definition: Simulation.h:37
Class for holding the results after binning up a power-spectrum.
bool subtract_shotnoise
Subtract shotnoise or not (used by algorithms)
void scale(const double boxsize)
Scale to physical units: k *= 1/Box and pofk *= Box^N.
Class for reading Gadget files. Checks and corrects for different endian-ness.
Definition: GadgetUtils.h:103
GadgetHeader get_header()
Get the header (assumes it has been read)
Definition: GadgetUtils.cpp:61
void read_gadget(std::string filename, std::vector< T, Alloc > &part, double buffer_factor, bool only_keep_part_in_domain, bool verbose)
Read all gadget files and store the data in part.
Definition: GadgetUtils.h:242
This class reads transfer/power-spectrum data from the output of a Einstein-Boltzmann solver.
Definition: CAMBReader.h:50
Class for holding grids and performing real-to-complex and complex-to-real FFTs using FFTW with MPI.
Definition: FFTWGrid.h:88
int get_nmesh() const
Number of grid-cells per dimension.
Definition: FFTWGrid.h:1054
void add_memory_label(std::string label)
For memory logging: add a label to the grid.
Definition: FFTWGrid.h:318
ptrdiff_t get_local_nx() const
Number of local x-slices in the real grid.
Definition: FFTWGrid.h:1079
void set_fourier_from_index(const IndexIntType ind, const ComplexType value)
Set value of cell in fourier grid using (local) index.
Definition: FFTWGrid.h:1036
ComplexType get_fourier_from_index(const IndexIntType index) const
Fetch value in fourier grid by (local) index.
Definition: FFTWGrid.h:1031
FourierRange get_fourier_range(int islice_begin=0, int islice_end=0) const
Range iterator for going through all active cells in the main fourier grid by index [ e....
Definition: FFTWGrid.h:419
void fftw_r2c()
Perform real-to-complex fourier transform.
Definition: FFTWGrid.h:881
void get_fourier_wavevector_and_norm_by_index(const IndexIntType ind, std::array< double, N > &kvec, double &kmag) const
From index in the grid get the k-vector and the magnitude of it.
Definition: FFTWGrid.h:1103
void set_grid_status_real(bool grid_is_a_real_grid)
Set the status of the grid: is it currently a real grid or a fourier grid?
Definition: FFTWGrid.h:468
This is a wrapper class for easy use of GSL splines It is (OpenMP) thread safe as long as splines are...
Definition: Spline.h:80
static MemoryLog * get()
Definition: MemoryLogging.h:86
A container class for holding particles that are distributed across many CPUs and to easily deal with...
Definition: MPIParticles.h:69
Generate random numbers using the GSL library (fiducial: gsl_rng_ranlxd1)
This is a class for having a unified interface for random numbers in the library.
This is a wrapper around the GSL library to easily solve ODEs and return the data in whatever format ...
Definition: ODESolver.h:87
DVector get_final_data() const
Get the solution at the end point.
Definition: ODESolver.cpp:166
void solve(ODEFunctionPointer ode_equation, void *parameters, DVector &xarr, DVector &yinitial, const gsl_odeiv2_step_type *stepper=ODESOLVER_FIDUCIAL_STEPPER, ODEFunctionPointerJacobian jacobian=nullptr)
Definition: ODESolver.cpp:71
For holding a map of parameters of different types with easy set and get's allowing for fiducial valu...
Definition: ParameterMap.h:51
T get(std::string name) const
Fetch a value. If it doesn't exist we throw an error.
Class for performing timings of the code using std::chrono.
Definition: Timings.h:22
void StartTiming(const char *name)
Start timing.
Definition: Timings.h:63
Base class for gravity models.
Definition: GravityModel.h:26
std::shared_ptr< GravityModel< NDIM > > grav
Everything related to gravity: growth factors, computing forces.
Definition: Simulation.h:64
Spline power_initial_spline
Definition: Simulation.h:103
void compute_density_field_fourier(FFTWGrid< NDIM > &density_grid_fourier, double a)
From particles to density field.
Definition: Simulation.h:1373
bool output_particles
Definition: Simulation.h:200
std::pair< std::vector< double >, std::vector< double > > compute_deltatime_KDK(double amin, double amax, int nsteps)
Definition: Simulation.h:280
friend void output_fml(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
friend void compute_fof_halos(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
double particle_allocation_factor
Definition: Simulation.h:158
friend void compute_power_spectrum_multipoles(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
bool bispectrum_interlacing
Definition: Simulation.h:195
bool simulation_use_scaledependent_cola
Definition: Simulation.h:113
std::string bispectrum_density_assignment_method
Definition: Simulation.h:194
NBodySimulation(std::shared_ptr< Cosmology > cosmo, std::shared_ptr< GravityModel< NDIM > > grav, MPIParticles< T > &&_part)
Definition: Simulation.h:224
std::string force_density_assignment_method
Definition: Simulation.h:117
double fof_linking_length
Definition: Simulation.h:172
NBodySimulation(std::shared_ptr< Cosmology > cosmo, std::shared_ptr< GravityModel< NDIM > > grav)
Definition: Simulation.h:218
FML::UTILS::Timings timer
Definition: Simulation.h:99
bool pofk_multipole_subtract_shotnoise
Definition: Simulation.h:186
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_every_output
Definition: Simulation.h:212
int pofk_multipole_nmesh
Definition: Simulation.h:184
FFTWGrid< NDIM > phi_1LPT_ini_fourier
Definition: Simulation.h:93
friend void output_gadget(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
FFTWGrid< NDIM > phi_3LPTa_ini_fourier
Definition: Simulation.h:95
std::string ic_reconstruct_smoothing_filter
Definition: Simulation.h:152
std::string timestep_scalefactor_spacing
Definition: Simulation.h:165
bool pofk_interlacing
Definition: Simulation.h:178
friend void generate_initial_conditions(NBodySimulation< _NDIM, _T > &sim)
double fof_buffer_length_mpch
Definition: Simulation.h:173
std::string pofk_density_assignment_method
Definition: Simulation.h:180
std::string ic_fnl_type
Definition: Simulation.h:140
std::pair< std::vector< double >, std::vector< double > > compute_scalefactors_KDK(double amin, double amax, int nsteps)
Definition: Simulation.h:433
std::string ic_input_filename
Definition: Simulation.h:131
std::vector< double > output_redshifts
Definition: Simulation.h:199
MPIParticles< T > part
All the particles.
Definition: Simulation.h:81
std::string ic_random_generator
Definition: Simulation.h:126
std::string timestep_algorithm
Definition: Simulation.h:163
std::string ic_reconstruct_assigment_method
Definition: Simulation.h:151
std::string output_folder
Definition: Simulation.h:202
void read_ic()
This method simply read particles and uses them for the simulation.
Definition: Simulation.h:1606
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_total_every_step
Definition: Simulation.h:210
bool ic_use_gravity_model_GR
Definition: Simulation.h:133
void analyze_and_output(int ioutput, double redshift)
Compute stuff on the fly and output.
Definition: Simulation.h:1473
bool ic_fix_amplitude
Definition: Simulation.h:136
double ic_input_redshift
Definition: Simulation.h:132
std::string force_kernel
Definition: Simulation.h:118
void read_parameters(ParameterMap &param)
Read in and set parameters we need.
Definition: Simulation.h:466
FFTWGrid< NDIM > phi_3LPTb_ini_fourier
Definition: Simulation.h:96
bool force_linear_massive_neutrinos
Definition: Simulation.h:119
FFTWGrid< NDIM > phi_2LPT_ini_fourier
Definition: Simulation.h:94
friend void compute_power_spectrum(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
double ic_sigma8
Definition: Simulation.h:147
std::shared_ptr< LinearTransferData > transferdata
Everything related to linear perturbations, transfer functions, initial pofk This is only used if ic_...
Definition: Simulation.h:70
friend void compute_bispectrum(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
Spline transfer_initial_spline
Definition: Simulation.h:104
friend void output_pofk_for_every_step(NBodySimulation< _NDIM, _T > &sim)
void init()
Initialize simulation. Create initial conditions. Make it ready to run.
Definition: Simulation.h:695
std::string ic_type_of_input
Definition: Simulation.h:130
std::shared_ptr< ParameterMap > parameters
A copy of the simulation parameters just to have it.
Definition: Simulation.h:76
bool ic_reconstruct_interlacing
Definition: Simulation.h:154
std::vector< std::pair< double, std::vector< PowerSpectrumBinning< NDIM > > > > pofk_multipoles_every_output
Definition: Simulation.h:214
bool bispectrum_subtract_shotnoise
Definition: Simulation.h:196
std::string simulation_name
Definition: Simulation.h:110
std::shared_ptr< Cosmology > cosmo
Everything related to the background evolution.
Definition: Simulation.h:59
double simulation_boxsize
Definition: Simulation.h:111
FFTWGrid< NDIM > initial_density_field_fourier
The initial density field delta_cb(zini,k) computed with the same Nmesh as the forces (used for linea...
Definition: Simulation.h:88
NBodySimulation()=default
double ic_reconstruct_dimless_smoothing_scale
Definition: Simulation.h:153
std::string ic_reconstruct_gadgetfilepath
Definition: Simulation.h:150
std::string ic_random_field_type
Definition: Simulation.h:122
double timestep_spacing_power
Definition: Simulation.h:166
std::string timestep_method
Definition: Simulation.h:162
bool pofk_multipole_interlacing
Definition: Simulation.h:185
bool pofk_subtract_shotnoise
Definition: Simulation.h:179
std::string pofk_multipole_density_assignment_method
Definition: Simulation.h:188
int pofk_multipole_ellmax
Definition: Simulation.h:187
void run()
Run simulation.
Definition: Simulation.h:1169
std::vector< int > timestep_nsteps
Definition: Simulation.h:161
Spline power_primordial_spline
Definition: Simulation.h:102
double timestep_cola_nLPT
Definition: Simulation.h:164
bool ic_sigma8_normalization
Definition: Simulation.h:145
bool ic_reverse_phases
Definition: Simulation.h:137
double ic_fnl_redshift
Definition: Simulation.h:142
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_cb_every_step
Definition: Simulation.h:209
bool simulation_use_cola
Definition: Simulation.h:112
double ic_sigma8_redshift
Definition: Simulation.h:146
std::string output_fileformat
Definition: Simulation.h:201
double ic_initial_redshift
Definition: Simulation.h:123
void bin_up_deconvolved_power_spectrum(const FFTWGrid< N > &fourier_grid, PowerSpectrumBinning< N > &pofk, std::string density_assignment_method)
Compute the power-spectrum of a fourier grid.
void compute_1LPT_potential_fourier(const FFTWGrid< N > &delta_fourier, FFTWGrid< N > &phi_1LPT_fourier)
Generate the 1LPT potential defined as and .
void compute_2LPT_potential_fourier(const FFTWGrid< N > &delta_fourier, FFTWGrid< N > &phi_2LPT_fourier)
Generate the 2LPT potential defined as and .
void print_header_info(GadgetHeader &header)
Definition: GadgetUtils.cpp:32
DVector2D read_regular_ascii(std::string filename, int ncols, std::vector< int > cols_to_keep, int nskip, size_t nestimated_lines)
Read a regular ascii files with nskip header lines and containing ncol collums nestimated_lines is th...
Definition: FileUtils.cpp:14
void smoothing_filter_fourier_space(FFTWGrid< N > &fourier_grid, double smoothing_scale, std::string smoothing_method)
Low-pass filters (tophat, gaussian, sharpk)
std::vector< double > DVector
Definition: Spline.h:29
std::pair< int, int > get_extra_slices_needed_for_density_assignment(std::string density_assignment_method)
Compute how many extra slices we need in the FFTWGrid for a given density assignement / interpolation...
void particles_to_fourier_grid(T *part, size_t NumPart, size_t NumPartTot, FFTWGrid< N > &density_grid_fourier, std::string density_assignment_method, bool interlacing)
Assign particles to grid to compute the over density.
void particles_to_grid(const T *part, size_t NumPart, size_t NumPartTot, FFTWGrid< N > &density, std::string density_assignment_method)
Assign particles to a grid to compute the over density field delta.
double compute_sigma_of_R(std::function< double(double)> Pofk_of_kBox_over_volume, double R_mpch, double boxsize_mpch)
This computes the standard deviation of linear fluctuations smoothed over a sphere of radius,...
Definition: NBody.h:1294
get_vel constexpr double * GetPos(...)
constexpr double * GetLagrangianPos(...)
constexpr double * GetVel(...)
constexpr double * GetD_2LPT(...)
void generate_nonlocal_gaussian_random_field_fourier_cosmology(FFTWGrid< N > &delta_fourier, RandomGenerator *rng, std::function< double(double)> Pofk_of_kBox_over_Pofk_primordal, std::function< double(double)> Pofk_of_kBox_over_volume_primordial, bool fix_amplitude, double fNL, std::string type_of_fnl, double u=0.0, std::vector< double > kernel_values={})
This computes a non-gaussian density field at any redshift.
std::function< int(double, const double *, double *)> ODEFunction
Definition: ODESolver.h:33
bool create_folder(std::string foldername)
Definition: Global.cpp:207
constexpr long long int power(int base, int exponent)
Simple integer a^b power-function by squaring.
Definition: Global.h:187
int ThisTask
The MPI task number.
Definition: Global.cpp:33
void print_system_memory_use()
Print the resident set size and the peak value of it so far.
Definition: Global.cpp:233
const double exp
Definition: Global.h:259
std::vector< T, Allocator< T > > Vector
Definition: Global.h:79
bool verbose
Definition: example.py:19
float z
Definition: example.py:56