MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
pmesh.h
Go to the documentation of this file.
1 #ifndef PMESH_H
2 #define PMESH_H
3 #include <gsl/gsl_rng.h>
4 #include <libgadget/petapm.h>
5 #include <libgadget/utils.h>
6 
7 /*
8  * The following functions are from fastpm/libfastpm/initialcondition.c.
9  * Agrees with nbodykit's pmesh/whitenoise.c, which agrees with n-genic.
10  * */
11 typedef struct {
12  struct {
13  ptrdiff_t start[3];
14  ptrdiff_t size[3];
15  ptrdiff_t strides[3];
16  ptrdiff_t total;
17  } ORegion;
18  int Nmesh[3];
19 } PMDesc;
20 
21 static inline void
22 SETSEED(PMDesc * pm, unsigned int * table[2][2], int i, int j, gsl_rng * rng)
23 {
24  unsigned int seed = 0x7fffffff * gsl_rng_uniform(rng);
25 
26  int ii[2] = {i, (pm->Nmesh[0] - i) % pm->Nmesh[0]};
27  int jj[2] = {j, (pm->Nmesh[1] - j) % pm->Nmesh[1]};
28  int d1, d2;
29  for(d1 = 0; d1 < 2; d1++) {
30  ii[d1] -= pm->ORegion.start[0];
31  jj[d1] -= pm->ORegion.start[1];
32  }
33  for(d1 = 0; d1 < 2; d1++)
34  for(d2 = 0; d2 < 2; d2++) {
35  if( ii[d1] >= 0 &&
36  ii[d1] < pm->ORegion.size[0] &&
37  jj[d2] >= 0 &&
38  jj[d2] < pm->ORegion.size[1]
39  ) {
40  table[d1][d2][ii[d1] * pm->ORegion.size[1] + jj[d2]] = seed;
41  }
42  }
43 }
44 static inline unsigned int
45 GETSEED(PMDesc * pm, unsigned int * table[2][2], int i, int j, int d1, int d2)
46 {
47  i -= pm->ORegion.start[0];
48  j -= pm->ORegion.start[1];
49  if(i < 0) abort();
50  if(j < 0) abort();
51  if(i >= pm->ORegion.size[0]) abort();
52  if(j >= pm->ORegion.size[1]) abort();
53  return table[d1][d2][i * pm->ORegion.size[1] + j];
54 }
55 
56 static void
57 SAMPLE(gsl_rng * rng, double * ampl, double * phase)
58 {
59  *phase = gsl_rng_uniform(rng) * 2 * M_PI;
60  *ampl = 0;
61  do *ampl = gsl_rng_uniform(rng); while(*ampl == 0);
62 }
63 
64 static void
65 pmic_fill_gaussian_gadget(PMDesc * pm, double * delta_k, int seed, int setUnitaryAmplitude, int setInvertPhase)
66 {
67  /* Fill delta_k with gadget scheme */
68  int d;
69  int i, j, k;
70 
71  gsl_rng * rng = gsl_rng_alloc(gsl_rng_ranlxd1);
72  gsl_rng_set(rng, seed);
73 
74  unsigned int * seedtable[2][2];
75  for(i = 0; i < 2; i ++)
76  for(j = 0; j < 2; j ++) {
77  seedtable[i][j] = (unsigned int *) mymalloc("seedtable", pm->ORegion.size[0] * pm->ORegion.size[1] * sizeof(int));
78  memset(seedtable[i][j], 0, pm->ORegion.size[0] * pm->ORegion.size[1] * sizeof(int));
79  }
80 
81  for(i = 0; i < pm->Nmesh[0] / 2; i++) {
82  for(j = 0; j < i; j++) SETSEED(pm, seedtable, i, j, rng);
83  for(j = 0; j < i + 1; j++) SETSEED(pm, seedtable, j, i, rng);
84  for(j = 0; j < i; j++) SETSEED(pm, seedtable, pm->Nmesh[0] - 1 - i, j, rng);
85  for(j = 0; j < i + 1; j++) SETSEED(pm, seedtable, pm->Nmesh[1] - 1 - j, i, rng);
86  for(j = 0; j < i; j++) SETSEED(pm, seedtable, i, pm->Nmesh[1] - 1 - j, rng);
87  for(j = 0; j < i + 1; j++) SETSEED(pm, seedtable, j, pm->Nmesh[0] - 1 - i, rng);
88  for(j = 0; j < i; j++) SETSEED(pm, seedtable, pm->Nmesh[0] - 1 - i, pm->Nmesh[1] - 1 - j, rng);
89  for(j = 0; j < i + 1; j++) SETSEED(pm, seedtable, pm->Nmesh[1] - 1 - j, pm->Nmesh[0] - 1 - i, rng);
90  }
91  gsl_rng_free(rng);
92 
93  ptrdiff_t irel[3];
94  for(i = pm->ORegion.start[0];
95  i < pm->ORegion.start[0] + pm->ORegion.size[0];
96  i ++) {
97 
98  gsl_rng * lower_rng = gsl_rng_alloc(gsl_rng_ranlxd1);
99  gsl_rng * this_rng = gsl_rng_alloc(gsl_rng_ranlxd1);
100 
101  int ci = pm->Nmesh[0] - i;
102  if(ci >= pm->Nmesh[0]) ci -= pm->Nmesh[0];
103 
104  for(j = pm->ORegion.start[1];
105  j < pm->ORegion.start[1] + pm->ORegion.size[1];
106  j ++) {
107  /* always pull the gaussian from the lower quadrant plane for k = 0
108  * plane*/
109  /* always pull the whitenoise from the lower quadrant plane for k = 0
110  * plane and k == All.Nmesh / 2 plane*/
111  int d1 = 0, d2 = 0;
112  int cj = pm->Nmesh[1] - j;
113  if(cj >= pm->Nmesh[1]) cj -= pm->Nmesh[1];
114 
115  /* d1, d2 points to the conjugate quandrant */
116  if( (ci == i && cj < j)
117  || (ci < i && cj != j)
118  || (ci < i && cj == j)) {
119  d1 = 1;
120  d2 = 1;
121  }
122 
123  unsigned int seed_conj, seed_this;
124  /* the lower quadrant generator */
125  seed_conj = GETSEED(pm, seedtable, i, j, d1, d2);
126  gsl_rng_set(lower_rng, seed_conj);
127 
128  seed_this = GETSEED(pm, seedtable, i, j, 0, 0);
129  gsl_rng_set(this_rng, seed_this);
130 
131  for(k = 0; k <= pm->Nmesh[2] / 2; k ++) {
132  int use_conj = (d1 != 0 || d2 != 0) && (k == 0 || k == pm->Nmesh[2] / 2);
133 
134  double ampl, phase;
135  if(use_conj) {
136  /* on k = 0 and All.Nmesh/2 plane, we use the lower quadrant generator,
137  * then hermit transform the result if it is nessessary */
138  SAMPLE(this_rng, &ampl, &phase);
139  SAMPLE(lower_rng, &ampl, &phase);
140  } else {
141  SAMPLE(lower_rng, &ampl, &phase);
142  SAMPLE(this_rng, &ampl, &phase);
143  }
144 
145  ptrdiff_t iabs[3] = {i, j, k};
146  ptrdiff_t ip = 0;
147  for(d = 0; d < 3; d ++) {
148  irel[d] = iabs[d] - pm->ORegion.start[d];
149  ip += pm->ORegion.strides[d] * irel[d];
150  }
151 
152  if(irel[2] < 0) continue;
153  if(irel[2] >= pm->ORegion.size[2]) continue;
154 
155  /* we want two numbers that are of std ~ 1/sqrt(2) */
156  ampl = sqrt(- log(ampl));
157 
158  if (setUnitaryAmplitude) ampl = 1.0; /* cos and sin gives 1/sqrt(2)*/
159 
160 
161  if (setInvertPhase){
162  phase += M_PI; /*invert phase*/
163  }
164 
165  (delta_k + 2 * ip)[0] = ampl * cos(phase);
166  (delta_k + 2 * ip)[1] = ampl * sin(phase);
167 
168  if(use_conj) {
169  (delta_k + 2 * ip)[1] *= -1;
170  }
171 
172  if((pm->Nmesh[0] - iabs[0]) % pm->Nmesh[0] == iabs[0] &&
173  (pm->Nmesh[1] - iabs[1]) % pm->Nmesh[1] == iabs[1] &&
174  (pm->Nmesh[2] - iabs[2]) % pm->Nmesh[2] == iabs[2]) {
175  /* The mode is self conjuguate, thus imaginary mode must be zero */
176  (delta_k + 2 * ip)[1] = 0;
177  (delta_k + 2 * ip)[0] = ampl * cos(phase);
178  }
179 
180  if(iabs[0] == 0 && iabs[1] == 0 && iabs[2] == 0) {
181  /* the mean is zero */
182  (delta_k + 2 * ip)[0] = 0;
183  (delta_k + 2 * ip)[1] = 0;
184  }
185  }
186  }
187  gsl_rng_free(lower_rng);
188  gsl_rng_free(this_rng);
189  }
190  for(i = 1; i >= 0; i --)
191  for(j = 1; j >= 0; j --) {
192  myfree(seedtable[i][j]);
193  }
194 /*
195  char * fn[1000];
196  sprintf(fn, "canvas.dump.f4.%d", pm->ThisTask);
197  fwrite(pm->canvas, sizeof(pm->canvas[0]), pm->ORegion.total * 2, fopen(fn, "w"));
198 */
199 }
200 #endif
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define myfree(x)
Definition: mymalloc.h:19
static void SETSEED(PMDesc *pm, unsigned int *table[2][2], int i, int j, gsl_rng *rng)
Definition: pmesh.h:22
static void SAMPLE(gsl_rng *rng, double *ampl, double *phase)
Definition: pmesh.h:57
static void pmic_fill_gaussian_gadget(PMDesc *pm, double *delta_k, int seed, int setUnitaryAmplitude, int setInvertPhase)
Definition: pmesh.h:65
static unsigned int GETSEED(PMDesc *pm, unsigned int *table[2][2], int i, int j, int d1, int d2)
Definition: pmesh.h:45
Definition: pmesh.h:11
struct PMDesc::@16 ORegion
ptrdiff_t start[3]
Definition: pmesh.h:13
ptrdiff_t size[3]
Definition: pmesh.h:14
int Nmesh[3]
Definition: pmesh.h:18
ptrdiff_t total
Definition: pmesh.h:16
ptrdiff_t strides[3]
Definition: pmesh.h:15
Definition: power.c:35