MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
lightcone.c
Go to the documentation of this file.
1 #include <mpi.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6 #include <gsl/gsl_math.h>
7 #include <gsl/gsl_integration.h>
8 /*For mkdir*/
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 
12 #include "utils.h"
13 
14 #include "timefac.h"
15 #include "partmanager.h"
16 #include "cosmology.h"
17 #include "physconst.h"
18 
19 #define NENTRY 4096
20 static double tab_loga[NENTRY];
21 static double dloga;
22 static double tab_Dc[NENTRY];
23 /*
24  * light cone on the fly:
25  *
26  * assuming the origin is at (0, 0, 0)
27  *
28  * */
29 
30 /*
31  * replicas to consider, function of redshift;
32  *
33  * */
34 static int Nreplica;
35 static int BoxBoost = 20;
36 static double Reps[8192][3];
37 static double HorizonDistance2;
38 static double HorizonDistance;
39 static double HorizonDistancePrev;
40 static double HorizonDistance2Prev;
41 static double HorizonDistanceRef;
42 static double zmin = 0.1;
43 static double zmax = 80.0;
44 static double ReferenceRedshift = 2.0; /* write all particles below this redshift; write a fraction above this. */
45 static double SampleFraction; /* current fraction of particle gets written */
46 static FILE * fd_lightcone;
47 
48 static double lightcone_get_horizon(double a);
49 static void lightcone_cross(int p, double ddrift);
50 static void lightcone_set_time(double a, const double BoxSize);
51 /*
52 M, L = self.M, self.L
53  logx = numpy.linspace(log10amin, 0, Np)
54  def kernel(log10a):
55  a = numpy.exp(log10a)
56  return 1 / self.Ea(a) * a ** -1 # dz = - 1 / a dlog10a
57  y = numpy.array( [romberg(kernel, log10a, 0, vec_func=True, divmax=10) for log10a in logx])
58 */
59 static double kernel(double loga, void * params) {
60  double a = exp(loga);
61  Cosmology * CP = (Cosmology *) params;
62  return 1 / hubble_function(CP, a) * CP->Hubble / a;
63 }
64 
65 static void lightcone_init_entry(Cosmology * CP, int i, const double UnitLength_in_cm) {
66  tab_loga[i] = - dloga * (NENTRY - i - 1);
67 
68  gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000);
69 
70  double result, error;
71 
72  gsl_function F;
73  F.function = &kernel;
74  F.params = CP;
75  gsl_integration_qags (&F, tab_loga[i], 0, 0, 1e-7, 1000,
76  w, &result, &error);
77 
78  /* result is in DH, hubble distance */
79  /* convert to cm / h */
80  result *= LIGHTCGS / HUBBLE;
81  /* convert to Kpc/h or internal units */
82  result /= UnitLength_in_cm;
83 
84  gsl_integration_workspace_free (w);
85  tab_Dc[i] = result;
86 // double a = exp(tab_loga[i]);
87 // double z = 1 / a - 1;
88 // printf("a = %g z = %g Dc = %g\n", a, z, result);
89 }
90 
91 void lightcone_init(Cosmology * CP, double timeBegin, const double UnitLength_in_cm, const char * OutputDir)
92 {
93  int i;
94  dloga = (0.0 - log(timeBegin)) / (NENTRY - 1);
95  for(i = 0; i < NENTRY; i ++) {
97  };
98  char buf[1024];
99  int chunk = 100;
100  int ThisTask;
101  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
102 
103  sprintf(buf, "%s/lightcone/", OutputDir);
104  mkdir(buf, 02755);
105  sprintf(buf, "%s/lightcone/%03d/", OutputDir, (int)(ThisTask / chunk));
106  mkdir(buf, 02755);
107  sprintf(buf, "%s/lightcone/%03d/lightcone-%05d.raw", OutputDir, (int)(ThisTask / chunk), ThisTask);
108 
109  fd_lightcone = fopen(buf, "a+");
110  if(fd_lightcone == NULL) {
111  endrun(1, "failed to open %s\n", buf);
112  }
114  printf("lightcone reference redshift = %g distance = %g\n",
116 }
117 
118 /* returns the horizon distance */
119 static double lightcone_get_horizon(double a) {
120  double loga = log(a);
121  int bin = (log(a) -tab_loga[0]) / dloga;
122  if (bin < 0) {
123  return tab_Dc[0];
124  }
125  if (bin >= NENTRY - 1) {
126  return tab_Dc[NENTRY - 1];
127  }
128  double u1 = loga - tab_loga[bin];
129  double u2 = tab_loga[bin + 1] - loga;
130  u1 /= (tab_loga[bin + 1] - tab_loga[bin]);
131  u2 /= (tab_loga[bin + 1] - tab_loga[bin]);
132  return tab_Dc[bin] * u2 + tab_Dc[bin + 1] * u1;
133 }
134 
135 /* fill in the table of box offsets for current time */
136 static void update_replicas(double a, double BoxSize) {
137  int Nmax = BoxBoost * BoxBoost * BoxBoost;
138  int i;
139  int rx, ry, rz;
140  rx = ry = rz = 0;
141  Nreplica = 0;
142 
143  for(i = 0; i < Nmax; i ++) {
144  double dx = BoxSize * rx;
145  double dy = BoxSize * ry;
146  double dz = BoxSize * rz;
147  double d1, d2;
148  d1 = dx * dx + dy * dy + dz * dz;
149  dx += BoxSize;
150  dy += BoxSize;
151  dz += BoxSize;
152  d2 = dx * dx + dy * dy + dz * dz;
153  if(d1 <= HorizonDistance2 && d2 >= HorizonDistance2) {
154  Reps[Nreplica][0] = rx * BoxSize;
155  Reps[Nreplica][1] = ry * BoxSize;
156  Reps[Nreplica][2] = rz * BoxSize;
157  Nreplica ++;
158  if(Nreplica > 1000) {
159  endrun(951234, "too many replica");
160  }
161  }
162  rz ++;
163  if(rz == BoxBoost) {
164  rz = 0;
165  ry ++;
166  }
167  if(ry == BoxBoost) {
168  ry = 0;
169  rx ++;
170  }
171  }
172 }
173 
174 /* Compute a list of particles which crossed
175  * the lightcone boundaries on this timestep and
176  * write them to the lightcone file*/
177 void lightcone_compute(double a, double BoxSize, Cosmology * CP, inttime_t ti_curr, inttime_t ti_next)
178 {
179  int i;
180  lightcone_set_time(a, BoxSize);
181  const double ddrift = get_exact_drift_factor(CP, ti_curr, ti_next);
182  #pragma omp parallel for
183  for(i = 0; i < PartManager->NumPart; i++)
184  {
185  lightcone_cross(i, ddrift);
186  }
187 }
188 
189 void lightcone_set_time(double a, const double BoxSize) {
190  double z = 1 / a - 1;
191  if(z > zmin && z < zmax) {
196  update_replicas(a, BoxSize);
197  fflush(fd_lightcone);
198  if (z < ReferenceRedshift) {
199  SampleFraction = 1.0;
200  } else {
201  /* write a smaller fraction of the points at high redshift
202  */
203  /* This is the angular resolution rule */
207  /* This is the luminosity resolution rule */
208 #if 0
210  SampleFraction *= (1 + ReferenceRedshift) / (1 + z);
212 
213 #endif
214  }
215  message(0,"RefRedeshit=%g, SampleFraction=%g HorizonDistance=%g\n", ReferenceRedshift, SampleFraction, HorizonDistance);
216  } else {
217  SampleFraction = 0;
218  }
219 }
220 
221 /* check crossing of the horizon, write the particle */
222 static void lightcone_cross(int p, double ddrift) {
223  if(SampleFraction <= 0.0) return;
224  int i;
225  int k;
226  /* DM only */
227  if(P[p].Type != 1) return;
228 
229  for(i = 0; i < Nreplica; i++) {
230  double r = get_random_number(P[p].ID + i);
231  if(r > SampleFraction) continue;
232 
233  double pnew[3];
234  double pold[3];
235  double p3[4];
236  double dnew = 0, dold = 0;
237  for(k = 0; k < 3; k ++) {
238  pold[k] = P[p].Pos[k] + Reps[i][k] - PartManager->CurrentParticleOffset[k];
239  pnew[k] = P[p].Pos[k] + P[i].Vel[k] * ddrift - PartManager->CurrentParticleOffset[k];
240  dnew += pnew[k] * pnew[k];
241  dold += pold[k] * pold[k];
242  }
243  if(
244  (dold <= HorizonDistance2Prev && dnew >= HorizonDistance2)
245  ) {
246  double u1, u2;
247  if(dold != dnew) {
248  double cnew, cold;
249  dnew = sqrt(dnew);
250  dold = sqrt(dold);
251  cnew = dnew - HorizonDistance;
252  cold = dold - HorizonDistancePrev;
253  u1 = -cold / (cnew - cold);
254  u2 = cnew / (cnew - cold);
255  } else {
256  /* really should write all particles along the line:
257  * this partilce is moving along the horizon! */
258  u1 = u2 = 0.5;
259  }
260 
261  /* write particle position */
262  for(k = 0; k < 3; k ++) {
263  p3[k] = pold[k] * u2 + pnew[k] * u1;
264  }
265  p3[3] = SampleFraction;
266  fwrite(p3, sizeof(double), 4, fd_lightcone);
267  }
268  }
269 }
double hubble_function(const Cosmology *CP, double a)
Definition: cosmology.c:58
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
static double SampleFraction
Definition: lightcone.c:45
static double HorizonDistance2Prev
Definition: lightcone.c:40
static double tab_loga[NENTRY]
Definition: lightcone.c:20
static int BoxBoost
Definition: lightcone.c:35
static double HorizonDistanceRef
Definition: lightcone.c:41
static double tab_Dc[NENTRY]
Definition: lightcone.c:22
static int Nreplica
Definition: lightcone.c:34
#define NENTRY
Definition: lightcone.c:19
static double kernel(double loga, void *params)
Definition: lightcone.c:59
static double HorizonDistance
Definition: lightcone.c:38
static FILE * fd_lightcone
Definition: lightcone.c:46
void lightcone_compute(double a, double BoxSize, Cosmology *CP, inttime_t ti_curr, inttime_t ti_next)
Definition: lightcone.c:177
static void lightcone_set_time(double a, const double BoxSize)
Definition: lightcone.c:189
static double HorizonDistance2
Definition: lightcone.c:37
static double dloga
Definition: lightcone.c:21
static double zmin
Definition: lightcone.c:42
static void lightcone_init_entry(Cosmology *CP, int i, const double UnitLength_in_cm)
Definition: lightcone.c:65
static double HorizonDistancePrev
Definition: lightcone.c:39
static void update_replicas(double a, double BoxSize)
Definition: lightcone.c:136
static double zmax
Definition: lightcone.c:43
static void lightcone_cross(int p, double ddrift)
Definition: lightcone.c:222
static double ReferenceRedshift
Definition: lightcone.c:44
void lightcone_init(Cosmology *CP, double timeBegin, const double UnitLength_in_cm, const char *OutputDir)
Definition: lightcone.c:91
static double Reps[8192][3]
Definition: lightcone.c:36
static double lightcone_get_horizon(double a)
Definition: lightcone.c:119
struct part_manager_type PartManager[1]
Definition: partmanager.c:11
#define P
Definition: partmanager.h:88
#define HUBBLE
Definition: physconst.h:25
#define LIGHTCGS
Definition: physconst.h:18
static Cosmology * CP
Definition: power.c:27
static double UnitLength_in_cm
Definition: power.c:26
double Hubble
Definition: cosmology.h:21
double CurrentParticleOffset[3]
Definition: partmanager.h:82
double get_random_number(uint64_t id)
Definition: system.c:60
int ThisTask
Definition: test_exchange.c:23
double get_exact_drift_factor(Cosmology *CP, inttime_t ti0, inttime_t ti1)
Definition: timefac.c:64
int32_t inttime_t
Definition: types.h:8