Cholla 3.0.1-dev
Cholla - Massively parallel hydro on GPUs
Loading...
Searching...
No Matches
cool_components.h
Go to the documentation of this file.
1
4#pragma once
5
6#include <cmath>
7
8#include "../global/global.h"
9#include "../io/ParameterMap.h"
10#include "../utils/error_handling.h"
11#include "../utils/gpu.hpp" // inlcudes HIP header that define __forceinline__
12
52{
53
55inline __device__ Real primordial_cool(Real n, Real T)
56{
57 Real n_h, Y, y, g_ff, cool;
58 Real n_h0, n_hp, n_he0, n_hep, n_hepp, n_e, n_e_old;
59 Real alpha_hp, alpha_hep, alpha_d, alpha_hepp, gamma_eh0, gamma_ehe0, gamma_ehep;
60 Real le_h0, le_hep, li_h0, li_he0, li_hep, lr_hp, lr_hep, lr_hepp, ld_hep, l_ff;
61 Real gamma_lh0, gamma_lhe0, gamma_lhep, e_h0, e_he0, e_hep, H;
62 int heat_flag, n_iter;
63 Real diff, tol;
64
65 // set flag to 1 for photoionization & heating
66 heat_flag = 0;
67
68 // Real X = 0.76; //hydrogen abundance by mass
69 Y = 0.24; // helium abundance by mass
70 y = Y / (4 - 4 * Y);
71
72 // set the hydrogen number density
73 n_h = n;
74
75 // calculate the recombination and collisional ionization rates
76 // (Table 2 from Katz 1996)
77 alpha_hp = (8.4e-11) * (1.0 / sqrt(T)) * pow((T / 1e3), (-0.2)) * (1.0 / (1.0 + pow((T / 1e6), (0.7))));
78 alpha_hep = (1.5e-10) * (pow(T, (-0.6353)));
79 alpha_d = (1.9e-3) * (pow(T, (-1.5))) * exp(-470000.0 / T) * (1.0 + 0.3 * exp(-94000.0 / T));
80 alpha_hepp = (3.36e-10) * (1.0 / sqrt(T)) * pow((T / 1e3), (-0.2)) * (1.0 / (1.0 + pow((T / 1e6), (0.7))));
81 gamma_eh0 = (5.85e-11) * sqrt(T) * exp(-157809.1 / T) * (1.0 / (1.0 + sqrt(T / 1e5)));
82 gamma_ehe0 = (2.38e-11) * sqrt(T) * exp(-285335.4 / T) * (1.0 / (1.0 + sqrt(T / 1e5)));
83 gamma_ehep = (5.68e-12) * sqrt(T) * exp(-631515.0 / T) * (1.0 / (1.0 + sqrt(T / 1e5)));
84 // externally evaluated integrals for photoionization rates
85 // assumed J(nu) = 10^-22 (nu_L/nu)
86 gamma_lh0 = 3.19851e-13;
87 gamma_lhe0 = 3.13029e-13;
88 gamma_lhep = 2.00541e-14;
89 // externally evaluated integrals for heating rates
90 e_h0 = 2.4796e-24;
91 e_he0 = 6.86167e-24;
92 e_hep = 6.21868e-25;
93
94 // assuming no photoionization, solve equations for number density of
95 // each species
96 n_e = n_h; // as a first guess, use the hydrogen number density
97 n_iter = 20;
98 diff = 1.0;
99 tol = 1.0e-6;
100 if (heat_flag) {
101 for (int i = 0; i < n_iter; i++) {
102 n_e_old = n_e;
103 n_h0 = n_h * alpha_hp / (alpha_hp + gamma_eh0 + gamma_lh0 / n_e);
104 n_hp = n_h - n_h0;
105 n_hep = y * n_h /
106 (1.0 + (alpha_hep + alpha_d) / (gamma_ehe0 + gamma_lhe0 / n_e) +
107 (gamma_ehep + gamma_lhep / n_e) / alpha_hepp);
108 n_he0 = n_hep * (alpha_hep + alpha_d) / (gamma_ehe0 + gamma_lhe0 / n_e);
109 n_hepp = n_hep * (gamma_ehep + gamma_lhep / n_e) / alpha_hepp;
110 n_e = n_hp + n_hep + 2 * n_hepp;
111 diff = fabs(n_e_old - n_e);
112 if (diff < tol) {
113 break;
114 }
115 }
116 } else {
117 n_h0 = n_h * alpha_hp / (alpha_hp + gamma_eh0);
118 n_hp = n_h - n_h0;
119 n_hep = y * n_h / (1.0 + (alpha_hep + alpha_d) / (gamma_ehe0) + (gamma_ehep) / alpha_hepp);
120 n_he0 = n_hep * (alpha_hep + alpha_d) / (gamma_ehe0);
121 n_hepp = n_hep * (gamma_ehep) / alpha_hepp;
122 n_e = n_hp + n_hep + 2 * n_hepp;
123 }
124
125 // using number densities, calculate cooling rates for
126 // various processes (Table 1 from Katz 1996)
127 le_h0 = (7.50e-19) * exp(-118348.0 / T) * (1.0 / (1.0 + sqrt(T / 1e5))) * n_e * n_h0;
128 le_hep = (5.54e-17) * pow(T, (-0.397)) * exp(-473638.0 / T) * (1.0 / (1.0 + sqrt(T / 1e5))) * n_e * n_hep;
129 li_h0 = (1.27e-21) * sqrt(T) * exp(-157809.1 / T) * (1.0 / (1.0 + sqrt(T / 1e5))) * n_e * n_h0;
130 li_he0 = (9.38e-22) * sqrt(T) * exp(-285335.4 / T) * (1.0 / (1.0 + sqrt(T / 1e5))) * n_e * n_he0;
131 li_hep = (4.95e-22) * sqrt(T) * exp(-631515.0 / T) * (1.0 / (1.0 + sqrt(T / 1e5))) * n_e * n_hep;
132 lr_hp = (8.70e-27) * sqrt(T) * pow((T / 1e3), (-0.2)) * (1.0 / (1.0 + pow((T / 1e6), (0.7)))) * n_e * n_hp;
133 lr_hep = (1.55e-26) * pow(T, (0.3647)) * n_e * n_hep;
134 lr_hepp = (3.48e-26) * sqrt(T) * pow((T / 1e3), (-0.2)) * (1.0 / (1.0 + pow((T / 1e6), (0.7)))) * n_e * n_hepp;
135 ld_hep = (1.24e-13) * pow(T, (-1.5)) * exp(-470000.0 / T) * (1.0 + 0.3 * exp(-94000.0 / T)) * n_e * n_hep;
136 g_ff = 1.1 + 0.34 * exp(-(5.5 - log(T)) * (5.5 - log(T)) / 3.0); // Gaunt factor
137 l_ff = (1.42e-27) * g_ff * sqrt(T) * (n_hp + n_hep + 4 * n_hepp) * n_e;
138
139 // calculate total cooling rate (erg s^-1 cm^-3)
140 cool = le_h0 + le_hep + li_h0 + li_he0 + li_hep + lr_hp + lr_hep + lr_hepp + ld_hep + l_ff;
141
142 // calculate total photoionization heating rate
143 H = 0.0;
144 if (heat_flag) {
145 H = n_h0 * e_h0 + n_he0 * e_he0 + n_hep * e_hep;
146 }
147
148 cool -= H;
149
150 return cool;
151}
152
159inline __device__ Real analytic_creasey11_lambda(Real n, Real T)
160{
161 Real T0 = 10000.0;
162 Real T1 = 20 * T0;
163 // Real lambda = 5.0e-24; //cooling coefficient, 5e-24 erg cm^3 s^-1
164 Real lambda = 5.0e-20; // cooling coefficient, 5e-24 erg cm^3 s^-1
165
166 // constant cooling rate
167 // cool = n*n*lambda;
168
169 // Creasey cooling function
170 if (T >= T0 && T <= 0.5 * (T1 + T0)) {
171 return lambda * (T - T0) / T0;
172 } else if (T >= 0.5 * (T1 + T0) && T <= T1) {
173 return lambda * (T1 - T) / T0;
174 } else {
175 return 0.0;
176 }
177}
178
192__device__ __forceinline__ Real analytic_cie_lambda(Real log10T)
193{
194 // fit to CIE cooling function
195 if (log10T < 4.0) {
196 return 0.0;
197 } else if (log10T >= 4.0 && log10T < 5.9) {
198 return pow(10.0, (-1.3 * (log10T - 5.25) * (log10T - 5.25) - 21.25));
199 } else if (log10T >= 5.9 && log10T < 7.4) {
200 return pow(10.0, (0.7 * (log10T - 7.1) * (log10T - 7.1) - 22.8));
201 } else {
202 return pow(10.0, (0.45 * log10T - 26.065));
203 }
204}
205
218__device__ __forceinline__ Real analytic_koyama_inutsuka_02_lambda(Real T)
219{
220 return 2e-26 * (1e7 * exp(-1.148e5 / (T + 1000.0)) + 1.4e-2 * sqrt(T) * exp(-92.0 / T));
221}
222
246__device__ __forceinline__ Real combined_analytic_ti_cie_lambda(Real T)
247{
248 if (T < 10.0) {
249 return 0.0; // no cooling below 10 K
250 } else if (T >= 10.0 && T < 1e4) {
252 } else {
253 return analytic_cie_lambda(log10(T));
254 }
255}
256
273{
281 double n_av_cgs_;
282
283 inline static constexpr const char* use_photoelectric_parname = "chemistry.photoelectric_heating";
284 inline static constexpr const char* photoelectric_n_av_parname = "chemistry.photoelectric_n_av_cgs";
285
286 public:
287 __host__ static bool is_specified_by_params(ParameterMap& pmap)
288 {
289 return pmap.value_or(PhotoelectricHeatingModel::use_photoelectric_parname, false);
290 }
291
292 __host__ explicit PhotoelectricHeatingModel(ParameterMap& pmap)
293 {
294 // In this case, we want to actually use photoelectric heating
295 if (pmap.value_or(PhotoelectricHeatingModel::use_photoelectric_parname, false)) {
296 double n_av_cgs = pmap.value_or(PhotoelectricHeatingModel::photoelectric_n_av_parname, 100.0);
297 CHOLLA_ASSERT(n_av_cgs > 0.0, "The \"%s\" parameter cannot specify a non-positive value",
298 PhotoelectricHeatingModel::photoelectric_n_av_parname);
299 n_av_cgs_ = n_av_cgs;
300 } else {
301 // in this case, we initialize an instance that doesn't actually perform any
302 // heating/cooling. We may want to get rid of this branch
303 CHOLLA_ASSERT(!pmap.has_param(photoelectric_n_av_parname),
304 "It is an error to specify the \"%s\" parameter when the \"%s\" hasn't "
305 "explicitly been set to true.",
306 PhotoelectricHeatingModel::photoelectric_n_av_parname,
307 PhotoelectricHeatingModel::use_photoelectric_parname);
308 n_av_cgs_ = 0.0; // <- this means that there isn't heating
309 }
310 }
311
312 bool is_active() const { return n_av_cgs_ != 0.0; }
313
318 __device__ Real operator()(Real n, Real T) const { return (T < 1e4) ? n * n_av_cgs_ * 1.0e-26 : 0.0; }
319};
320
321} // namespace cool_component
322
// end of group
A class that provides map-like access to parameter files.
Definition ParameterMap.h:74
Definition cool_components.h:273
__device__ Real operator()(Real n, Real T) const
computes the heating rate per unit volume, erg /s / cm^3.
Definition cool_components.h:318
Describes cooling components.
Definition cool_components.h:52
__device__ __forceinline__ Real combined_analytic_ti_cie_lambda(Real T)
Analytic cooling function recipe that roughly matches the "TI" cooling runs shown in in Kim & Ostrike...
Definition cool_components.h:246
__device__ Real primordial_cool(Real n, Real T)
Definition cool_components.h:55
__device__ Real analytic_creasey11_lambda(Real n, Real T)
Cooling the cooling function from Creasey 2011.
Definition cool_components.h:159
__device__ __forceinline__ Real analytic_cie_lambda(Real log10T)
computes the cooling rate, based on an analytic fit to a solar metallicity CIE cooling curve calculat...
Definition cool_components.h:192
__device__ __forceinline__ Real analytic_koyama_inutsuka_02_lambda(Real T)
computes the cooling rate, based on an analytic fit provided in Koyama & Inutsuka (2002)
Definition cool_components.h:218