MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
cooling.c
Go to the documentation of this file.
1 /**************
2  * This file is based on the Gadget-3 cooling.c.
3  *
4  * The main atomic rates have been rewritten from scratch and now exist in cooling_rates.c.
5  * There is also support for metal cooling and a fluctuating UV background in cooling_uvfluc.c
6  *
7  * There is no public version of original cooling.c freely available.
8  *
9  * Only reference is 2004 version by Brian O'Shea in ENZO repo,
10  * which contains a deferred freedom claimer depending on the action
11  * of Volker Springel.
12  *
13  * The LICENSE of the DoCooling function is therefore still in limbo,
14  * although everything else is now unencumbered.
15  *
16  ************** */
17 
18 #include <mpi.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 #include <bigfile.h>
24 #include "utils/endrun.h"
25 #include "utils/mymalloc.h"
26 #include "utils/interp.h"
27 #include "physconst.h"
28 #include "cooling.h"
29 #include "cooling_rates.h"
30 #include "cooling_qso_lightup.h"
31 #include "cosmology.h"
32 
33 static struct cooling_units coolunits;
34 
35 /*Do initialisation for the cooling module*/
36 void init_cooling(const char * TreeCoolFile, const char * MetalCoolFile, char * reion_hist_file, struct cooling_units cu, Cosmology * CP)
37 {
38  coolunits = cu;
39  /*Initialize the cooling rates*/
41  init_cooling_rates(TreeCoolFile, MetalCoolFile, CP);
42  /* Initialize the helium reionization model*/
43  init_qso_lightup(reion_hist_file);
44 }
45 
46 #define MAXITER 1000
47 
48 /* Wrapper function which returns the rate of change of internal energy in units of
49  * erg/s/g. Arguments:
50  * rho: density in protons/cm^3 (physical)
51  * u: internal energy in units of erg/g
52  * Z: metallicity
53  * redshift: redshift
54  * isHeIIIionized: flags whether the particle has been HeII reionized.
55  */
56 static double
57 get_lambdanet(double rho, double u, double redshift, double Z, struct UVBG * uvbg, double * ne_guess, int isHeIIIionized)
58 {
59  double LambdaNet = get_heatingcooling_rate(rho, u, 1 - HYDROGEN_MASSFRAC, redshift, Z, uvbg, ne_guess);
60  if(!isHeIIIionized) {
61  /* get_long_mean_free_path_heating returns the heating in units of erg/s/cm^3,
62  * the factor of the mean density converts from erg/s/cm^3 to erg/s/g */
63  LambdaNet += get_long_mean_free_path_heating(redshift) / (coolunits.rho_crit_baryon * pow(1 + redshift,3));
64  }
65  return LambdaNet;
66 }
67 
68 /* returns new internal energy per unit mass.
69  * Arguments are passed in code units, density is proper density.
70  */
71 double DoCooling(double redshift, double u_old, double rho, double dt, struct UVBG * uvbg, double *ne_guess, double Z, double MinEgySpec, int isHeIIIionized)
72 {
73  if(!coolunits.CoolingOn) return 0;
74 
75  double u, du;
76  double u_lower, u_upper;
77  double LambdaNet;
78  int iter = 0;
79 
80  rho *= coolunits.density_in_phys_cgs / PROTONMASS; /* convert to (physical) protons/cm^3 */
81  u_old *= coolunits.uu_in_cgs;
82  MinEgySpec *= coolunits.uu_in_cgs;
83  if(u_old < MinEgySpec)
84  u_old = MinEgySpec;
85  dt *= coolunits.tt_in_s;
86 
87  u = u_old;
88  u_lower = u;
89  u_upper = u;
90 
91  LambdaNet = get_lambdanet(rho, u, redshift, Z, uvbg, ne_guess, isHeIIIionized);
92 
93  /* bracketing */
94  if(u - u_old - LambdaNet * dt < 0) /* heating */
95  {
96  do
97  {
98  u_lower = u_upper;
99  u_upper *= 1.1;
100  } while(u_upper - u_old - get_lambdanet(rho, u_upper, redshift, Z, uvbg, ne_guess, isHeIIIionized) * dt < 0);
101  }
102  else
103  {
104  do {
105  u_upper = u_lower;
106  u_lower /= 1.1;
107  /* This means that we don't need an initial bracket*/
108  if(u_upper <= MinEgySpec) {
109  break;
110  }
111  } while(u_lower - u_old - get_lambdanet(rho, u_lower, redshift, Z, uvbg, ne_guess, isHeIIIionized) * dt > 0);
112  }
113 
114  do
115  {
116  u = 0.5 * (u_lower + u_upper);
117  /* If we know that the new energy
118  * is below the minimum gas internal energy, we are done here.*/
119  if(u_upper <= MinEgySpec) {
120  u = MinEgySpec;
121  break;
122  }
123 
124  LambdaNet = get_lambdanet(rho, u, redshift, Z, uvbg, ne_guess, isHeIIIionized);
125 
126  if(u - u_old - LambdaNet * dt > 0)
127  {
128  u_upper = u;
129  }
130  else
131  {
132  u_lower = u;
133  }
134 
135  du = u_upper - u_lower;
136 
137  iter++;
138 
139  if(iter >= (MAXITER - 10))
140  message(1, "u= %g\n", u);
141  }
142  while(fabs(du / u) > 1.0e-6 && iter < MAXITER);
143 
144  if(iter >= MAXITER)
145  {
146  endrun(10, "failed to converge in DoCooling()\n");
147  }
148 
149  u /= coolunits.uu_in_cgs; /*convert back to internal units */
150 
151  return u;
152 }
153 
154 /* returns cooling time.
155  * NOTE: If we actually have heating, a cooling time of 0 is returned.
156  */
157 double GetCoolingTime(double redshift, double u_old, double rho, struct UVBG * uvbg, double *ne_guess, double Z)
158 {
159  if(!coolunits.CoolingOn) return 0;
160 
161  /* convert to physical cgs units */
163  u_old *= coolunits.uu_in_cgs;
164 
165  /* Note: this does not include the long mean free path heating from helium reionization*/
166  double LambdaNet = get_heatingcooling_rate(rho, u_old, 1 - HYDROGEN_MASSFRAC, redshift, Z, uvbg, ne_guess);
167 
168  if(LambdaNet >= 0) /* ups, we have actually heating due to UV background */
169  return 0;
170 
171  double coolingtime = u_old / (- LambdaNet);
172 
173  /*Convert back to internal units*/
174  coolingtime /= coolunits.tt_in_s;
175 
176  return coolingtime;
177 }
178 
179 /*Gets the neutral fraction from density and internal energy in internal units*/
180 double
181 GetNeutralFraction(double u_old, double rho, const struct UVBG * uvbg, double ne_init)
182 {
183  /* convert to physical cgs units */
185  u_old *= coolunits.uu_in_cgs;
186  double nh0 = get_neutral_fraction_phys_cgs(rho, u_old, 1 - HYDROGEN_MASSFRAC, uvbg, &ne_init);
187  return nh0;
188 }
189 
190 /*Gets the helium ion fraction from density and internal energy in internal units*/
191 double
192 GetHeliumIonFraction(int ion, double u_old, double rho, const struct UVBG * uvbg, double ne_init)
193 {
194  /* convert to physical cgs units */
196  u_old *= coolunits.uu_in_cgs;
197  double helium_ion = get_helium_ion_phys_cgs(ion, rho, u_old, 1 - HYDROGEN_MASSFRAC, uvbg, ne_init);
198  return helium_ion;
199 }
void init_cooling(const char *TreeCoolFile, const char *MetalCoolFile, char *reion_hist_file, struct cooling_units cu, Cosmology *CP)
Definition: cooling.c:36
double GetCoolingTime(double redshift, double u_old, double rho, struct UVBG *uvbg, double *ne_guess, double Z)
Definition: cooling.c:157
static double get_lambdanet(double rho, double u, double redshift, double Z, struct UVBG *uvbg, double *ne_guess, int isHeIIIionized)
Definition: cooling.c:57
#define MAXITER
Definition: cooling.c:46
static struct cooling_units coolunits
Definition: cooling.c:33
double DoCooling(double redshift, double u_old, double rho, double dt, struct UVBG *uvbg, double *ne_guess, double Z, double MinEgySpec, int isHeIIIionized)
Definition: cooling.c:71
double GetHeliumIonFraction(int ion, double u_old, double rho, const struct UVBG *uvbg, double ne_init)
Definition: cooling.c:192
double GetNeutralFraction(double u_old, double rho, const struct UVBG *uvbg, double ne_init)
Definition: cooling.c:181
double get_long_mean_free_path_heating(double redshift)
void init_qso_lightup(char *reion_hist_file)
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)
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)
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
#define HYDROGEN_MASSFRAC
Definition: physconst.h:37
#define PROTONMASS
Definition: physconst.h:21
static Cosmology * CP
Definition: power.c:27
Definition: cooling.h:8
double rho_crit_baryon
Definition: cooling.h:31
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