MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
Classes | Functions | Variables
glass.c File Reference
#include <mpi.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <omp.h>
#include <gsl/gsl_rng.h>
#include "allvars.h"
#include "proto.h"
#include <libgadget/petapm.h>
#include <libgadget/walltime.h>
#include <libgadget/utils.h>
#include <libgadget/powerspectrum.h>
#include <libgadget/gravity.h>
Include dependency graph for glass.c:

Go to the source code of this file.

Classes

struct  ic_prep_data
 

Functions

static void potential_transfer (PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
 
static void force_x_transfer (PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
 
static void force_y_transfer (PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
 
static void force_z_transfer (PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
 
static void readout_force_x (PetaPM *pm, int i, double *mesh, double weight)
 
static void readout_force_y (PetaPM *pm, int i, double *mesh, double weight)
 
static void readout_force_z (PetaPM *pm, int i, double *mesh, double weight)
 
static PetaPMRegion_prepare (PetaPM *pm, PetaPMParticleStruct *pstruct, void *userdata, int *Nregions)
 
static void glass_force (PetaPM *pm, double t_f, struct ic_part_data *ICP, const int NumPart)
 
static void glass_stats (struct ic_part_data *ICP, int NumPart)
 
int setup_glass (IDGenerator *idgen, PetaPM *pm, double shift, int seed, double mass, struct ic_part_data *ICP, const double UnitLength_in_cm, const char *OutputDir)
 
void glass_evolve (PetaPM *pm, int nsteps, const char *pkoutname, struct ic_part_data *ICP, const int NumPart, const double UnitLength_in_cm, const char *OutputDir)
 
static double diff_kernel (double w)
 
static void force_transfer (PetaPM *pm, int k, pfft_complex *value)
 

Variables

static PetaPMFunctions functions []
 
static PetaPMGlobalFunctions global_functions = {measure_power_spectrum, NULL, potential_transfer}
 
static struct ic_part_datacurICP
 
static double pot_factor
 

Function Documentation

◆ _prepare()

static PetaPMRegion * _prepare ( PetaPM pm,
PetaPMParticleStruct pstruct,
void *  userdata,
int *  Nregions 
)
static

Definition at line 218 of file glass.c.

219 {
220  struct ic_prep_data * icprep = (struct ic_prep_data *) userdata;
221  int NumPart = icprep->NumPart;
222  struct ic_part_data * ICP = icprep->curICP;
223 
224  /* dimensionless invert gravity;
225  *
226  * pot = nabla ^ -2 delta
227  *
228  * (2pi / L) ** -2 is for kint -> k.
229  * Need to divide by mean mass per cell to get delta */
230  pot_factor = -1 * (-1) * pow(2 * M_PI / pm->BoxSize, -2);
231 
232  PetaPMRegion * regions = (PetaPMRegion *) mymalloc2("Regions", sizeof(PetaPMRegion));
233  int k;
234  int r = 0;
235  int i;
236  double min[3] = {pm->BoxSize, pm->BoxSize, pm->BoxSize};
237  double max[3] = {0, 0, 0.};
238  double totmass = 0;
239 
240  for(i = 0; i < NumPart; i ++) {
241  for(k = 0; k < 3; k ++) {
242  if(min[k] > ICP[i].Pos[k])
243  min[k] = ICP[i].Pos[k];
244  if(max[k] < ICP[i].Pos[k])
245  max[k] = ICP[i].Pos[k];
246  }
247 
248  totmass += ICP[i].Mass;
249  }
250 
251  MPI_Allreduce(MPI_IN_PLACE, &totmass, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
252 
253  /* 1 / pow(pm->Nmesh, 3) is included by the FFT, so just use total mass. */
254  pot_factor /= totmass;
255 
256  for(k = 0; k < 3; k ++) {
257  regions[r].offset[k] = floor(min[k] / pm->BoxSize * pm->Nmesh - 1);
258  regions[r].size[k] = ceil(max[k] / pm->BoxSize * pm->Nmesh + 2);
259  regions[r].size[k] -= regions[r].offset[k];
260  }
261 
262  /* setup the internal data structure of the region */
263  petapm_region_init_strides(&regions[r]);
264  *Nregions = 1;
265 
266  walltime_measure("/PMgrav/Regions");
267  return regions;
268 }
static double pot_factor
Definition: glass.c:215
#define mymalloc2(name, size)
Definition: mymalloc.h:16
void petapm_region_init_strides(PetaPMRegion *region)
Definition: petapm.c:813
int Nmesh
Definition: petapm.h:68
double BoxSize
Definition: petapm.h:70
Definition: petapm.h:7
ptrdiff_t size[3]
Definition: petapm.h:10
ptrdiff_t offset[3]
Definition: petapm.h:9
float Mass
Definition: allvars.h:14
double Pos[3]
Definition: allvars.h:10
struct ic_part_data * curICP
Definition: glass.c:173
int NumPart
Definition: glass.c:174
#define walltime_measure(name)
Definition: walltime.h:8

References PetaPM::BoxSize, ic_prep_data::curICP, ic_part_data::Mass, mymalloc2, PetaPM::Nmesh, ic_prep_data::NumPart, Region::offset, petapm_region_init_strides(), ic_part_data::Pos, pot_factor, Region::size, and walltime_measure.

Referenced by glass_force().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ diff_kernel()

static double diff_kernel ( double  w)
static

Definition at line 316 of file glass.c.

316  {
317 /* order N = 1 */
318 /*
319  * This is the same as GADGET-2 but in fourier space:
320  * see gadget-2 paper and Hamming's book.
321  * c1 = 2 / 3, c2 = 1 / 12
322  * */
323  return 1 / 6.0 * (8 * sin (w) - sin (2 * w));
324 }

Referenced by force_transfer().

Here is the caller graph for this function:

◆ force_transfer()

static void force_transfer ( PetaPM pm,
int  k,
pfft_complex *  value 
)
static

Definition at line 326 of file glass.c.

326  {
327  double tmp0;
328  double tmp1;
329  /*
330  * negative sign is from force_x = - Del_x pot
331  *
332  * filter is i K(w)
333  * */
334  double fac = -1 * diff_kernel (k * (2 * M_PI / pm->Nmesh)) * (pm->Nmesh / pm->BoxSize);
335  tmp0 = - value[0][1] * fac;
336  tmp1 = value[0][0] * fac;
337  value[0][0] = tmp0;
338  value[0][1] = tmp1;
339 }
static double diff_kernel(double w)
Definition: glass.c:316

References PetaPM::BoxSize, diff_kernel(), and PetaPM::Nmesh.

Referenced by force_x_transfer(), force_y_transfer(), and force_z_transfer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ force_x_transfer()

static void force_x_transfer ( PetaPM pm,
int64_t  k2,
int  kpos[3],
pfft_complex *  value 
)
static

Definition at line 340 of file glass.c.

340  {
341  force_transfer(pm, kpos[0], value);
342 }
static void force_transfer(PetaPM *pm, int k, pfft_complex *value)
Definition: glass.c:326

References force_transfer().

Here is the call graph for this function:

◆ force_y_transfer()

static void force_y_transfer ( PetaPM pm,
int64_t  k2,
int  kpos[3],
pfft_complex *  value 
)
static

Definition at line 343 of file glass.c.

343  {
344  force_transfer(pm, kpos[1], value);
345 }

References force_transfer().

Here is the call graph for this function:

◆ force_z_transfer()

static void force_z_transfer ( PetaPM pm,
int64_t  k2,
int  kpos[3],
pfft_complex *  value 
)
static

Definition at line 346 of file glass.c.

346  {
347  force_transfer(pm, kpos[2], value);
348 }

References force_transfer().

Here is the call graph for this function:

◆ glass_evolve()

void glass_evolve ( PetaPM pm,
int  nsteps,
const char *  pkoutname,
struct ic_part_data ICP,
const int  NumPart,
const double  UnitLength_in_cm,
const char *  OutputDir 
)

Definition at line 73 of file glass.c.

74 {
75  int i;
76  int step = 0;
77  double t_x = 0;
78  double t_v = 0;
79  double t_f = 0;
80 
81  /*Allocate memory for a power spectrum*/
82  powerspectrum_alloc(pm->ps, pm->Nmesh, omp_get_max_threads(), 0, pm->BoxSize*UnitLength_in_cm);
83 
84  glass_force(pm, t_x, ICP, NumPart);
85 
86  /* Our pick of the units ensures there is an oscillation period of 2 * M_PI.
87  *
88  * (don't ask me how this worked -- I think I failed this problem in physics undergrad. )
89  * We use 4 steps per oscillation, and end at
90  *
91  * 12 + 1 = 13, the first time phase is M_PI / 2, a close encounter to the minimum.
92  *
93  * */
94  for(step = 0; step < nsteps; step++) {
95  /* leap-frog, K D D F K */
96  double dt = M_PI / 2; /* step size */
97  double hdt = 0.5 * dt; /* half a step */
98  int d;
99  /*
100  * Use inverted gravity with a damping term proportional to the velocity.
101  *
102  * The magic setup was studied in
103  * https://github.com/rainwoodman/fastpm-python/blob/1be020b/Example/Glass.ipynb
104  * */
105 
106  /* Kick */
107  for(i = 0; i < NumPart; i ++) {
108  for(d = 0; d < 3; d ++) {
109  /* mind the damping term */
110  ICP[i].Vel[d] += (ICP[i].Disp[d] - ICP[i].Vel[d]) * hdt;
111  }
112  }
113  t_x += hdt;
114 
115  /* Drift */
116  for(i = 0; i < NumPart; i ++) {
117  for(d = 0; d < 3; d ++) {
118  ICP[i].Pos[d] += ICP[i].Vel[d] * dt;
119  }
120  }
121  t_v += dt;
122 
123  glass_force(pm, t_x, ICP, NumPart);
124  t_f = t_x;
125 
126  /* Kick */
127  for(i = 0; i < NumPart; i ++) {
128  for(d = 0; d < 3; d ++) {
129  /* mind the damping term */
130  ICP[i].Vel[d] += (ICP[i].Disp[d] - ICP[i].Vel[d]) * hdt;
131  }
132  }
133 
134  t_x += hdt;
135  message(0, "Generating glass, step = %d, t_f= %g, t_v = %g, t_x = %g\n", step, t_f / (2 * M_PI), t_v / (2 *M_PI), t_x / (2 * M_PI));
136  glass_stats(ICP, NumPart);
137 
138  /*Now save the power spectrum*/
139  powerspectrum_save(pm->ps, OutputDir, pkoutname, t_f, 1.0);
140  }
141 
142  /*We are done with the power spectrum, free it*/
143  powerspectrum_free(pm->ps);
144 }
void message(int where, const char *fmt,...)
Definition: endrun.c:175
static void glass_stats(struct ic_part_data *ICP, int NumPart)
Definition: glass.c:148
static void glass_force(PetaPM *pm, double t_f, struct ic_part_data *ICP, const int NumPart)
Definition: glass.c:181
static double UnitLength_in_cm
Definition: power.c:26
void powerspectrum_save(Power *ps, const char *OutputDir, const char *filename, const double Time, const double D1)
Definition: powerspectrum.c:92
void powerspectrum_free(Power *ps)
Definition: powerspectrum.c:44
void powerspectrum_alloc(Power *ps, const int nbins, const int nthreads, const int MassiveNuLinResp, const double BoxSize_in_cm)
Definition: powerspectrum.c:16
Power ps[1]
Definition: petapm.h:76
float Vel[3]
Definition: allvars.h:11
float Disp[3]
Definition: allvars.h:12

References PetaPM::BoxSize, ic_part_data::Disp, glass_force(), glass_stats(), message(), PetaPM::Nmesh, ic_part_data::Pos, powerspectrum_alloc(), powerspectrum_free(), powerspectrum_save(), PetaPM::ps, UnitLength_in_cm, and ic_part_data::Vel.

Referenced by main(), and setup_glass().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ glass_force()

static void glass_force ( PetaPM pm,
double  t_f,
struct ic_part_data ICP,
const int  NumPart 
)
static

Definition at line 181 of file glass.c.

181  {
182 
183  PetaPMParticleStruct pstruct = {
184  ICP,
185  sizeof(ICP[0]),
186  (char*) &ICP[0].Pos[0] - (char*) ICP,
187  (char*) &ICP[0].Mass - (char*) ICP,
188  NULL,
189  NULL,
190  NumPart,
191  };
192  curICP = ICP;
193 
194  int i;
195  #pragma omp parallel for
196  for(i = 0; i < NumPart; i++)
197  {
198  ICP[i].Disp[0] = ICP[i].Disp[1] = ICP[i].Disp[2] = 0;
199  }
200 
201  powerspectrum_zero(pm->ps);
202 
203  struct ic_prep_data icprep = {ICP, NumPart};
204  /*
205  * we apply potential transfer immediately after the R2C transform,
206  * Therefore the force transfer functions are based on the potential,
207  * not the density.
208  * */
209  petapm_force(pm, _prepare, &global_functions, functions, &pstruct, &icprep);
210 
211  powerspectrum_sum(pm->ps);
212  walltime_measure("/LongRange");
213 }
static PetaPMRegion * _prepare(PetaPM *pm, PetaPMParticleStruct *pstruct, void *userdata, int *Nregions)
Definition: glass.c:218
static struct ic_part_data * curICP
Definition: glass.c:177
static PetaPMGlobalFunctions global_functions
Definition: glass.c:33
static PetaPMFunctions functions[]
Definition: glass.c:25
void petapm_force(PetaPM *pm, petapm_prepare_func prepare, PetaPMGlobalFunctions *global_functions, PetaPMFunctions *functions, PetaPMParticleStruct *pstruct, void *userdata)
Definition: petapm.c:353
void powerspectrum_sum(Power *ps)
Definition: powerspectrum.c:54
void powerspectrum_zero(Power *ps)
Definition: powerspectrum.c:35

References _prepare(), curICP, ic_part_data::Disp, functions, global_functions, ic_part_data::Mass, ic_prep_data::NumPart, petapm_force(), ic_part_data::Pos, powerspectrum_sum(), powerspectrum_zero(), PetaPM::ps, and walltime_measure.

Referenced by glass_evolve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ glass_stats()

static void glass_stats ( struct ic_part_data ICP,
int  NumPart 
)
static

Definition at line 148 of file glass.c.

148  {
149  int i;
150  double disp2 = 0;
151  double vel2 = 0;
152  double n = NumPart;
153  for(i = 0; i < NumPart; i++)
154  {
155  int k;
156  for(k = 0; k < 3; k++)
157  {
158  double dis = ICP[i].Disp[k];
159  double vel = ICP[i].Vel[k];
160  disp2 += dis * dis;
161  vel2 += vel * vel;
162  }
163  }
164  MPI_Allreduce(MPI_IN_PLACE, &disp2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
165  MPI_Allreduce(MPI_IN_PLACE, &vel2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
166  MPI_Allreduce(MPI_IN_PLACE, &n, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
167 
168  message(0, "Force std = %g, vel std = %g\n", sqrt(disp2 / n), sqrt(vel2 / n));
169 }

References ic_part_data::Disp, message(), and ic_part_data::Vel.

Referenced by glass_evolve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ potential_transfer()

static void potential_transfer ( PetaPM pm,
int64_t  k2,
int  kpos[3],
pfft_complex *  value 
)
static

Definition at line 282 of file glass.c.

282  {
283 
284  double f = 1.0;
285  const double smth = 1.0 / k2;
286  /* the CIC deconvolution kernel is
287  *
288  * sinc_unnormed(k_x L / 2 pm->Nmesh) ** 2
289  *
290  * k_x = kpos * 2pi / L
291  *
292  * */
293  /*
294  * first decovolution is CIC in par->mesh
295  * second decovolution is correcting readout
296  * I don't understand the second yet!
297  * */
298  const double fac = pot_factor * smth * f * f;
299 
300  /*Compute the power spectrum*/
301  powerspectrum_add_mode(pm->ps, k2, kpos, value, f, pm->Nmesh);
302 
303  if(k2 == 0) {
304  /* Remove zero mode corresponding to the mean.*/
305  value[0][0] = 0.0;
306  value[0][1] = 0.0;
307  return;
308  }
309 
310  value[0][0] *= fac;
311  value[0][1] *= fac;
312 }
void powerspectrum_add_mode(Power *PowerSpectrum, const int64_t k2, const int kpos[3], pfft_complex *const value, const double invwindow, double Nmesh)
Definition: gravpm.c:327

References PetaPM::Nmesh, pot_factor, powerspectrum_add_mode(), and PetaPM::ps.

Here is the call graph for this function:

◆ readout_force_x()

static void readout_force_x ( PetaPM pm,
int  i,
double *  mesh,
double  weight 
)
static

Definition at line 349 of file glass.c.

349  {
350  curICP[i].Disp[0] += weight * mesh[0];
351 }

References curICP, and ic_part_data::Disp.

◆ readout_force_y()

static void readout_force_y ( PetaPM pm,
int  i,
double *  mesh,
double  weight 
)
static

Definition at line 352 of file glass.c.

352  {
353  curICP[i].Disp[1] += weight * mesh[0];
354 }

References curICP, and ic_part_data::Disp.

◆ readout_force_z()

static void readout_force_z ( PetaPM pm,
int  i,
double *  mesh,
double  weight 
)
static

Definition at line 355 of file glass.c.

355  {
356  curICP[i].Disp[2] += weight * mesh[0];
357 }

References curICP, and ic_part_data::Disp.

◆ setup_glass()

int setup_glass ( IDGenerator idgen,
PetaPM pm,
double  shift,
int  seed,
double  mass,
struct ic_part_data ICP,
const double  UnitLength_in_cm,
const char *  OutputDir 
)

Definition at line 41 of file glass.c.

42 {
43  gsl_rng * rng = gsl_rng_alloc(gsl_rng_ranlxd1);
44  int ThisTask;
45  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
46  gsl_rng_set(rng, seed + ThisTask);
47  memset(ICP, 0, idgen->NumPart*sizeof(struct ic_part_data));
48 
49  int i;
50  /* Note: this loop should nto be omp because
51  * of the call to gsl_rng_uniform*/
52  for(i = 0; i < idgen->NumPart; i ++) {
53  int k;
54  idgen_create_pos_from_index(idgen, i, &ICP[i].Pos[0]);
55  /* a spread of 3 will kill most of the grid anisotropy structure;
56  * and still being local */
57  for(k = 0; k < 3; k++) {
58  double rand = idgen->BoxSize / idgen->Ngrid * 3 * (gsl_rng_uniform(rng) - 0.5);
59  ICP[i].Pos[k] += shift + rand;
60  }
61  ICP[i].Mass = mass;
62  }
63 
64  gsl_rng_free(rng);
65 
66  char * fn = fastpm_strdup_printf("powerspectrum-glass-%08X", seed);
67  glass_evolve(pm, 14, fn, ICP, idgen->NumPart, UnitLength_in_cm, OutputDir);
68  myfree(fn);
69 
70  return idgen->NumPart;
71 }
void glass_evolve(PetaPM *pm, int nsteps, const char *pkoutname, struct ic_part_data *ICP, const int NumPart, const double UnitLength_in_cm, const char *OutputDir)
Definition: glass.c:73
#define myfree(x)
Definition: mymalloc.h:19
void idgen_create_pos_from_index(IDGenerator *idgen, int index, double pos[3])
Definition: zeldovich.c:79
char * fastpm_strdup_printf(const char *fmt,...)
Definition: string.c:41
int Ngrid
Definition: proto.h:12
double BoxSize
Definition: proto.h:13
int NumPart
Definition: proto.h:14
int ThisTask
Definition: test_exchange.c:23

References IDGenerator::BoxSize, fastpm_strdup_printf(), glass_evolve(), idgen_create_pos_from_index(), ic_part_data::Mass, myfree, IDGenerator::Ngrid, IDGenerator::NumPart, ic_part_data::Pos, ThisTask, and UnitLength_in_cm.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ curICP

struct ic_part_data* curICP
static

◆ functions

PetaPMFunctions functions[]
static
Initial value:
=
{
{NULL, NULL, NULL},
}
static void force_x_transfer(PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
Definition: glass.c:340
static void readout_force_z(PetaPM *pm, int i, double *mesh, double weight)
Definition: glass.c:355
static void readout_force_x(PetaPM *pm, int i, double *mesh, double weight)
Definition: glass.c:349
static void force_z_transfer(PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
Definition: glass.c:346
static void force_y_transfer(PetaPM *pm, int64_t k2, int kpos[3], pfft_complex *value)
Definition: glass.c:343
static void readout_force_y(PetaPM *pm, int i, double *mesh, double weight)
Definition: glass.c:352

Definition at line 25 of file glass.c.

Referenced by glass_force().

◆ global_functions

Definition at line 33 of file glass.c.

Referenced by glass_force(), gravpm_force(), petapm_force(), and petapm_force_r2c().

◆ pot_factor

double pot_factor
static

Definition at line 215 of file glass.c.

Referenced by _prepare(), and potential_transfer().