MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
cooling_uvfluc.c
Go to the documentation of this file.
1 /**************
2  * This file (C) Yu Feng 2017 implements support for a fluctuating UVB, using an external table.
3  * This table is generated following the model explained in Battaglia & Trac 2010.
4  ************** */
5 
6 #include <mpi.h>
7 #include <string.h>
8 #include <math.h>
9 #include "cooling_rates.h"
10 #include "physconst.h"
11 #include "bigfile.h"
12 #include "bigfile-mpi.h"
13 #include "utils/mymalloc.h"
14 #include "utils/interp.h"
15 #include "utils/endrun.h"
16 
17 static struct {
18  int enabled;
20  double * Table;
21  ptrdiff_t Nside;
22 } UVF;
23 
24 /* Read a big array from filename/dataset into an array, allocating memory in buffer.
25  * which is returned. Nread argument is set equal to number of elements read.*/
26 static double *
27 read_big_array(const char * filename, const char * dataset, int * Nread)
28 {
29  int N;
30  double * buffer=NULL;
31  int ThisTask;
32  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
33 
34  if(ThisTask == 0) {
35  BigFile bf[1];
36  BigBlockPtr ptr;
37  BigBlock bb[1];
38  BigArray array[1];
39  size_t dims[2];
40  big_file_open(bf, filename);
41  if(0 != big_file_open_block(bf, bb, dataset)) {
42  endrun(1, "Cannot open %s %s: %s\n", filename, dataset, big_file_get_error_message());
43  }
44 
45  N = bb->size;
46 
47  if(dtype_itemsize(bb->dtype) != sizeof(double))
48  endrun(1, "UVflucatuation file %s should contain double-precision data, contains %s\n", filename, bb->dtype);
49 
50  buffer = (double *) mymalloc("cooling_data", N * dtype_itemsize(bb->dtype) * bb->nmemb);
51  dims[0] = N;
52  dims[1] = bb->nmemb;
53 
54  big_array_init(array, buffer, bb->dtype, 2, dims, NULL);
55  if(0 != big_block_seek(bb, &ptr, 0))
56  endrun(1, "Failed to seek block %s %s: %s\n", filename, dataset, big_file_get_error_message());
57 
58  if(0 != big_block_read(bb, &ptr, array))
59  endrun(1, "Failed to read %s %s: %s", filename, dataset, big_file_get_error_message());
60  /* steal the buffer */
61  big_block_close(bb);
62  big_file_close(bf);
63  }
64 
65  MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
66  if(ThisTask != 0)
67  buffer = (double *) mymalloc("cooling_data",N * sizeof(double));
68 
69  MPI_Bcast(buffer, N, MPI_DOUBLE, 0, MPI_COMM_WORLD);
70 
71  *Nread = N;
72  return buffer;
73 }
74 
75 /* The UV fluctation file is a bigfile with these tables:
76  * ReionizedFraction: values of the reionized fraction as function of
77  * redshift.
78  * Redshift_Bins: uniform redshifts of the reionized fraction values
79  *
80  * XYZ_Bins: the uniform XYZ points where Z_reion is tabulated. (length of Nside)
81  *
82  * Zreion_Table: a Nside (X) x Nside (Y)x Nside (z) C ordering double array,
83  * the reionization redshift as function of space, on a grid give by
84  * XYZ_Bins.
85  *
86  * Notice that this table is broadcast to all MPI ranks, thus it can't be
87  * too big. (400x400x400 is around 400 MBytes)
88  *
89  * */
90 void
91 init_uvf_table(const char * UVFluctuationFile, const int UVFlucLen, const double BoxSize, const double UnitLength_in_cm)
92 {
93  if(strnlen(UVFluctuationFile, UVFlucLen) == 0) {
94  UVF.enabled = 0;
95  return;
96  }
97 
98  /* Open and validate the UV fluctuation file*/
99  BigFile bf;
100  BigBlock bh;
101  if(0 != big_file_mpi_open(&bf, UVFluctuationFile, MPI_COMM_WORLD)) {
102  endrun(0, "Failed to open snapshot at %s:%s\n", UVFluctuationFile,
103  big_file_get_error_message());
104  }
105 
106  if(0 != big_file_mpi_open_block(&bf, &bh, "Zreion_Table", MPI_COMM_WORLD)) {
107  endrun(0, "Failed to create block at %s:%s\n", "Header",
108  big_file_get_error_message());
109  }
110  double TableBoxSize;
111  double ReionRedshift;
112  if ((0 != big_block_get_attr(&bh, "Nmesh", &UVF.Nside, "u8", 1)) ||
113  (0 != big_block_get_attr(&bh, "BoxSize", &TableBoxSize, "f8", 1)) ||
114  (0 != big_block_get_attr(&bh, "Redshift", &ReionRedshift, "f8", 1)) ||
115  (0 != big_block_mpi_close(&bh, MPI_COMM_WORLD))) {
116  endrun(0, "Failed to close block: %s\n",
117  big_file_get_error_message());
118  }
119  big_file_mpi_close(&bf, MPI_COMM_WORLD);
120  double BoxMpc = BoxSize * UnitLength_in_cm / CM_PER_MPC;
121  if(fabs(TableBoxSize - BoxMpc) > BoxMpc * 1e-5)
122  endrun(0, "Wrong UV fluctuation file! %s is for box size %g Mpc/h, but current box is %g Mpc/h\n", UVFluctuationFile, TableBoxSize, BoxMpc);
123 
124  message(0, "Using NON-UNIFORM UV BG fluctuations from %s. Median reionization redshift is %g\n", UVFluctuationFile, ReionRedshift);
125  UVF.enabled = 1;
126 
127  int size;
128  UVF.Table = read_big_array(UVFluctuationFile, "Zreion_Table", &size);
129 
130  if(UVF.Nside * UVF.Nside * UVF.Nside != size)
131  endrun(0, "Corrupt UV Fluctuation table: Nside = %ld, but table is %ld != %ld^3\n", UVF.Nside, size, UVF.Nside);
132 
133  int64_t dims[] = {UVF.Nside, UVF.Nside, UVF.Nside};
134  interp_init(&UVF.interp, 3, dims);
135  interp_init_dim(&UVF.interp, 0, 0, BoxSize);
136  interp_init_dim(&UVF.interp, 1, 0, BoxSize);
137  interp_init_dim(&UVF.interp, 2, 0, BoxSize);
138 
139  if(UVF.Table[0] < 0.01 || UVF.Table[0] > 100.0) {
140  endrun(0, "UV Fluctuation out of range: %g\n", UVF.Table[0]);
141  }
142 }
143 
144 /*
145  * returns the spatial dependent UVBG if UV fluctuation is enabled.
146  * Otherwise returns the global UVBG passed in.
147  *
148  * */
149 struct UVBG get_local_UVBG(double redshift, const struct UVBG * const GlobalUVBG, const double * const Pos, const double * const PosOffset)
150 {
151  if(!UVF.enabled) {
152  /* directly use the TREECOOL table if UVF is disabled */
153  return *GlobalUVBG;
154  }
155 
156  struct UVBG uvbg = {0};
157 
158  uvbg.self_shield_dens = GlobalUVBG->self_shield_dens;
159 
160  double corrpos[3];
161  int i;
162  for(i = 0; i < 3; i++)
163  corrpos[i] = Pos[i] - PosOffset[i];
164  double zreion = interp_eval_periodic(&UVF.interp, corrpos, UVF.Table);
165  if(zreion < redshift) {
166  uvbg.zreion = zreion;
167  return uvbg;
168  }
169  memcpy(&uvbg, GlobalUVBG, sizeof(struct UVBG));
170  uvbg.zreion = zreion;
171  return uvbg;
172 }
173 
174 
175 /*Here comes the Metal Cooling code*/
176 struct {
179  double * Redshift_bins;
180 
183 
186 
187  double * Lmet_table; /* metal cooling @ one solar metalicity*/
188 
189  Interp interp;
191 
192 void
193 InitMetalCooling(const char * MetalCoolFile)
194 {
195  /* now initialize the metal cooling table from cloudy; we got this file
196  * from vogelsberger's Arepo simulations; it is supposed to be
197  * cloudy + UVB - H and He; look so.
198  * the table contains only 1 Z_sun values. Need to be scaled to the
199  * metallicity.
200  *
201  * */
202  /* let's see if the Metal Cool File is magic NoMetal */
203  if(strlen(MetalCoolFile) == 0) {
204  MetalCool.CoolingNoMetal = 1;
205  return;
206  } else {
207  MetalCool.CoolingNoMetal = 0;
208  }
209 
210  int size;
211  //This is never used if MetalCoolFile == ""
212  double * tabbedmet = read_big_array(MetalCoolFile, "MetallicityInSolar_bins", &size);
213 
214  if(size != 1 || tabbedmet[0] != 0.0) {
215  endrun(123, "MetalCool file %s is wrongly tabulated\n", MetalCoolFile);
216  }
217  myfree(tabbedmet);
218 
219  MetalCool.Redshift_bins = read_big_array(MetalCoolFile, "Redshift_bins", &MetalCool.NRedshift_bins);
220  MetalCool.HydrogenNumberDensity_bins = read_big_array(MetalCoolFile, "HydrogenNumberDensity_bins", &MetalCool.NHydrogenNumberDensity_bins);
221  MetalCool.Temperature_bins = read_big_array(MetalCoolFile, "Temperature_bins", &MetalCool.NTemperature_bins);
222  MetalCool.Lmet_table = read_big_array(MetalCoolFile, "NetCoolingRate", &size);
223 
224  int64_t dims[] = {MetalCool.NRedshift_bins, MetalCool.NHydrogenNumberDensity_bins, MetalCool.NTemperature_bins};
225 
226  interp_init(&MetalCool.interp, 3, dims);
227  interp_init_dim(&MetalCool.interp, 0, MetalCool.Redshift_bins[0], MetalCool.Redshift_bins[MetalCool.NRedshift_bins - 1]);
228  interp_init_dim(&MetalCool.interp, 1, MetalCool.HydrogenNumberDensity_bins[0],
229  MetalCool.HydrogenNumberDensity_bins[MetalCool.NHydrogenNumberDensity_bins - 1]);
230  interp_init_dim(&MetalCool.interp, 2, MetalCool.Temperature_bins[0],
231  MetalCool.Temperature_bins[MetalCool.NTemperature_bins - 1]);
232 }
233 
234 double
235 TableMetalCoolingRate(double redshift, double temp, double nHcgs)
236 {
237  if(MetalCool.CoolingNoMetal)
238  return 0;
239 
240  double lognH = log10(nHcgs);
241  double logT = log10(temp);
242 
243  double x[] = {redshift, lognH, logT};
244  int status[3];
245  double rate = interp_eval(&MetalCool.interp, x, MetalCool.Lmet_table, status);
246  /* XXX: in case of very hot / very dense we just use whatever the table says at
247  * the limit. should be OK. */
248  return rate;
249 }
int enabled
double * Lmet_table
int NHydrogenNumberDensity_bins
int CoolingNoMetal
static struct @0 UVF
Interp interp
int NRedshift_bins
void init_uvf_table(const char *UVFluctuationFile, const int UVFlucLen, const double BoxSize, const double UnitLength_in_cm)
double * HydrogenNumberDensity_bins
void InitMetalCooling(const char *MetalCoolFile)
struct UVBG get_local_UVBG(double redshift, const struct UVBG *const GlobalUVBG, const double *const Pos, const double *const PosOffset)
double TableMetalCoolingRate(double redshift, double temp, double nHcgs)
double * Table
int NTemperature_bins
double * Temperature_bins
static double * read_big_array(const char *filename, const char *dataset, int *Nread)
double * Redshift_bins
ptrdiff_t Nside
struct @1 MetalCool
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
double interp_eval(Interp *obj, double *x, double *ydata, int *status)
Definition: interp.c:72
void interp_init(Interp *obj, int Ndim, int64_t *dims)
Definition: interp.c:9
void interp_init_dim(Interp *obj, int d, double Min, double Max)
Definition: interp.c:50
double interp_eval_periodic(Interp *obj, double *x, double *ydata)
Definition: interp.c:134
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define myfree(x)
Definition: mymalloc.h:19
#define CM_PER_MPC
Definition: physconst.h:20
static double UnitLength_in_cm
Definition: power.c:26
Definition: interp.h:6
Definition: cooling.h:8
double self_shield_dens
Definition: cooling.h:15
double zreion
Definition: cooling.h:16
int ThisTask
Definition: test_exchange.c:23