39const double box = 1000.0;
46const double fNL = 100.0;
67const double A_s = 2e-9;
68const double n_s = 0.96;
94 int LPT_order_COLA = 0;
96 if constexpr (FML::PARTICLE::has_get_D_1LPT<Particle>())
98 if constexpr (FML::PARTICLE::has_get_D_2LPT<Particle>())
100 if constexpr (FML::PARTICLE::has_get_D_3LPTa<Particle>() or FML::PARTICLE::has_get_D_3LPTb<Particle>())
102 LPT_order_COLA = std::min(LPT_order_COLA,
LPT_order_IC);
118 throw std::runtime_error(
"Cannot open file: " +
filename);
119 std::vector<double> logk;
120 std::vector<double> logpofk;
127 logk.push_back(std::log(kin));
128 logpofk.push_back(std::log(pofkin));
139 auto Pofk_of_kBox_over_volume = [&](
double kBox) {
140 const double logk = std::log(kBox /
box);
141 const double volume = std::pow(
box,
NDIM);
142 return DiniOverD * DiniOverD *
std::exp(logpofk_spline(logk)) / volume;
144 auto Pofk_of_kBox_over_volume_primordial = [&](
double kBox) {
145 const double k = kBox /
box;
146 return 2.0 * M_PI * M_PI / (kBox * kBox * kBox) *
A_s * std::pow(
k /
kpivot,
n_s - 1.0);
148 auto Pofk_of_kBox_over_Pofk_primordial = [&](
double kBox) {
149 return Pofk_of_kBox_over_volume(kBox) / Pofk_of_kBox_over_volume_primordial(kBox);
155 auto H_over_H0_of_loga = [&](
double loga) {
return HoverH0(
std::exp(loga)); };
156 std::function<double(
double)> growth_rate_f_1LPT_of_loga = [&](
double loga) {
159 std::function<double(
double)> growth_rate_f_2LPT_of_loga = [&](
double loga) {
162 std::function<double(
double)> growth_rate_f_3LPTa_of_loga = [&](
double loga) {
165 std::function<double(
double)> growth_rate_f_3LPTb_of_loga = [&](
double loga) {
168 std::vector<std::function<double(
double)>> growth_rate_f_of_loga;
169 growth_rate_f_of_loga.push_back(growth_rate_f_1LPT_of_loga);
170 growth_rate_f_of_loga.push_back(growth_rate_f_2LPT_of_loga);
171 growth_rate_f_of_loga.push_back(growth_rate_f_3LPTa_of_loga);
172 growth_rate_f_of_loga.push_back(growth_rate_f_3LPTb_of_loga);
177 std::shared_ptr<FML::RANDOM::RandomGenerator> rng = std::make_shared<FML::RANDOM::RandomGenerator>();
184 std::vector<double> velocity_norms(4);
185 for (
int i = 0; i < 4; i++) {
187 100.0 *
box * H_over_H0_of_loga(std::log(
aini)) *
aini * growth_rate_f_of_loga[i](std::log(
aini));
191 FML::NBODY::NBodyInitialConditions<NDIM, Particle>(part,
197 Pofk_of_kBox_over_Pofk_primordial,
198 Pofk_of_kBox_over_volume_primordial,
211 for (
auto & p : part) {
213 for (
int idim = 0; idim <
NDIM; idim++) {
225 auto poisson_factor = [&](
double a) {
return 1.5 *
OmegaM * a; };
227 auto compute_vel_timestep = [&](
double alow,
double ahigh) {
229 const double amid = (ahigh + alow) / 2.;
230 ODEFunction deriv = [&](
double a, [[maybe_unused]]
const double * t,
double * dtda) {
231 dtda[0] = 1.0 / (a * a * a *
HoverH0(a)) * poisson_factor(a) / poisson_factor(amid);
239 ode.
solve(deriv, avec, tini);
243 auto compute_pos_timestep = [&](
double alow,
double ahigh) {
244 ODEFunction deriv = [&](
double a, [[maybe_unused]]
const double * t,
double * dtda) {
245 dtda[0] = 1.0 / (a * a * a *
HoverH0(a));
252 ode.
solve(deriv, avec, tini);
259 for (
int i = 0; i <=
nsteps; i++) {
263 const double apos_old =
aini + delta_aexp * i;
264 const double apos_new = (i ==
nsteps) ?
aend : apos_old + delta_aexp;
265 const double avel_old = (i == 0) ?
aini : apos_old - 0.5 * delta_aexp;
266 const double avel_new = (i == 0) ?
aini + 0.5 * delta_aexp : (i ==
nsteps ?
aend : apos_old + 0.5 * delta_aexp);
270 const double delta_time_pos = compute_pos_timestep(apos_old, apos_new);
271 const double delta_time_vel = compute_vel_timestep(avel_old, avel_new);
272 const double norm_poisson_equation = poisson_factor(apos_old);
280 density_grid_fourier,
288 std::array<FFTWGrid<NDIM>,
NDIM> force_real;
289 FML::NBODY::compute_force_from_density_fourier<NDIM>(
300 const double fac1_pos = (D1new - D1old) / D1ini;
301 const double fac1_vel = -norm_poisson_equation * D1old / D1ini * delta_time_vel;
306 const double fac2_pos = (D2new - D2old) / D2ini;
307 const double fac2_vel = -norm_poisson_equation * (D2old - D1old * D1old) / D2ini * delta_time_vel;
312 const double fac3a_pos = (D3anew - D3aold) / D3aini;
313 const double fac3a_vel =
314 -norm_poisson_equation * (D3aold - 2.0 * D1old * D1old * D1old) / D3aini * delta_time_vel;
319 const double fac3b_pos = (D3bnew - D3bold) / D3bini;
320 const double fac3b_vel =
321 -norm_poisson_equation * (D3bold + D1old * D1old * D1old - D1old * D2old) / D3bini * delta_time_vel;
324 for (
auto & p : part) {
328 if (LPT_order_COLA >= 1) {
329 auto * D1 = FML::PARTICLE::GetD_1LPT(p);
330 for (
int idim = 0; idim <
NDIM; idim++) {
331 pos[idim] += D1[idim] * fac1_pos;
332 vel[idim] += D1[idim] * fac1_vel;
336 if (LPT_order_COLA >= 2) {
338 for (
int idim = 0; idim <
NDIM; idim++) {
339 pos[idim] += D2[idim] * fac2_pos;
340 vel[idim] += D2[idim] * fac2_vel;
344 if constexpr (FML::PARTICLE::has_get_D_3LPTa<Particle>())
345 if (LPT_order_COLA >= 3) {
347 for (
int idim = 0; idim <
NDIM; idim++) {
348 pos[idim] += D3a[idim] * fac3a_pos;
349 vel[idim] += D3a[idim] * fac3a_vel;
353 if constexpr (FML::PARTICLE::has_get_D_3LPTb<Particle>())
354 if (LPT_order_COLA >= 3) {
356 for (
int idim = 0; idim <
NDIM; idim++) {
357 pos[idim] += D3b[idim] * fac3b_pos;
358 vel[idim] += D3b[idim] * fac3b_vel;
365 FML::NBODY::DriftParticles<NDIM, Particle>(part, delta_time_pos);
368 std::cout << i <<
" / " <<
nsteps <<
" Positions at a: " << apos_new <<
" Velocities at a: " << avel_new
389 const double vfac_1LPT =
391 const double vfac_2LPT =
393 const double vfac_3LPTa =
395 const double vfac_3LPTb =
399 for (
auto & p : part) {
402 if constexpr (FML::PARTICLE::has_get_D_1LPT<Particle>())
403 if (LPT_order_COLA >= 1) {
404 auto * D1 = FML::PARTICLE::GetD_1LPT(p);
405 for (
int idim = 0; idim <
NDIM; idim++) {
406 vel[idim] += D1[idim] * vfac_1LPT;
410 if constexpr (FML::PARTICLE::has_get_D_2LPT<Particle>())
411 if (LPT_order_COLA >= 2) {
413 for (
int idim = 0; idim <
NDIM; idim++) {
414 vel[idim] += D2[idim] * vfac_2LPT;
418 if constexpr (FML::PARTICLE::has_get_D_3LPTa<Particle>())
419 if (LPT_order_COLA >= 3) {
421 for (
int idim = 0; idim <
NDIM; idim++) {
422 vel[idim] += D3a[idim] * vfac_3LPTa;
426 if constexpr (FML::PARTICLE::has_get_D_3LPTb<Particle>())
427 if (LPT_order_COLA >= 3) {
429 for (
int idim = 0; idim <
NDIM; idim++) {
430 vel[idim] += D3b[idim] * vfac_3LPTb;
441 std::cout <<
"Compute power spectrum\n";
444 const bool interlacing =
true;
445 const std::string density_assignment =
"CIC";
447 FML::CORRELATIONFUNCTIONS::compute_power_spectrum<NDIM>(
Nmesh,
456 std::ofstream fp(
"pofk_out.txt");
457 fp <<
"\n# k (h/Mpc) P(k) (Mpc/h)^3\n";
458 for (
int i = 0; i <
pofk.n; i++) {
459 fp <<
pofk.kbin[i] <<
" " <<
pofk.pofk[i] <<
"\n";
469 const int ellmax = 4;
470 std::vector<FML::CORRELATIONFUNCTIONS::PowerSpectrumBinning<NDIM>> Pells(1 + ellmax,
Nmesh / 2);
471 FML::CORRELATIONFUNCTIONS::compute_power_spectrum_multipoles<NDIM>(
472 Nmesh, part, velocity_to_displacement, Pells, density_assignment, interlacing);
475 for (
size_t ell = 0; ell < Pells.size(); ell++) {
476 Pells[ell].scale(
box);
481 FML::assert_mpi(Pells[0].n ==
pofk.n,
"We require P(k) and Pell(k) to have the same bins");
482 std::ofstream fp(
"pofk_multipoles_out.txt");
483 const double f = growth_rate_f_1LPT_of_loga(std::log(
aend));
484 for (
int i = 0; i < Pells[0].n; i++) {
485 fp << Pells[0].k[i] <<
" ";
486 for (
size_t ell = 0; ell < Pells.size(); ell += 2) {
487 fp << Pells[ell].pofk[i] <<
" ";
491 fp <<
pofk.pofk[i] * (1.0 + 2. * f / 3. + f * f / 5.) <<
" ";
493 fp <<
pofk.pofk[i] * (4. * f / 3. + 4. * f * f / 7.) <<
" ";
495 fp <<
pofk.pofk[i] * (8. * f * f / 35.) <<
" ";
507 2.0 * M_PI *
Nmesh / 2,
520 std::ofstream fp(
"bofk_out.txt");
521 fp <<
"# k1 k2 k3 B123 Q123 N123\n";
525 double k1 = bofk.
kmean[i];
526 double k2 = bofk.
kmean[j];
527 double k3 = bofk.
kmean[
k];
531 fp << k1 <<
" " << k2 <<
" " << k3 <<
" " << B123 <<
" " << Q123 <<
" " << N123 <<
"\n";
542 std::vector<FoFHalo> FoFGroups;
556 std::cout <<
"\n# Found " << FoFGroups.size() <<
" halos on task " <<
FML::ThisTask <<
"\n";
557 std::ofstream fp(
"halo_out.txt");
558 for (
auto & g : FoFGroups) {
561 for (
int idim = 0; idim <
NDIM; idim++)
562 fp << g.pos[idim] *
box <<
" ";
568 MPI_Barrier(MPI_COMM_WORLD);
SimpleParticle< Ndim > Particle
const unsigned int random_seed
const int nbin_bispectrum
FML::INTERPOLATION::SPLINE::Spline D_3LPTa_of_loga
FML::INTERPOLATION::SPLINE::Spline D_2LPT_of_loga
const std::string filename
const std::string type_of_random_field
const double buffer_factor
const std::string interpolation_method
const int n_min_FoF_group
FML::INTERPOLATION::SPLINE::Spline D_3LPTb_of_loga
const double FoFBoundarySizeMpch
const double linking_length
FML::INTERPOLATION::SPLINE::Spline D_1LPT_of_loga
FML::SOLVERS::ODESOLVER::ODESolver ODESolver
FML::INTERPOLATION::SPLINE::DVector DVector
FML::SOLVERS::ODESOLVER::ODEFunction ODEFunction
Class for storing the results from general polyspectrum.
double get_spectrum(const std::array< int, ORDER > &ik)
Get the polyspectra at (k[ik1], k[ik2], ...)
std::vector< double > kmean
kmean is the mean of wavenumbers added to the bin
void scale(const double boxsize)
To physical units: k *= 1/boxsize and P *= boxsize^((ORDER-1) NDIM)
double get_bincount(const std::array< int, ORDER > &ik)
Returns the volume factor N123.
double get_reduced_spectrum(const std::array< int, ORDER > &ik)
Get the reduced polyspectrum: P / fac where fac = sqrt(P(k1)P(k2)) for order=2 and P(k1)P(k2) + cyc f...
Class for holding the results after binning up a power-spectrum.
This class defines how to compute the halos from the particles.
Class for holding grids and performing real-to-complex and complex-to-real FFTs using FFTW with MPI.
void fftw_r2c()
Perform real-to-complex fourier transform.
This is a wrapper class for easy use of GSL splines It is (OpenMP) thread safe as long as splines are...
double deriv_x(double x) const
Get the value of the first derivative of the spline.
A container class for holding particles that are distributed across many CPUs and to easily deal with...
size_t get_npart_total() const
Total number of active particles across all tasks.
T * get_particles_ptr()
Get a pointer to the first particle.
void communicate_particles()
Communicate particles across CPU boundaries.
void info()
Show some info about the class.
size_t get_npart() const
Number of active particles on the local task.
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)
void compute_bispectrum(int Ngrid, T *part, size_t NumPart, size_t NumPartTotal, BispectrumBinning< N > &bofk, std::string density_assignment_method, bool interlacing)
Computes the bispectrum from particles.
void compute_LPT_growth_factors_LCDM(double OmegaM, double zini, std::function< double(double)> HoverH0_of_a, FML::INTERPOLATION::SPLINE::Spline &D_1LPT_of_loga, FML::INTERPOLATION::SPLINE::Spline &D_2LPT_of_loga, FML::INTERPOLATION::SPLINE::Spline &D_3LPTa_of_loga, FML::INTERPOLATION::SPLINE::Spline &D_3LPTb_of_loga)
Compute 1,2,3LPT growth-factors in LCDM and spline them The growth factors are normalized such that D...
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_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.
get_vel constexpr double * GetPos(...)
constexpr double * GetD_3LPTa(...)
constexpr double * GetVel(...)
constexpr double * GetD_3LPTb(...)
constexpr double * GetD_2LPT(...)
std::function< int(double, const double *, double *)> ODEFunction
std::vector< double > DVector
int ThisTask
The MPI task number.
int NTasks
Total number of MPI tasks.
Example of a particle for COLA N-body simulations that is compatible with the make IC and N-body meth...