1#ifndef SIMULATION_HEADER
2#define SIMULATION_HEADER
53template <
int NDIM,
class T>
59 std::shared_ptr<Cosmology>
cosmo;
64 std::shared_ptr<GravityModel<NDIM>>
grav;
228 part = std::move(_part);
255 template <
int _NDIM,
class _T>
259 template <
int _NDIM,
class _T>
261 template <
int _NDIM,
class _T>
263 template <
int _NDIM,
class _T>
266 template <
int _NDIM,
class _T>
268 template <
int _NDIM,
class _T>
270 template <
int _NDIM,
class _T>
272 template <
int _NDIM,
class _T>
279template <
int NDIM,
class T>
281 -> std::pair<std::vector<double>, std::vector<double>> {
289 auto poisson_factor = [&](
double a) {
return 1.5 * cosmo->get_OmegaM() * grav->GeffOverG(a) * a; };
294 auto compute_kick_timestep_tassev = [&](
double alow,
double ahigh,
int istep,
int nsteps) {
295 double amid = (ahigh + alow) / 2.;
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));
310 auto compute_kick_timestep_quinn = [&](
double alow,
double ahigh,
int istep,
int nsteps) {
311 double amid = (ahigh + alow) / 2.;
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);
327 ode.
solve(deriv, avec, tini);
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.;
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);
348 ode.
solve(deriv, avec, tini);
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));
366 ode.
solve(deriv, avec, tini);
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);
379 throw std::runtime_error(
"Unknown timestep_method [" + timestep_method +
"]");
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);
388 throw std::runtime_error(
"Unknown timestep_method [" + timestep_method +
"]");
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);
404 throw std::runtime_error(
"Unknown timestep_scalefactor_spacing [" + timestep_scalefactor_spacing +
"]");
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);
428 return {delta_time_drift, delta_time_kick};
431template <
int NDIM,
class T>
432std::pair<std::vector<double>, std::vector<double>>
438 auto scale_factor_of_step = [&](
double i) {
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);
448 throw std::runtime_error(
"Unknown timestep_scalefactor_spacing [" + timestep_scalefactor_spacing +
"]");
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);
462 return {scalefactor_pos, scalefactor_vel};
465template <
int NDIM,
class T>
468 parameters = std::make_shared<ParameterMap>(param);
472 std::cout <<
"#=====================================================\n";
473 std::cout <<
"# NBodySimulation::read_parameters\n";
474 std::cout <<
"#=====================================================\n\n";
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");
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";
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!");
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");
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";
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");
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");
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");
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";
554 if (ic_sigma8_normalization) {
555 std::cout <<
"ic_sigma8 : " << ic_sigma8 <<
"\n";
556 std::cout <<
"ic_sigma8_redshift : " << ic_sigma8_redshift <<
"\n";
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
564 std::cout <<
"ic_reconstruct_interlacing : " << ic_reconstruct_interlacing <<
"\n";
569 particle_Npart_1D = param.
get<
int>(
"particle_Npart_1D");
570 particle_allocation_factor = param.
get<
double>(
"particle_allocation_factor");
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";
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");
589 std::cout <<
"timestep_nsteps : ";
590 for (
auto & n : timestep_nsteps)
591 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";
599 if (timestep_scalefactor_spacing ==
"powerlaw") {
600 std::cout <<
"timestep_spacing_power : " << timestep_spacing_power <<
"\n";
605 fof = param.
get<
bool>(
"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");
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";
622 pofk = param.
get<
bool>(
"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");
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";
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");
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
659 bispectrum = param.
get<
bool>(
"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");
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";
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");
684 std::cout <<
"output_particles : " << output_particles <<
"\n";
685 std::cout <<
"output_redshifts : ";
686 for (
auto &
z : output_redshifts)
687 std::cout <<
z <<
" , ";
689 std::cout <<
"output_fileformat : " << output_fileformat <<
"\n";
690 std::cout <<
"output_folder : " << output_folder <<
"\n";
694template <
int NDIM,
class T>
699 std::cout <<
"#=====================================================\n";
700 std::cout <<
"# Create initial conditions\n";
701 std::cout <<
"#=====================================================\n";
705 if (output_folder !=
"") {
707 throw std::runtime_error(
"Cannot create output directory [" + output_folder +
"]");
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);
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);
752 if (ic_type_of_input ==
"powerspectrum") {
757 const int col_pofk = 1;
758 std::vector<int> cols_to_keep{col_k, col_pofk};
759 const int nheaderlines = 1;
762 karr.resize(pofkdata.size());
763 power.resize(pofkdata.size());
764 transfer.resize(pofkdata.size());
765 power_primordial.resize(pofkdata.size());
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);
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";
800 }
else if (ic_type_of_input ==
"transferfunction") {
805 const int col_tofk = 1;
806 std::vector<int> cols_to_keep{col_k, col_tofk};
807 const int nheaderlines = 1;
810 karr.resize(tofkdata.size());
811 power.resize(tofkdata.size());
812 transfer.resize(tofkdata.size());
813 power_primordial.resize(tofkdata.size());
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);
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";
848 }
else if (ic_type_of_input ==
"transferinfofile") {
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(),
860 transferdata->read_transfer(ic_input_filename);
863 grav->set_transferdata(transferdata);
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);
876 power_primordial.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));
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;
891 throw std::runtime_error(
"Unknown ic type[" + ic_type_of_input +
"]");
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)");
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";
908 FML::assert_mpi(power_initial_spline(0.01) == power_initial_spline(0.01),
"NaN detected");
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);
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);
919 auto pofk_atnormtime_over_volume = [&](
double kBox) {
921 grav_ic->get_D_1LPT(1.0 / (1.0 + ic_sigma8_redshift), kBox / simulation_boxsize / grav_ic->H0_hmpc);
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);
933 const double pofk_norm_factor = ic_sigma8_normalization ? std::pow(ic_sigma8 / sigma8, 2) : 1.0;
936 if (pofk_norm_factor != 1.0) {
937 for (
auto & p :
power) {
938 p *= pofk_norm_factor;
940 for (
auto & p : power_primordial) {
941 p *= pofk_norm_factor;
943 for (
auto & t : transfer) {
944 t *= std::sqrt(pofk_norm_factor);
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");
952 transferdata->set_As(transferdata->get_As() * pofk_norm_factor);
955 cosmo->set_As(cosmo->get_As() * pofk_norm_factor);
960 std::cout <<
"#=====================================================\n";
961 std::cout <<
"Updated cosmology and gravitymodel to reflect change of As:\n";
962 std::cout <<
"#=====================================================\n";
970 auto make_sigma_spline = [&]() {
972 const double Rmin_mpch = 0.01;
973 const double Rmax_mpch = 100.0;
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));
980 return Spline(R_mpch, sigma,
"sigma(R_mpch,z=0.0)");
982 auto sigma_spline = make_sigma_spline();
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))
999 std::cout <<
"#=====================================================\n";
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>();
1013 throw std::runtime_error(
"Unknown random generator " + ic_random_generator);
1014 rng->set_seed(ic_random_seed);
1018 FFTWGrid<NDIM> delta_ini_fourier(ic_nmesh, nextra.first, nextra.second);
1024 timer.StartTiming(
"InitialDensityField");
1025 if (ic_random_field_type ==
"gaussian") {
1027 auto Pofk_of_kBox_over_volume = [&](
double kBox) {
1028 return power_initial_spline(kBox / simulation_boxsize) / std::pow(simulation_boxsize,
NDIM);
1030 FML::RANDOM::GAUSSIAN::generate_gaussian_random_field_fourier<NDIM>(
1031 delta_ini_fourier, rng.get(), Pofk_of_kBox_over_volume, ic_fix_amplitude);
1033 }
else if (ic_random_field_type ==
"nongaussian") {
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),
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);
1052 Pofk_of_kBox_over_Pofk_primordal,
1053 Pofk_of_kBox_over_volume_primordial,
1058 }
else if (ic_random_field_type ==
"read_particles") {
1061 throw std::runtime_error(
"Unknown ic_random_field_type [" + ic_random_field_type +
"]");
1063 timer.EndTiming(
"InitialDensityField");
1066 if (ic_reverse_phases) {
1069#pragma omp parallel for
1071 for (
int islice = 0; islice < Local_nx; islice++) {
1072 for (
auto && fourier_index : delta_ini_fourier.
get_fourier_range(islice, islice + 1)) {
1081 if (ic_random_field_type ==
"read_particles") {
1086 const double aini = 1.0 / (1.0 + ic_initial_redshift);
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");
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);
1104 FML::NBODY::NBodyInitialConditions<NDIM, T>(part,
1106 particle_allocation_factor,
1108 phi_nLPT_potentials,
1111 ic_initial_redshift,
1115 if (simulation_use_cola and simulation_use_scaledependent_cola) {
1116 if (FML::PARTICLE::has_get_D_1LPT<T>()) {
1118 phi_1LPT_ini_fourier = delta_ini_fourier;
1120 auto Local_x_start = phi_1LPT_ini_fourier.get_local_x_start();
1121 auto Local_nx = phi_1LPT_ini_fourier.get_local_nx();
1123#pragma omp parallel for
1125 for (
int islice = 0; islice < Local_nx; islice++) {
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)
1131 phi_1LPT_ini_fourier.get_fourier_wavevector_and_norm2_by_index(fourier_index, kvec, kmag2);
1134 phi_1LPT_ini_fourier.set_fourier_from_index(fourier_index, value);
1138 if (Local_x_start == 0)
1139 phi_1LPT_ini_fourier.set_fourier_from_index(0, 0.0);
1141 if (FML::PARTICLE::has_get_D_2LPT<T>()) {
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)");
1147 if (FML::PARTICLE::has_get_D_3LPTa<T>() and FML::PARTICLE::has_get_D_3LPTb<T>()) {
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)");
1157 timer.EndTiming(
"InitialConditions");
1163 if (simulation_use_cola) {
1164 cola_initialize_velocities<NDIM, T>(part);
1168template <
int NDIM,
class T>
1170 timer.StartTiming(
"Timestepping");
1173 const auto nleftright =
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");
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]);
1192 for (
size_t ioutput = 0; ioutput < output_redshifts.size(); ioutput++) {
1195 double z = 1.0 / as.first[icount + i] - 1.0;
1196 if (
z < output_redshifts[ioutput] + 1e-3)
1200 nsteps_between_outputs.push_back(i);
1203 timestep_nsteps = nsteps_between_outputs;
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]
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";
1237 std::cout <<
"#=====================================================\n";
1238 std::cout <<
"# Starting main time-stepping loop\n";
1239 std::cout <<
"#=====================================================\n\n";
1242 int istep_total = 0;
1243 for (
size_t ioutput = 0; ioutput < output_redshifts.size(); ioutput++) {
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]);
1254 auto delta_time = compute_deltatime_KDK(amin, amax, timestep_nsteps[ioutput]);
1259 if (timestep_nsteps[ioutput] > 0)
1260 for (
int istep = 0; istep <= timestep_nsteps[ioutput]; istep++) {
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];
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";
1282 if (istep < timestep_nsteps[ioutput])
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");
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,
1302 timer.EndTiming(
"ComputeForce");
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");
1313 if (simulation_use_cola) {
1314 timer.StartTiming(
"COLA");
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,
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,
1332 cola_kick_drift<NDIM, T>(part, grav,
aini, apos, apos_new, delta_time_kick, delta_time_drift);
1334 timer.EndTiming(
"COLA");
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");
1354 analyze_and_output(ioutput, output_redshifts[ioutput]);
1356 timer.EndTiming(
"Timestepping");
1361 timer.EndTiming(
"The whole simulation");
1363 timer.PrintAllTimings();
1366#ifdef MEMORY_LOGGING
1372template <
int NDIM,
class T>
1376 std::cout <<
"Adding particles (baryons+CDM) to the densityfield\n";
1384 part.get_npart_total(),
1385 density_grid_fourier,
1386 force_density_assignment_method);
1397 const double redshift = 1.0 / a - 1.0;
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});
1410 if (force_linear_massive_neutrinos and cosmo->get_OmegaMNu() > 0.0 and transferdata) {
1413 if (not initial_density_field_fourier) {
1414 initial_density_field_fourier = density_grid_fourier;
1416 FML::assert_mpi(std::fabs(redshift - ic_initial_redshift) < 1e-3,
"This should not happen");
1420 std::cout <<
"Adding linear massive neutrinos to the densityfield\n";
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);
1433 const double OmegaM = cosmo->get_OmegaM();
1434 const double OmegaMNu = cosmo->get_OmegaMNu();
1435 const double fMNu = OmegaMNu /
OmegaM;
1437 auto Local_nx = initial_density_field_fourier.get_local_nx();
1439#pragma omp parallel for
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)) {
1446 auto delta_ini = initial_density_field_fourier.get_fourier_from_index(fourier_index);
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});
1472template <
int NDIM,
class T>
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;
1484 output_folder + (output_folder ==
"" ?
"" :
"/") +
"snapshot_" + simulation_name +
"_z" + redshiftstring;
1486 throw std::runtime_error(
"Failed to create snapshot folder [" + snapshot_folder +
"]");
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";
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,
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,
1513 cola_add_on_LPT_velocity<NDIM, T>(part, grav,
aini, a, addsubtract_sign);
1522 if (simulation_use_cola) {
1523 timer.StartTiming(
"COLA output");
1524 add_on_LPT_velocity(+1.0);
1525 timer.EndTiming(
"COLA output");
1532 if (pofk_cb_every_step.size() > 0 or pofk_total_every_step.size() > 0) {
1540 timer.StartTiming(
"Power-spectrum");
1542 timer.EndTiming(
"Power-spectrum");
1548 if (pofk_multipole) {
1549 timer.StartTiming(
"Power-spectrum multipoles");
1551 timer.EndTiming(
"Power-spectrum multipoles");
1558 timer.StartTiming(
"FOF");
1560 timer.EndTiming(
"FOF");
1567 timer.StartTiming(
"Bispectrum");
1569 timer.EndTiming(
"Bispectrum");
1575 if (output_particles) {
1576 timer.StartTiming(
"Output particles");
1577 if (output_fileformat ==
"GADGET")
1579 if (output_fileformat ==
"FML") {
1580 output_fml(*
this, redshift, snapshot_folder);
1582 timer.EndTiming(
"Output particles");
1588 if (simulation_use_cola) {
1589 timer.StartTiming(
"COLA output");
1590 add_on_LPT_velocity(-1.0);
1591 timer.EndTiming(
"COLA output");
1595template <
int NDIM,
class T>
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();
1605template <
int NDIM,
class T>
1610 std::cout <<
"#=====================================================\n";
1611 std::cout <<
"# Reading initial conditions from GADGET files [" + ic_reconstruct_gadgetfilepath +
"]\n";
1612 std::cout <<
"#=====================================================\n";
1620 const std::string fileprefix = ic_reconstruct_gadgetfilepath;
1621 const bool only_keep_part_in_domain =
true;
1623 g.
read_gadget(fileprefix, externalpart, particle_allocation_factor, only_keep_part_in_domain,
verbose);
1628 const double scale_factor = header.time;
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 "
1637 const double vel_norm = scale_factor / (100 * simulation_boxsize);
1639#pragma omp parallel for
1641 for (
size_t i = 0; i < externalpart.size(); i++) {
1643 for (
int idim = 0; idim <
NDIM; idim++)
1644 vel[idim] *= vel_norm;
1648 part.move_from(std::move(externalpart));
1651 const auto nleftright =
1653 FFTWGrid<NDIM> delta_fourier(ic_nmesh, nleftright.first, nleftright.second);
1656 part.get_npart_total(),
1658 ic_reconstruct_assigment_method,
1659 ic_reconstruct_interlacing);
1662 FML::INTERPOLATION::deconvolve_window_function_fourier<NDIM>(delta_fourier, ic_reconstruct_assigment_method);
1668 delta_fourier, ic_reconstruct_dimless_smoothing_scale, ic_reconstruct_smoothing_filter);
1671 if (simulation_use_cola) {
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");
1679 if constexpr (FML::PARTICLE::has_get_D_1LPT<T>()) {
1682 std::cout <<
"Reconstructing 1LPT potential...\n";
1686 FFTWGrid<NDIM> & phi_1LPT_fourier = simulation_use_scaledependent_cola ? phi_1LPT_ini_fourier : temp;
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();
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");
1701 auto * part_ptr = part.get_particles_ptr();
1703#pragma omp parallel for
1705 for (
size_t ind = 0; ind < part.get_npart(); 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];
1713 if constexpr (FML::PARTICLE::has_get_q<T>()) {
1715 for (
int idim = 0; idim <
NDIM; idim++) {
1716 q[idim] = pos[idim] - D[idim];
1723 if constexpr (FML::PARTICLE::has_get_D_2LPT<T>()) {
1726 std::cout <<
"Reconstructing 2LPT potential...\n";
1730 FFTWGrid<NDIM> & phi_2LPT_fourier = simulation_use_scaledependent_cola ? phi_2LPT_ini_fourier : temp;
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();
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");
1746 auto * part_ptr = part.get_particles_ptr();
1748#pragma omp parallel for
1750 for (
size_t ind = 0; ind < part.get_npart(); ind++) {
1752 for (
int idim = 0; idim <
NDIM; idim++) {
1753 D[idim] = displacements[idim][ind];
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)
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)
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)
FML::UTILS::ParameterMap ParameterMap
FML::INTERPOLATION::SPLINE::Spline Spline
FML::RANDOM::GSLRandomGenerator GSLRandomGenerator
FML::FILEUTILS::GADGET::GadgetReader GadgetReader
FML::FILEUTILS::LinearTransferData LinearTransferData
FML::INTERPOLATION::SPLINE::DVector DVector
FML::SOLVERS::ODESOLVER::ODESolver ODESolver
FML::SOLVERS::ODESOLVER::ODEFunction ODEFunction
FML::RANDOM::RandomGenerator RandomGenerator
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.
GadgetHeader get_header()
Get the header (assumes it has been read)
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.
This class reads transfer/power-spectrum data from the output of a Einstein-Boltzmann solver.
Class for holding grids and performing real-to-complex and complex-to-real FFTs using FFTW with MPI.
int get_nmesh() const
Number of grid-cells per dimension.
void add_memory_label(std::string label)
For memory logging: add a label to the grid.
ptrdiff_t get_local_nx() const
Number of local x-slices in the real grid.
void set_fourier_from_index(const IndexIntType ind, const ComplexType value)
Set value of cell in fourier grid using (local) index.
ComplexType get_fourier_from_index(const IndexIntType index) const
Fetch value in fourier grid by (local) index.
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....
void fftw_r2c()
Perform real-to-complex fourier transform.
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.
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?
This is a wrapper class for easy use of GSL splines It is (OpenMP) thread safe as long as splines are...
A container class for holding particles that are distributed across many CPUs and to easily deal with...
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 ...
DVector get_final_data() const
Get the solution at the end point.
void solve(ODEFunctionPointer ode_equation, void *parameters, DVector &xarr, DVector &yinitial, const gsl_odeiv2_step_type *stepper=ODESOLVER_FIDUCIAL_STEPPER, ODEFunctionPointerJacobian jacobian=nullptr)
For holding a map of parameters of different types with easy set and get's allowing for fiducial valu...
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.
void StartTiming(const char *name)
Start timing.
Base class for gravity models.
std::shared_ptr< GravityModel< NDIM > > grav
Everything related to gravity: growth factors, computing forces.
Spline power_initial_spline
void compute_density_field_fourier(FFTWGrid< NDIM > &density_grid_fourier, double a)
From particles to density field.
std::pair< std::vector< double >, std::vector< double > > compute_deltatime_KDK(double amin, double amax, int nsteps)
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
friend void compute_power_spectrum_multipoles(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
bool bispectrum_interlacing
bool simulation_use_scaledependent_cola
std::string bispectrum_density_assignment_method
NBodySimulation(std::shared_ptr< Cosmology > cosmo, std::shared_ptr< GravityModel< NDIM > > grav, MPIParticles< T > &&_part)
std::string force_density_assignment_method
double fof_linking_length
NBodySimulation(std::shared_ptr< Cosmology > cosmo, std::shared_ptr< GravityModel< NDIM > > grav)
FML::UTILS::Timings timer
bool pofk_multipole_subtract_shotnoise
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_every_output
FFTWGrid< NDIM > phi_1LPT_ini_fourier
friend void output_gadget(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
FFTWGrid< NDIM > phi_3LPTa_ini_fourier
std::string ic_reconstruct_smoothing_filter
std::string timestep_scalefactor_spacing
friend void generate_initial_conditions(NBodySimulation< _NDIM, _T > &sim)
double fof_buffer_length_mpch
std::string pofk_density_assignment_method
std::pair< std::vector< double >, std::vector< double > > compute_scalefactors_KDK(double amin, double amax, int nsteps)
std::string ic_input_filename
std::vector< double > output_redshifts
MPIParticles< T > part
All the particles.
std::string ic_random_generator
std::string timestep_algorithm
std::string ic_reconstruct_assigment_method
std::string output_folder
void read_ic()
This method simply read particles and uses them for the simulation.
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_total_every_step
bool ic_use_gravity_model_GR
void analyze_and_output(int ioutput, double redshift)
Compute stuff on the fly and output.
void read_parameters(ParameterMap ¶m)
Read in and set parameters we need.
FFTWGrid< NDIM > phi_3LPTb_ini_fourier
bool force_linear_massive_neutrinos
FFTWGrid< NDIM > phi_2LPT_ini_fourier
friend void compute_power_spectrum(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
std::shared_ptr< LinearTransferData > transferdata
Everything related to linear perturbations, transfer functions, initial pofk This is only used if ic_...
friend void compute_bispectrum(NBodySimulation< _NDIM, _T > &sim, double redshift, std::string snapshot_folder)
Spline transfer_initial_spline
friend void output_pofk_for_every_step(NBodySimulation< _NDIM, _T > &sim)
void init()
Initialize simulation. Create initial conditions. Make it ready to run.
std::string ic_type_of_input
std::shared_ptr< ParameterMap > parameters
A copy of the simulation parameters just to have it.
bool ic_reconstruct_interlacing
std::vector< std::pair< double, std::vector< PowerSpectrumBinning< NDIM > > > > pofk_multipoles_every_output
bool bispectrum_subtract_shotnoise
std::string simulation_name
std::shared_ptr< Cosmology > cosmo
Everything related to the background evolution.
double simulation_boxsize
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...
NBodySimulation()=default
double ic_reconstruct_dimless_smoothing_scale
std::string ic_reconstruct_gadgetfilepath
std::string ic_random_field_type
double timestep_spacing_power
std::string timestep_method
bool pofk_multipole_interlacing
bool pofk_subtract_shotnoise
std::string pofk_multipole_density_assignment_method
int pofk_multipole_ellmax
void run()
Run simulation.
std::vector< int > timestep_nsteps
Spline power_primordial_spline
double timestep_cola_nLPT
bool ic_sigma8_normalization
std::vector< std::pair< double, PowerSpectrumBinning< NDIM > > > pofk_cb_every_step
double ic_sigma8_redshift
std::string output_fileformat
double ic_initial_redshift
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)
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...
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
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,...
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
bool create_folder(std::string foldername)
constexpr long long int power(int base, int exponent)
Simple integer a^b power-function by squaring.
int ThisTask
The MPI task number.
void print_system_memory_use()
Print the resident set size and the peak value of it so far.
std::vector< T, Allocator< T > > Vector