MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
test_cooling_rates.c
Go to the documentation of this file.
1 /*Tests for the cooling rates module, ported from python.*/
2 
3 #include <stdarg.h>
4 #include <stddef.h>
5 #include <setjmp.h>
6 #include <cmocka.h>
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <libgadget/physconst.h>
13 #include <libgadget/config.h>
14 #include "stub.h"
15 
16 //Stub
17 int
19 {
20  return 0;
21 }
22 
23 double recomb_alphaHp(double temp);
24 
25 #define NEXACT 20
26 /*For hydrogen recombination we have an exact answer from Ferland et al 1992 (http://adsabs.harvard.edu/abs/1992ApJ...387...95F).
27 This function returns as an array these rates, for testing purposes.*/
28 //case B recombination rates for hydrogen from Ferland 92, final column of Table 1. For n >= 2.
29 static const double f92g2[NEXACT] = {5.758e-11, 2.909e-11, 1.440e-11, 6.971e-12,3.282e-12, 1.489e-12, 6.43e-13, 2.588e-13, 9.456e-14, 3.069e-14, 8.793e-15, 2.245e-15, 5.190e-16, 1.107e-16, 2.221e-17, 4.267e-18, 7.960e-19, 1.457e-19,2.636e-20, 4.737e-21};
30 //case B recombination rates for hydrogen from Ferland 92, second column of Table 1. For n == 1.
31 static const double f92n1[NEXACT] = {9.258e-12, 5.206e-12, 2.927e-12, 1.646e-12, 9.246e-13, 5.184e-13, 2.890e-13, 1.582e-13, 8.255e-14, 3.882e-14, 1.545e-14, 5.058e-15, 1.383e-15, 3.276e-16, 7.006e-17, 1.398e-17, 2.665e-18, 4.940e-19, 9.001e-20, 1.623e-20};
32 static const double tt[NEXACT] = {3.16227766e+00, 1.0e+01, 3.16227766e+01, 1.0e+02, 3.16227766e+02, 1.00e+03, 3.16227766e+03, 1.e+04, 3.16227766e+04, 1.e+05, 3.16227766e+05, 1.e+06, 3.16227766e+06, 1.0e+07, 3.16227766e+07, 1.0e+08, 3.16227766e+08, 1.0e+09, 3.16227766e+09, 1.0e+10};
33 
34 static struct cooling_params get_test_coolpar(void)
35 {
36  static struct cooling_params coolpar;
37  coolpar.CMBTemperature = 2.7255;
38  coolpar.PhotoIonizeFactor = 1;
39  coolpar.SelfShieldingOn = 1;
40  coolpar.fBar = 0.17;
41  coolpar.PhotoIonizationOn = 1;
42  coolpar.recomb = Verner96;
43  coolpar.cooling = Sherwood;
44  coolpar.UVRedshiftThreshold = -1;
45  coolpar.MinGasTemp = 100;
46  coolpar.HeliumHeatOn = 0;
47  coolpar.HydrogenHeatAmp = 0;
48  return coolpar;
49 }
50 
51 /*Test the recombination rates*/
52 static void test_recomb_rates(void ** state)
53 {
54  struct cooling_params coolpar = get_test_coolpar();
55  int i;
56  const char * TreeCool = GADGET_TESTDATA_ROOT "/examples/TREECOOL_ep_2018p";
57  const char * MetalCool = "";
58 
59  Cosmology CP = {0};
60  CP.OmegaCDM = 0.3;
61  CP.OmegaBaryon = coolpar.fBar * CP.OmegaCDM;
62  CP.HubbleParam = 0.7;
63 
64  set_coolpar(coolpar);
65  init_cooling_rates(TreeCool, MetalCool, &CP);
66  for(i=0; i< NEXACT; i++) {
67  assert_true(fabs(recomb_alphaHp(tt[i])/(f92g2[i]+f92n1[i])-1.) < 1e-2);
68  }
69 
70  coolpar.recomb = Cen92;
71  set_coolpar(coolpar);
72  init_cooling_rates(TreeCool, MetalCool, &CP);
73  /*Cen rates are not very accurate.*/
74  for(i=4; i< 12; i++) {
75  assert_true(fabs(recomb_alphaHp(tt[i])/(f92g2[i]+f92n1[i])-1.) < 0.5);
76  }
77 }
78 
79 /*Test that the UVBG loading code works*/
80 static void test_uvbg_loader(void ** state)
81 {
82  struct cooling_params coolpar = get_test_coolpar();
83  coolpar.SelfShieldingOn = 1;
84  const char * TreeCool = GADGET_TESTDATA_ROOT "/examples/TREECOOL_ep_2018p";
85  const char * MetalCool = "";
86  set_coolpar(coolpar);
87  Cosmology CP = {0};
88  CP.OmegaCDM = 0.3;
89  CP.OmegaBaryon = coolpar.fBar * CP.OmegaCDM;
90  CP.HubbleParam = 0.7;
91  init_cooling_rates(TreeCool, MetalCool, &CP);
92  /*Test sensible rates at high redshift*/
93  struct UVBG uvbg = get_global_UVBG(16);
94  assert_true(uvbg.epsH0 == 0);
95  assert_true(uvbg.self_shield_dens > 1e8);
96  assert_true(uvbg.gJH0 == 0);
97  /*Test at zero redshift*/
98  uvbg = get_global_UVBG(0);
99  assert_true(fabs(uvbg.epsH0/3.65296e-25 -1) < 1e-5);
100  assert_true(fabs(uvbg.epsHe0/3.98942e-25 -1) < 1e-5);
101  assert_true(fabs(uvbg.epsHep/3.33253e-26 -1) < 1e-5);
102  assert_true(fabs(uvbg.gJH0/6.06e-14 -1) < 1e-5);
103  assert_true(fabs(uvbg.gJHe0/3.03e-14 -1) < 1e-5);
104  assert_true(fabs(uvbg.gJHep/1.1e-15 -1) < 1e-5);
105  assert_true(fabs(uvbg.self_shield_dens/0.0010114161149989826 - 1) < 1e-5);
106  /*Test at intermediate redshift*/
107  uvbg = get_global_UVBG(3.);
108  //message(0, "uvbg %g %g %g %g %g %g %g\n", uvbg.gJH0, uvbg.gJHe0, uvbg.gJHep, uvbg.epsH0, uvbg.epsHe0, uvbg.epsHep, uvbg.self_shield_dens);
109  assert_true(fabs(uvbg.epsH0/5.96570906168362e-24 -1) < 1e-5);
110  assert_true(fabs(uvbg.epsHe0/4.466976578202419e-24 -1) < 1e-5);
111  assert_true(fabs(uvbg.epsHep/2.758535690259892e-26 -1) < 1e-5);
112  assert_true(fabs(uvbg.gJH0/1.0549960730284017e-12 -1) < 1e-5);
113  assert_true(fabs(uvbg.gJHe0/4.759025257653999e-13 -1) < 1e-5);
114  assert_true(fabs(uvbg.gJHep/2.270599708640625e-16 -1) < 1e-5);
115  assert_true(fabs(uvbg.self_shield_dens/0.007691709693529007 - 1) < 1e-5);
116 }
117 
118 /* Simple tests for the rate network */
119 static void test_rate_network(void ** state)
120 {
121  struct cooling_params coolpar = get_test_coolpar();
122  const char * TreeCool = GADGET_TESTDATA_ROOT "/examples/TREECOOL_ep_2018p";
123  const char * MetalCool = "";
124 
125  set_coolpar(coolpar);
126  Cosmology CP = {0};
127  CP.OmegaCDM = 0.3;
128  CP.OmegaBaryon = coolpar.fBar * CP.OmegaCDM;
129  CP.HubbleParam = 0.7;
130 
131  init_cooling_rates(TreeCool, MetalCool, &CP);
132 
133  struct UVBG uvbg = get_global_UVBG(2);
134 
135 
136  //Complete ionisation at low density
137  double logt;
138  assert_true( fabs(get_equilib_ne(1e-6, 200.*1e10, 0.24, &logt, &uvbg, 1) / (1e-6*0.76) - (1 + 2* 0.24/(1-0.24)/4)) < 3e-5);
139  assert_true( fabs(get_equilib_ne(1e-6, 200.*1e10, 0.12, &logt, &uvbg, 1) / (1e-6*0.88) - (1 + 2* 0.12/(1-0.12)/4)) < 3e-5);
140  assert_true( fabs(get_equilib_ne(1e-5, 200.*1e10, 0.24, &logt, &uvbg, 1) / (1e-5*0.76) - (1 + 2* 0.24/(1-0.24)/4)) < 3e-4);
141  assert_true( fabs(get_equilib_ne(1e-4, 200.*1e10, 0.24, &logt, &uvbg, 1) / (1e-4*0.76) - (1 + 2* 0.24/(1-0.24)/4)) < 2e-3);
142 
143  double ne = 1.;
144  double temp = get_temp(1e-4, 200.*1e10,0.24, &uvbg, &ne);
145  assert_true(9500 < temp);
146  assert_true(temp < 9510);
147  //Roughly prop to internal energy when ionised
148  assert_true(fabs(get_temp(1e-4, 400.*1e10,0.24, &uvbg, &ne) / get_temp(1e-4, 200.*1e10,0.24, &uvbg, &ne) - 2.) < 1e-3);
149 
150  assert_true(fabs(get_temp(1, 200.*1e10,0.24, &uvbg, &ne) - 14700) < 200);
151 
152  //Neutral fraction prop to density.
153  double dens[3] = {1e-4, 1e-5, 1e-6};
154  int i;
155  for(i = 0; i < 3; i++) {
156  assert_true(fabs(get_neutral_fraction_phys_cgs(dens[i], 200.*1e10,0.24, &uvbg, &ne) / dens[i] - 0.3113) < 1e-3);
157  }
158  //Neutral (self-shielded) at high density:
159  assert_true(get_neutral_fraction_phys_cgs(1, 100.,0.24, &uvbg, &ne) > 0.95);
160  assert_true(0.75 > get_neutral_fraction_phys_cgs(0.1, 100.*1e10,0.24, &uvbg, &ne));
161  assert_true(get_neutral_fraction_phys_cgs(0.1, 100.*1e10,0.24, &uvbg, &ne) > 0.735);
162 
163  //Check self-shielding is working.
164  coolpar.SelfShieldingOn = 0;
165  set_coolpar(coolpar);
166  init_cooling_rates(TreeCool, MetalCool, &CP);
167 
168  assert_true( get_neutral_fraction_phys_cgs(1, 100.*1e10,0.24, &uvbg, &ne) < 0.25);
169  assert_true( get_neutral_fraction_phys_cgs(0.1, 100.*1e10,0.24, &uvbg, &ne) <0.05);
170 }
171 
172 /* This test checks that the heating and cooling rate is as expected.
173  * In particular the physical density threshold is checked. */
174 static void test_heatingcooling_rate(void ** state)
175 {
176  struct cooling_params coolpar = get_test_coolpar();
177  coolpar.recomb = Cen92;
178  coolpar.cooling = KWH92;
179  coolpar.SelfShieldingOn = 0;
180 
181  const char * TreeCool = GADGET_TESTDATA_ROOT "/examples/TREECOOL_ep_2018p";
182  const char * MetalCool = "";
183 
184  /*unit system*/
185  double HubbleParam = 0.697;
186  double UnitDensity_in_cgs = 6.76991e-22;
187  double UnitTime_in_s = 3.08568e+16;
188  double UnitMass_in_g = 1.989e+43;
189  double UnitLength_in_cm = 3.08568e+21;
190  double UnitEnergy_in_cgs = UnitMass_in_g * pow(UnitLength_in_cm, 2) / pow(UnitTime_in_s, 2);
191  Cosmology CP = {0};
192  CP.OmegaCDM = 0.3;
193  CP.OmegaBaryon = coolpar.fBar * CP.OmegaCDM;
194  CP.HubbleParam = HubbleParam;
195 
196  set_coolpar(coolpar);
197  init_cooling_rates(TreeCool, MetalCool, &CP);
198 
199  struct cooling_units coolunits;
200  coolunits.CoolingOn = 1;
201  coolunits.density_in_phys_cgs = UnitDensity_in_cgs * HubbleParam * HubbleParam;
202  coolunits.uu_in_cgs = UnitEnergy_in_cgs / UnitMass_in_g;
203  coolunits.tt_in_s = UnitTime_in_s / HubbleParam;
204 
205  /*Default values from sfr_eff.c. Some dependence on HubbleParam, so don't change it.*/
206  double egyhot = 2104.92;
207  egyhot *= coolunits.uu_in_cgs;
208 
209  /* convert to physical cgs units */
210  double dens = 0.027755;
212  double ne = 1.0;
213 
214  struct UVBG uvbg = {0};
215  /* XXX: We set the threshold without metal cooling
216  * and with zero ionization at z=0.
217  * It probably make sense to set the parameters with
218  * a metalicity dependence. */
219  double LambdaNet = get_heatingcooling_rate(dens, egyhot, 1 - HYDROGEN_MASSFRAC, 0, 0, &uvbg, &ne);
220 
221  double tcool = egyhot / (- LambdaNet);
222 
223  /*Convert back to internal units*/
224  tcool /= coolunits.tt_in_s;
225 
226  //message(1, "tcool = %g LambdaNet = %g ne=%g\n", tcool, LambdaNet, ne);
227  /* This differs by 0.13% from the old cooling code number,
228  * apparently just because of rounding errors. The excitation cooling
229  * numbers from Cen are not accurate to better than 1% anyway, so don't worry about it*/
230  assert_true(fabs(tcool / 4.68906e-06 - 1) < 1e-3);
231 
232  /*Now check that we get the desired cooling rate with a UVB*/
233  uvbg = get_global_UVBG(0);
234 
235  assert_true(uvbg.epsHep > 0);
236  assert_true(uvbg.gJHe0 > 0);
237 
238  dens /= 100;
239  LambdaNet = get_heatingcooling_rate(dens, egyhot/10., 1 - HYDROGEN_MASSFRAC, 0, 0, &uvbg, &ne);
240  //message(1, "LambdaNet = %g, uvbg=%g\n", LambdaNet, uvbg.epsHep);
241  assert_true(fabs(LambdaNet / (-0.0410059) - 1) < 1e-3);
242 
243  LambdaNet = get_heatingcooling_rate(dens/2.5, egyhot/10., 1 - HYDROGEN_MASSFRAC, 0, 0, &uvbg, &ne);
244  assert_true(LambdaNet > 0);
245  /*Check self-shielding affects the cooling rates*/
246  coolpar.SelfShieldingOn = 1;
247  set_coolpar(coolpar);
248  init_cooling_rates(TreeCool, MetalCool, &CP);
249  LambdaNet = get_heatingcooling_rate(dens*1.5, egyhot/10., 1 - HYDROGEN_MASSFRAC, 0, 0, &uvbg, &ne);
250  //message(1, "LambdaNet = %g, uvbg=%g\n", LambdaNet, uvbg.epsHep);
251  assert_false(LambdaNet > 0);
252  assert_true(fabs(LambdaNet/ (-1.64834) - 1) < 1e-3);
253 }
254 
255 #if 0
256 /* This test checks that the heating and cooling rate is as expected.
257  * In particular the physical density threshold is checked. */
258 static void test_heatingcooling_rate_sherwood(void ** state)
259 {
260  struct cooling_params coolpar = get_test_coolpar();
261  coolpar.recomb = Verner96;
262  coolpar.cooling = Sherwood;
263 // coolpar.recomb = Cen92;
264 // coolpar.cooling = KWH92;
265 
266  coolpar.SelfShieldingOn = 0;
267  coolpar.MinGasTemp = 0;
268 
269  const char * TreeCool = GADGET_TESTDATA_ROOT "/examples/TREECOOL_ep_2018p";
270  const char * MetalCool = "";
271 
272  /*unit system*/
273  double HubbleParam = 0.679;
274  Cosmology CP = {0};
275  CP.OmegaCDM = 0.264;
276  CP.OmegaBaryon = coolpar.fBar * CP.OmegaCDM;
277  CP.HubbleParam = HubbleParam;
278 
279  set_coolpar(coolpar);
280  init_cooling_rates(TreeCool, MetalCool, &CP);
281 
282  /* temp at mean cosmological density */
283  double rhocb = CP.OmegaBaryon * 3.0 * pow(CP.HubbleParam*HUBBLE,2.0) /(8.0*M_PI*GRAVITY)/PROTONMASS;
284  double ne = rhocb;
285 
286  /* Loop over redshift*/
287  /* Now check that we get the desired cooling rate with a UVB*/
288  struct UVBG uvbg = get_global_UVBG(2);
289  double ienergy = 2.105e12;
290  double temp = get_temp(rhocb, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
291  int i;
292  FILE * fd = fopen("cooling_rates_sherwood.txt", "w");
293  fprintf(fd, "#density = %g temp = %g\n", rhocb, temp);
294  fprintf(fd, "#zz LambdaNet Heat FF Collis Recomb Cmptn temp ne\n");
295  FILE * fd2 = fopen("ion_state.txt", "w");
296  fprintf(fd2, "#zz nhcgs nH0 nHe0 nHep nHepp\n");
297  for(i = 0; i < 500; i++)
298  {
299  double zz = i * 6./ 500.;
300  uvbg = get_global_UVBG(zz);
301  double dens = rhocb * pow(1+zz,3);
302  double LambdaNet = get_heatingcooling_rate(dens, ienergy, 1 - HYDROGEN_MASSFRAC, zz, 0, &uvbg, &ne);
303  double LambdaCmptn = get_compton_cooling(dens, ienergy, 1 - HYDROGEN_MASSFRAC, zz, ne);
304  double LambdaCollis = get_individual_cooling(COLLIS, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
305  double LambdaRecomb = get_individual_cooling(RECOMB, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
306  double LambdaFF = get_individual_cooling(FREEFREE, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
307  double Heat = get_individual_cooling(HEAT, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
308  double temp = get_temp(dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
309  fprintf(fd, "%g %g %g %g %g %g %g %g %g\n",zz, LambdaNet, Heat, LambdaFF, LambdaCollis, LambdaRecomb, LambdaCmptn, temp, ne);
310  double nH0 = get_neutral_fraction_phys_cgs(dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, &ne);
311  double He0 = get_helium_ion_phys_cgs(0, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, ne);
312  double Hep = get_helium_ion_phys_cgs(1, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, ne);
313  double Hepp = get_helium_ion_phys_cgs(2, dens, ienergy, 1 - HYDROGEN_MASSFRAC, &uvbg, ne);
314  fprintf(fd2, "%g %g %g %g %g %g\n", zz, dens * HYDROGEN_MASSFRAC, nH0, He0, Hep, Hepp);
315  }
316  fclose(fd);
317  fclose(fd2);
318 }
319 #endif
320 
321 int main(void) {
322  const struct CMUnitTest tests[] = {
323  cmocka_unit_test(test_recomb_rates),
324  cmocka_unit_test(test_rate_network),
325  cmocka_unit_test(test_heatingcooling_rate),
326  cmocka_unit_test(test_uvbg_loader)
327  };
328  return cmocka_run_group_tests_mpi(tests, NULL, NULL);
329 }
static struct cooling_units coolunits
Definition: cooling.c:33
double get_temp(double density, double ienergy, double helium, const struct UVBG *uvbg, double *ne_init)
struct UVBG get_global_UVBG(double redshift)
double get_compton_cooling(double density, double ienergy, double helium, double redshift, double nebynh)
double get_equilib_ne(double density, double ienergy, double helium, double *logt, const struct UVBG *uvbg, double ne_init)
double get_helium_ion_phys_cgs(int ion, double density, double ienergy, double helium, const struct UVBG *uvbg, double ne_init)
double get_heatingcooling_rate(double density, double ienergy, double helium, double redshift, double metallicity, const struct UVBG *uvbg, double *ne_equilib)
void set_coolpar(struct cooling_params cp)
double get_neutral_fraction_phys_cgs(double density, double ienergy, double helium, const struct UVBG *uvbg, double *ne_init)
void init_cooling_rates(const char *TreeCoolFile, const char *MetalCoolFile, Cosmology *CP)
double get_individual_cooling(enum CoolProcess process, double density, double ienergy, double helium, const struct UVBG *uvbg, double *ne_equilib)
@ Sherwood
Definition: cooling_rates.h:19
@ KWH92
Definition: cooling_rates.h:17
@ RECOMB
Definition: cooling_rates.h:95
@ HEAT
Definition: cooling_rates.h:98
@ COLLIS
Definition: cooling_rates.h:96
@ FREEFREE
Definition: cooling_rates.h:97
@ Cen92
Definition: cooling_rates.h:11
@ Verner96
Definition: cooling_rates.h:12
struct @1 MetalCool
#define HUBBLE
Definition: physconst.h:25
#define HYDROGEN_MASSFRAC
Definition: physconst.h:37
#define GRAVITY
Definition: physconst.h:5
#define PROTONMASS
Definition: physconst.h:21
static Cosmology * CP
Definition: power.c:27
static double UnitLength_in_cm
Definition: power.c:26
double HubbleParam
Definition: cosmology.h:20
double OmegaCDM
Definition: cosmology.h:11
double OmegaBaryon
Definition: cosmology.h:19
Definition: cooling.h:8
double epsHep
Definition: cooling.h:13
double epsH0
Definition: cooling.h:12
double gJHep
Definition: cooling.h:10
double gJHe0
Definition: cooling.h:11
double gJH0
Definition: cooling.h:9
double self_shield_dens
Definition: cooling.h:15
double epsHe0
Definition: cooling.h:14
enum RecombType recomb
Definition: cooling_rates.h:26
double CMBTemperature
Definition: cooling_rates.h:41
enum CoolingType cooling
Definition: cooling_rates.h:28
int CoolingOn
Definition: cooling.h:23
double density_in_phys_cgs
Definition: cooling.h:25
double tt_in_s
Definition: cooling.h:29
double uu_in_cgs
Definition: cooling.h:27
double recomb_alphaHp(double temp)
static void test_heatingcooling_rate(void **state)
static const double tt[NEXACT]
static struct cooling_params get_test_coolpar(void)
static const double f92n1[NEXACT]
static void test_recomb_rates(void **state)
int main(void)
#define NEXACT
int during_helium_reionization(double redshift)
static void test_rate_network(void **state)
static void test_uvbg_loader(void **state)
static const double f92g2[NEXACT]