87 {
88
89
90
91
92
93
94 int LPT_order_COLA = 0;
96 if constexpr (FML::PARTICLE::has_get_D_1LPT<Particle>())
97 LPT_order_COLA = 1;
98 if constexpr (FML::PARTICLE::has_get_D_2LPT<Particle>())
99 LPT_order_COLA = 2;
100 if constexpr (FML::PARTICLE::has_get_D_3LPTa<Particle>() or
FML::PARTICLE::has_get_D_3LPTb<
Particle>())
101 LPT_order_COLA = 3;
102 LPT_order_COLA = std::min(LPT_order_COLA,
LPT_order_IC);
103 }
104
105
106
107
108
111
112
113
114
115
117 if (!fp.is_open())
118 throw std::runtime_error("Cannot open file: " +
filename);
119 std::vector<double> logk;
120 std::vector<double> logpofk;
122 double kin, pofkin;
123 fp >> kin;
124 if (fp.eof())
125 break;
126 fp >> pofkin;
127 logk.push_back(std::log(kin));
128 logpofk.push_back(std::log(pofkin));
129 }
130
132
133
134
135
136
137
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;
143 };
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);
147 };
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);
150 };
151
152
153
154
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) {
158 };
159 std::function<double(double)> growth_rate_f_2LPT_of_loga = [&](double loga) {
161 };
162 std::function<double(double)> growth_rate_f_3LPTa_of_loga = [&](double loga) {
164 };
165 std::function<double(double)> growth_rate_f_3LPTb_of_loga = [&](double loga) {
167 };
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);
173
174
175
176
177 std::shared_ptr<FML::RANDOM::RandomGenerator> rng = std::make_shared<FML::RANDOM::RandomGenerator>();
179
180
181
182
183
184 std::vector<double> velocity_norms(4);
185 for (int i = 0; i < 4; i++) {
186 velocity_norms[i] =
187 100.0 *
box * H_over_H0_of_loga(std::log(
aini)) *
aini * growth_rate_f_of_loga[i](std::log(
aini));
188 }
189
191 FML::NBODY::NBodyInitialConditions<NDIM, Particle>(part,
196 rng.get(),
197 Pofk_of_kBox_over_Pofk_primordial,
198 Pofk_of_kBox_over_volume_primordial,
204 velocity_norms);
205
206
207
208
210
211 for (auto & p : part) {
213 for (
int idim = 0; idim <
NDIM; idim++) {
214 vel[idim] = 0.0;
215 }
216 }
217 }
218
219
220
221
222
223
224
225 auto poisson_factor = [&](
double a) {
return 1.5 *
OmegaM * a; };
226
227 auto compute_vel_timestep = [&](double alow, double ahigh) {
228
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);
232 return GSL_SUCCESS;
233 };
234
235
239 ode.
solve(deriv, avec, tini);
241 };
242
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));
246 return GSL_SUCCESS;
247 };
248
252 ode.
solve(deriv, avec, tini);
254 };
255
256
257
258
259 for (
int i = 0; i <=
nsteps; i++) {
260
261
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);
267
268
269
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);
273
274
278 part.get_npart(),
279 part.get_npart_total(),
280 density_grid_fourier,
282 density_grid_fourier.fftw_r2c();
283
284
285
286
287
288 std::array<FFTWGrid<NDIM>,
NDIM> force_real;
289 FML::NBODY::compute_force_from_density_fourier<NDIM>(
291
292
294
295
300 const double fac1_pos = (D1new - D1old) / D1ini;
301 const double fac1_vel = -norm_poisson_equation * D1old / D1ini * delta_time_vel;
302
306 const double fac2_pos = (D2new - D2old) / D2ini;
307 const double fac2_vel = -norm_poisson_equation * (D2old - D1old * D1old) / D2ini * delta_time_vel;
308
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;
315
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;
322
323
324 for (auto & p : part) {
327
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;
333 }
334 }
335
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;
341 }
342 }
343
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;
350 }
351 }
352
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;
359 }
360 }
361 }
362 }
363
364
365 FML::NBODY::DriftParticles<NDIM, Particle>(part, delta_time_pos);
366
368 std::cout << i <<
" / " <<
nsteps <<
" Positions at a: " << apos_new <<
" Velocities at a: " << avel_new
369 << "\n";
370
371
372 part.info();
373 }
374
375
376
377
378
379
389 const double vfac_1LPT =
391 const double vfac_2LPT =
393 const double vfac_3LPTa =
395 const double vfac_3LPTb =
397
398
399 for (auto & p : part) {
401
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;
407 }
408 }
409
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;
415 }
416 }
417
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;
423 }
424 }
425
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;
431 }
432 }
433 }
434 }
435
436
437
438
439
441 std::cout << "Compute power spectrum\n";
442 }
443
444 const bool interlacing = true;
445 const std::string density_assignment = "CIC";
447 FML::CORRELATIONFUNCTIONS::compute_power_spectrum<NDIM>(
Nmesh,
448 part.get_particles_ptr(),
449 part.get_npart(),
450 part.get_npart_total(),
452 density_assignment,
453 interlacing);
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";
460 }
461 }
462
463
464
465
466
467
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);
473
474
475 for (size_t ell = 0; ell < Pells.size(); ell++) {
476 Pells[ell].scale(
box);
477 }
478
479
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] << " ";
488
489
490 if (ell == 0)
491 fp <<
pofk.pofk[i] * (1.0 + 2. * f / 3. + f * f / 5.) <<
" ";
492 if (ell == 2)
493 fp <<
pofk.pofk[i] * (4. * f / 3. + 4. * f * f / 7.) <<
" ";
494 if (ell == 4)
495 fp <<
pofk.pofk[i] * (8. * f * f / 35.) <<
" ";
496 }
497 fp << "\n";
498 }
499 fp << "\n";
500 }
501
502
503
504
506 0.0,
507 2.0 * M_PI *
Nmesh / 2,
511 part.get_particles_ptr(),
512 part.get_npart(),
513 part.get_npart_total(),
514 bofk,
515 density_assignment,
516 interlacing);
518
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];
528 double B123 = bofk.get_spectrum(i, j,
k);
529 double Q123 = bofk.get_reduced_spectrum(i, j,
k);
530 double N123 = bofk.get_bincount(i, j,
k);
531 fp << k1 << " " << k2 << " " << k3 << " " << B123 << " " << Q123 << " " << N123 << "\n";
532 }
533 }
534 }
535 }
536
537
538
539
540
541 part.communicate_particles();
542 std::vector<FoFHalo> FoFGroups;
544 FML::FOF::FriendsOfFriends<Particle, NDIM>(part.get_particles_ptr(),
545 part.get_npart(),
548 true,
549 bufferlength,
550 FoFGroups,
552
553
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) {
559 if (g.np > 0) {
560 fp << g.np << " ";
561 for (
int idim = 0; idim <
NDIM; idim++)
562 fp << g.pos[idim] *
box <<
" ";
563 fp << "\n";
564 }
565 }
566 }
567#ifdef USE_MPI
568 MPI_Barrier(MPI_COMM_WORLD);
569#endif
570 }
571
572#ifdef MEMORY_LOGGING
573
575#endif
576}
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::INTERPOLATION::SPLINE::DVector DVector
FML::SOLVERS::ODESOLVER::ODEFunction ODEFunction
Class for storing the results from general polyspectrum.
Class for holding the results after binning up a power-spectrum.
Class for holding grids and performing real-to-complex and complex-to-real FFTs using FFTW with MPI.
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...
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(...)
int ThisTask
The MPI task number.
int NTasks
Total number of MPI tasks.