PLUTO
pvte_law_dAngelo.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Basic interface definition for the \c PVTE_LAW EoS.
5 
6  Collect the basic set of functions required by the
7  \c PVTE_LAW equation of state:
8 
9  - InternalEnergyFunc() defines the gas internal energy as a function
10  temperature and ionization fractions (for non-equilibrium chemistry)
11  or temperature and density (in Local Thermodynamic Equilibrium - LTE -
12  or Collisional Ionization Equilibrium - CIE).
13  - GetMu() computes the mean molecular weight (in LTE or CIE).
14 
15  Auxiliary functions (needed by the the previous ones) are also
16  included here.
17 
18  The current version implements the EoS given by D'Angelo (2013).
19 
20  \author A. Mignone (mignone@ph.unito.it)\n
21  B. Vaidya
22  \date 20 June, 2014
23 
24  \b Reference
25  - D'Angelo et. al ApJ 778, 2013 (Eq. [26-27])
26 
27 */
28 /* /////////////////////////////////////////////////////////////////// */
29 #include "pluto.h"
30 
31 #define HELIUM_IONIZATION NO
32 
33 #define DEG_x 0 /* hydrogen ionization degree */
34 #define DEG_y 1 /* molecular hydrogen dissociation degree */
35 #define DEG_z1 2 /* helium single ionization degree */
36 #define DEG_z2 3 /* helium double ionization degree */
37 
38 
39 void GetFuncDum(double, double *);
40 #if NIONS == 0
41  static void GetSahaHFracs (double, double, double *);
42 #else
43  static void GetHFracs (double *, double *);
44 #endif
45 
46 /* ***************************************************************** */
47 double InternalEnergyFunc(double *v, double T)
48 /*!
49  * Compute the gas internal energy as a function of temperature
50  * and fractions (or density):
51  * - <tt> rhoe = rhoe(T,rho) </tt> in LTE or CIE;
52  * - <tt> rhoe = rhoe(T,X) </tt> in non-equilibrium chemistry.
53  *
54  * \param [in] v 1D Array of primitive variables containing
55  * density and species. Other variables are
56  * ignored.
57  * \param [in] T Gas temperature
58  *
59  * \return The gas internal energy (\c rhoe) in code units.
60  ******************************************************************* */
61 {
62  double eH, eHe, eHpH, eHplus, eH2, rhoe, eHeplus, eHeplusplus;
63  double func_zetaR;
64  double f[4];
65 
66  #if NIONS == 0
67  GetSahaHFracs(T, v[RHO], f);
68  #else
69  GetHFracs (v, f);
70  if (f[DEG_x] > 1.001 || f[DEG_y] > 1.001){
71  printf ("! InternalEnergy: x or y are too large %f, %f\n",
72  f[DEG_x],f[DEG_y]);
73  QUIT_PLUTO(1);
74  }
75  #endif
76 
77  GetFuncDum(T, &func_zetaR); /* = (1.5 + e(rot) + e(vib)) */
78 /* func_zetaR = 1.5; to recover ideal EoS */
79 
80 /* -- Estimate contributions to Egas -- */
81 
82  eH = 1.5*H_MASS_FRAC*(1.0 + f[DEG_x])*f[DEG_y];
83  eHe = 3.0*He_MASS_FRAC/8.0;
84  eH2 = 0.5*H_MASS_FRAC*(1.0 - f[DEG_y])*func_zetaR;
85 
86 /* -- constant terms -- */
87 
88  #if COOLING == NO
89  eHpH = 4.48*CONST_eV*H_MASS_FRAC*f[DEG_y]/(2.0*CONST_kB*T);
90  eHplus = 13.60*CONST_eV*H_MASS_FRAC*f[DEG_x]*f[DEG_y]/(CONST_kB*T);
91 
92  #if HELIUM_IONIZATION == YES
93  eHeplus = 24.59*CONST_eV*He_MASS_FRAC*f[DEG_z1]*(1.0 - f[DEG_z2])/(4.0*CONST_kB*T);
94  eHeplusplus = 54.42*CONST_eV*He_MASS_FRAC*f[DEG_z1]*f[DEG_z2]/(4.0*CONST_kB*T);
95  #else
96  eHeplus = eHeplusplus = 0.0;
97  #endif
98 
99  #else
100  eHpH = eHplus = eHeplus = eHeplusplus = 0.0;
101  #endif
102 
103 /* ----------------------------------------------------------------
104  Compute rhoe in cgs except for density which is left in
105  code units (to avoid extra multiplication and division later
106  ---------------------------------------------------------------- */
107 
108  rhoe = (eH2 + eH + eHe + eHpH + eHplus + eHeplus + eHeplusplus)*(CONST_kB*T*v[RHO]/CONST_mH);
109 
110  return rhoe/(UNIT_VELOCITY*UNIT_VELOCITY); /* convert to code units */
111 }
112 
113 #if NIONS == 0
114 /* ********************************************************************* */
115 void GetMu(double T, double rho, double *mu)
116 /*!
117  * Calculate the mean molecular weight for the case in which
118  * hydrogen fractions are estimated using Saha Equations.
119  *
120  * \param [in] T Gas temperature in Kelvin.
121  * \param [in] rho Gas density (code units)
122  * \param [out] mu Mean molecular weight
123  *
124  * \b Reference
125  * - Black and Bodenheimer, ApJ 199, 1975 (Eq. 8)
126  * - D'Angelo, G. et al ApJ 778, 2013 (Eqs. 15, 16.)
127  *********************************************************************** */
128 {
129  double f[4];
130 
131  GetSahaHFracs(T, rho, f);
132  #if HELIUM_IONIZATION == YES
133  *mu = 4.0/( 2.*H_MASS_FRAC*(1.0 + f[DEG_y] + 2.0*f[DEG_x]*f[DEG_y])
134  + He_MASS_FRAC*(1.0 + f[DEG_z1]*(1.0 + f[DEG_z2])));
135  #else
136  *mu = 4.0/(2.*H_MASS_FRAC*(1.0 + f[DEG_y] + 2.0*f[DEG_x]*f[DEG_y])
137  + He_MASS_FRAC);
138  #endif
139 }
140 
141 /* ********************************************************************* */
142 void GetSahaHFracs(double T, double rho, double *fdeg)
143 /*!
144  * Compute degree of ionization and dissociation using Saha Equations.
145  * The quadratic equation ay^2 + by + c = 0 is solved using
146  * a = 1, c = -b (for hydrogen). A similar expression is used for Helium.
147  *
148  * \param [in] T Gas temperature in Kelvin.
149  * \param [in] rho Gas density (in code units)
150  * \param [out] fdeg array of ionization/dissociation degrees.
151  *
152  * \b Reference
153  * - D'Angelo, G. et al ApJ 778, 2013 (Eqs. 15, 16.)
154  *
155  *********************************************************************** */
156 {
157  double rhs1, rhs2, rhs3;
158  double b,c, scrh;
159  double kT = CONST_kB*T;
160  double hbar = CONST_h/(2.0*CONST_PI);
161 
162  rho *= UNIT_DENSITY;
163 
164  rhs1 = CONST_mH/(2.0*H_MASS_FRAC*rho);
165  rhs2 = CONST_mH*kT/(4.0*CONST_PI*hbar*hbar);
166  rhs3 = exp(-4.48*CONST_eV/kT);
167  b = rhs1*rhs2*sqrt(rhs2)*rhs3;
168 
169  fdeg[DEG_y] = 2.0/(1.0 + sqrt(1.0 + 4.0/b)); /* solution of quadratic equation */
170 
171  rhs1 = CONST_mH/(H_MASS_FRAC*rho);
172  rhs2 = CONST_me*kT/(2.0*CONST_PI*hbar*hbar);
173  rhs3 = exp(-13.60*CONST_eV/kT);
174  b = rhs1*rhs2*sqrt(rhs2)*rhs3;
175 
176  fdeg[DEG_x] = 2.0/(1.0 + sqrt(1.0 + 4.0/b)); /* solution of quadratic equation */
177 
178  #if HELIUM_IONIZATION == YES
179  rhs3 = 4.0*CONST_mH/rho*rhs2*sqrt(rhs2)*exp(-24.59*CONST_eV/kT);
180  b = 4.0/He_MASS_FRAC*(H_MASS_FRAC + rhs3);
181  c = -rhs3*4.0/He_MASS_FRAC;
182  fdeg[DEG_z1] = -2.0*c/(b + sqrt(b*b - 4.0*c));
183 
184  rhs3 = CONST_mH/rho*rhs2*sqrt(rhs2)*exp(-54.42*CONST_eV/kT);
185  b = 4.0/He_MASS_FRAC*(H_MASS_FRAC + 0.25*He_MASS_FRAC + rhs3);
186  c = -rhs3*4.0/He_MASS_FRAC;
187  fdeg[DEG_z2] = -2.0*c/(b + sqrt(b*b - 4.0*c));
188  #endif
189 }
190 
191 #else
192 
193 /* ********************************************************************* */
194 void GetHFracs(double *v, double *f)
195 /*!
196  * Compute degree of ionization and dissociation
197  * from non-equillibrium evolution of various hydrogen fractions
198  * using the cooling module.
199  *
200  * \param [in] v 1D Array of primitive variables.
201  * \param [out] x Deree of Ionization of hydrogen.
202  * \param [out] y Degree of Dissociation of molecular hydrogen.
203  *
204  *********************************************************************** */
205 {
206  #if COOLING == SNEq
207  f[DEG_x] = 1.0 - v[X_HI];
208  f[DEG_y] = 1.0;
209  #elif COOLING == H2_COOL
210  /* Ionization Fraction. */
211  f[DEG_x] = v[X_HII]/(v[X_HII] + v[X_HI]);
212 
213  /* ----------------------------------------------------------
214  Dissociation Fraction y = 1.0 - mol. fraction,
215  the small epsilon = 1.0e-12 in mol.fraction is used
216  to avoid the NaN in case of very high temperature limit
217  where X_H2 = X_HI = 0.0 and fHII = 1.0.
218  Further it satisfies : y -> 1.0 as T -> Infinity.
219  ---------------------------------------------------------- */
220 
221  f[DEG_y] = 1.0 - 2.0*v[X_H2]/(2.0*v[X_H2] + v[X_HI] + 1.0e-12);
222 
223  #else
224  print1 ("! GetHFracs: not defined for this cooling\n");
225  QUIT_PLUTO(1);
226  #endif
227 }
228 #endif /* NIONS == 0 */
229 
230 /* ********************************************************************* */
231 double Gamma1(double *v)
232 /*!
233  * Calculate the value of the first adiabatic index:
234  * \f[
235  * \Gamma_1 = \frac{1}{c_V}\frac{p}{\rho T} \chi_T^2 + \chi_\rho^2
236  * \qquad{\rm where}\quad
237  * \chi_T = \left(\pd{\log p}{\log T}\right)_{\rho} =
238  * 1 - \pd{\log{\mu}}{\log T} \,;\quad
239  * \chi_\rho = \left(\pd{\log p}{\log\rho}\right)_{T} =
240  * 1 - \pd{\log{\mu}}{\log\rho} \,;\quad
241  * \f]
242  * where \c p and \c rho are in c.g.s units.
243  * Note that if species are evolved explicitly (non-equilibrium chemistry),
244  * we set \c chi=1.
245  *
246  * The heat capacity at constant volume, \c cV, is defined as the
247  * derivative of specific internal energy with respect to temperature:
248  * \f[
249  * c_V = \left.\pd{e}{T}\right|_V
250  * \f]
251  * and it is computed numerically using a centered derivative.
252  *
253  * This function is needed (at present) only when computing the
254  * sound speed in the Riemann solver.
255  * Since this is only needed for an approximated value, 5/3 (upper
256  * bound) should be ok.
257  *
258  * \b Reference
259  * - D'Angelo et. al ApJ 778, 2013 (Eq. [26-27])
260  *
261  * \param [in] v 1D array of primitive quantities
262  *
263  * \return Value of first adiabatic index Gamma1.
264  *********************************************************************** */
265 {
266  double gmm1, T;
267  double cv, mu, chirho = 1.0, chiT = 1.0, rho, rhoe;
268  double ep, em, delta = 1.e-2;
269  double Tp, Tm, mup, mum, rhop, rhom;
270  double dmu_dT, dmu_drho, de_dT;
271 
272  return 1.6667; /* !! For the current implementation, we always return
273  5/3 rather then computing the actual Gamma1 index
274  (which is quite expensive).
275  We do not think this is a major problem since
276  Gamma1 only appears in the estimate of the sound speed
277  needed by the Riemann solver. An upper bound will do. */
278 /* ---------------------------------------------
279  Obtain temperature and fractions.
280  --------------------------------------------- */
281 
282  #if NIONS == 0
283  GetPV_Temperature(v, &T);
284  GetMu(T, v[RHO], &mu);
285  #else
286  mu = MeanMolecularWeight(v);
287  T = v[PRS]/v[RHO]*KELVIN*mu;
288  #endif
289 
290 /* ---------------------------------------------------
291  Compute cV (Specific heat capacity for constant
292  volume) using centered derivative.
293  cV will be in code units. The corresponding cgs
294  units will be the same velocity^2/Kelvin.
295  --------------------------------------------------- */
296 
297  Tp = T*(1.0 + delta);
298  Tm = T*(1.0 - delta);
299  em = InternalEnergy(v, Tm)/v[RHO]; /* in code units */
300  ep = InternalEnergy(v, Tp)/v[RHO]; /* in code units */
301 
302  de_dT = (ep - em)/(2.0*delta*T);
303  cv = de_dT; /* this is code units. */
304 
305  #if NIONS == 0
306  rho = v[RHO];
307 
308  GetMu(Tp, rho, &mup);
309  GetMu(Tm, rho, &mum);
310  dmu_dT = (mup - mum)/(2.0*delta*T);
311  chiT = 1.0 - T/mu*dmu_dT;
312 
313  rhop = rho*(1.0 + delta);
314  rhom = rho*(1.0 - delta);
315  GetMu(T, rhop, &mup);
316  GetMu(T, rhom, &mum);
317  dmu_drho = (mup - mum)/(2.0*delta*rho);
318  chirho = 1.0 - rho/mu*dmu_drho;
319  #endif
320 
321 /* --------------------------------------------
322  Compute first adiabatic index
323  -------------------------------------------- */
324 
325  gmm1 = v[PRS]/(cv*T*v[RHO])*chiT*chiT + chirho;
326 
327  return gmm1;
328 }
329 
330 #if NIONS > 0
331 /* ********************************************************************* */
332 void InternalEnergyBracket (double rhoe, double *v, double *Tlo, double *Thi)
333 /*
334  *
335  *********************************************************************** */
336 {
337  double rho = v[RHO];
338  const double norm=CONST_kB*rho/CONST_mH;
339  const double a = 1.5*H_MASS_FRAC;
340  const double b = 3.0*He_MASS_FRAC/8.0;
341  const double c = 0.5*H_MASS_FRAC;
342  double q = rhoe*(UNIT_VELOCITY*UNIT_VELOCITY)/norm;
343  double f[4];
344 
345  GetHFracs (v, f);
346 
347  (*Thi) = q/(a*(1.0 + f[DEG_x])*f[DEG_y] + b + c*(1.0 - f[DEG_y])*1.49);
348  (*Tlo) = q/(a*(1.0 + f[DEG_x])*f[DEG_y] + b + c*(1.0 - f[DEG_y])*3.7);
349 
350 /* -- enlarge the interval by a little to avoid problems when y = 1 -- */
351 
352  (*Tlo) *= 0.99; /* avoid negative temperature */
353  (*Thi) += 1.0;
354 }
355 #endif
356 
#define CONST_h
Planck Constant.
Definition: pluto.h:258
static double a
Definition: init.c:135
tuple T
Definition: Sph_disk.py:33
#define DEG_y
#define UNIT_DENSITY
Unit density in gr/cm^3.
Definition: pluto.h:369
double InternalEnergy(double *v, double T)
#define CONST_eV
Electron Volt in erg.
Definition: pluto.h:256
void print1(const char *fmt,...)
Definition: amrPluto.cpp:511
#define RHO
Definition: mod_defs.h:19
tuple scrh
Definition: configure.py:200
double rhoe
Definition: eos.h:107
#define DEG_z2
double v[NVAR]
Definition: eos.h:106
static void GetSahaHFracs(double, double, double *)
void GetMu(double T, double rho, double *mu)
#define KELVIN
Definition: pluto.h:401
#define He_MASS_FRAC
Definition: pluto.h:551
#define CONST_me
Electron mass.
Definition: pluto.h:263
void GetFuncDum(double, double *)
Definition: zeta_tables.c:16
#define UNIT_VELOCITY
Unit velocity in cm/sec.
Definition: pluto.h:377
#define X_HII
Definition: cooling.h:31
#define CONST_kB
Boltzmann constant.
Definition: pluto.h:259
#define CONST_mH
Hydrogen atom mass.
Definition: pluto.h:264
Definition: cooling.h:110
tuple c
Definition: menu.py:375
#define DEG_x
PLUTO main header file.
#define DEG_z1
double MeanMolecularWeight(double *V)
double InternalEnergyFunc(double *v, double T)
#define CONST_PI
.
Definition: pluto.h:269
#define X_H2
Definition: cooling.h:30
double Gamma1(double *v)
int GetPV_Temperature(double *v, double *T)
Definition: thermal_eos.c:221
#define H_MASS_FRAC
Definition: pluto.h:542
static Runtime q
#define QUIT_PLUTO(e_code)
Definition: macros.h:125