PLUTO
internal_energy.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Thermodynamic relations for the caloric EoS, \c e=e(T,rho) and
5  \c T=T(e,rho).
6 
7  Collect various functions involving computations between internal
8  energy, density and temperature,
9  \f[
10  e = e(T,\vec{X})\,,\qquad
11  T = T(e,\vec{X})
12  \f]
13  where \c e is the specific internal energy, \c T is the temperature
14  and \c X are the ionization fractions.
15  The first relation is used to retrieve \c e as a function of
16  \c T and \c X by calling InternalEnergy() while the second one computes
17  \c T from internal energy and fractions and it is handled by the
18  function GetEV_Temperature():
19 
20  If no chemistry is used (\c NIONS==0 ), ionization fractions
21  are computed assuming equilibrium conditions and \c X=X(T,rho).
22  This requires the numerical inversion of the second equation
23  <tt> T=(e,X(T,rho)) </tt> which can be carried out using either a root
24  finder algorithm (typically Brent's method) or, alternatively, lookup
25  table together with cubic/linear (default) or bilinear interpolation.
26 
27  For the root-finder version, a 2D table (::Trhoe_tab) giving
28  <tt>T=T(rhoe,rho)</tt> is pre-computed in the function
29  MakeEV_TemperatureTable() and lookup table is used to narrow
30  down the root interval using the values stored inside this table.
31 
32  In the tabulated EOS version, a different table (::rhoe_tab)
33  <tt>rhoe=rhoe(T,rho)</tt> giving the internal energy at predefined values
34  of temperature and density is pre-calculated in the function
35  MakeInternalEnergyTable() so that internal energy and temperature can
36  be found by a combination of lookup table and bilinear (direct or inverse)
37  interpolation.
38 
39  \author A. Mignone (mignone@ph.unito.it)\n
40  B. Vaidya
41  \date 7 Jan, 2015
42 */
43 /* /////////////////////////////////////////////////////////////////// */
44 #include "pluto.h"
45 
46 #ifndef TV_ENERGY_TABLE_NX
47  #define TV_ENERGY_TABLE_NX 1024
48 #endif
49 #ifndef TV_ENERGY_TABLE_NY
50  #define TV_ENERGY_TABLE_NY 512
51 #endif
52 
53 static double rhoeFunc(double, void *);
54 static double InternalEnergyDeriv (double rho, double T);
55 
56 #if TV_ENERGY_TABLE == YES
57 static Table2D rhoe_tab; /**< A 2D table containing pre-computed values of
58  internal energy stored at equally spaced node
59  values of \c Log(T) and \c Log(rho) .*/
60 
61 /* ********************************************************************* */
63 /*!
64  * Compute a 2D table of the internal energy <tt>rhoe(T,rho)</tt> as
65  * function of temperature and density.
66  * The grid is equally spaced in <tt>log10(T) (=x)</tt> and
67  * <tt>log10(rho) (=y)</tt>.
68  * Values are stored in the static table ::rhoe_tab.
69  *
70  *********************************************************************** */
71 {
72  int i,j;
73  double x, y, q;
74  double T, rho, v[NVAR];
75 
76  print1 ("> MakeInternalEnergyTable(): Generating table (%d x %d points)\n",
78 
79  InitializeTable2D(&rhoe_tab, 1.0, 1.e8, TV_ENERGY_TABLE_NX,
80  1.e-6, 1.e6, TV_ENERGY_TABLE_NY);
81  for (j = 0; j < rhoe_tab.ny; j++){
82  for (i = 0; i < rhoe_tab.nx; i++){
83  T = rhoe_tab.x[i];
84  rho = rhoe_tab.y[j];
85  v[RHO] = rho;
86  rhoe_tab.f[j][i] = InternalEnergyFunc(v,T);
87  }}
88 
89  rhoe_tab.interpolation = SPLINE1;
90 
91 /* ----------------------------------------------------------------
92  Compute cubic spline coefficients
93  ---------------------------------------------------------------- */
94 
95  static double *dfdx;
96 
97  if (dfdx == NULL) dfdx = ARRAY_1D(TV_ENERGY_TABLE_NX, double);
98 
99  for (j = 0; j < rhoe_tab.ny; j++){
100  rho = rhoe_tab.y[j];
101  for (i = 0; i < rhoe_tab.nx; i++){
102  T = rhoe_tab.x[i];
103  dfdx[i] = InternalEnergyDeriv(rho, T);
104  }
105  if (rhoe_tab.interpolation == SPLINE1){
106  MonotoneSplineCoeffs(rhoe_tab.x, rhoe_tab.f[j], dfdx, rhoe_tab.nx,
107  rhoe_tab.a[j], rhoe_tab.b[j], rhoe_tab.c[j],
108  rhoe_tab.d[j]);
109  }else if (rhoe_tab.interpolation == SPLINE2){
110  SplineCoeffs(rhoe_tab.x, rhoe_tab.f[j],
111  dfdx[0], dfdx[rhoe_tab.nx-1], rhoe_tab.nx,
112  rhoe_tab.a[j], rhoe_tab.b[j], rhoe_tab.c[j], rhoe_tab.d[j]);
113  }
114  }
115 
116 /* let's plot the exact solutin and the spline using 20 points between
117  adjacent nodes */
118 #if 0
119 int ii;
120 double G, lnT, rhoe, rhoe_ex;
121 FILE *fp;
122 
123 j = TV_ENERGY_TABLE_NY/2;
124 
125 /* -- write exact internal energy, rhoe(T) -- */
126 
127 fp = fopen("rhoe.dat","w");
128 v[RHO] = rho = rhoe_tab.y[j];
129 for (i = 10; i < rhoe_tab.nx-11; i++){
130  for (ii = 0; ii < 20; ii++){ // Sub grid
131  T = rhoe_tab.x[i] + ii*rhoe_tab.dx[i]/20.0;
132  rhoe_ex = InternalEnergyFunc(v,T);
133  G = FundamentalDerivative(v,T);
134  Table2DInterpolate(&rhoe_tab, T, rho, &rhoe);
135  fprintf (fp, "%12.6e %12.6e %12.6e %12.6e\n",T,rhoe_ex, rhoe, G);
136  }
137 }
138 fclose(fp);
139 #endif
140 
141 
142  FinalizeTable2D(&rhoe_tab);
143  if (prank == 0) WriteBinaryTable2D("rhoe_tab.bin",&rhoe_tab);
144 }
145 
146 /* ********************************************************************* */
147 double InternalEnergyDeriv (double rho, double T)
148 /*!
149  * Compute derivative of internal energy using numerical
150  * differentiation
151  *
152  *********************************************************************** */
153 {
154  double Epp, Emm, Ep, Em, dEdT;
155  double dT = 1.e-3, v[256];
156 
157  v[RHO] = rho;
158  Epp = InternalEnergyFunc(v,T*(1.0 + 2.0*dT));
159  Ep = InternalEnergyFunc(v,T*(1.0 + 1.0*dT));
160  Em = InternalEnergyFunc(v,T*(1.0 - 1.0*dT));
161  Emm = InternalEnergyFunc(v,T*(1.0 - 2.0*dT));
162 
163  dEdT = (-Epp + 8.0*Ep - 8.0*Em + Emm)/(12.0*T*dT);
164  return dEdT;
165 }
166 
167 
168 #endif /* TV_ENERGY_TABLE == YES */
169 
170 #if NIONS == 0 && TV_ENERGY_TABLE == NO
171 static Table2D Trhoe_tab; /**< A 2D table containing pre-computed values of
172  temperature by inverting e=e(T,rho) at
173  equally spaced node values of
174  \c Log(rhoe) and \c Log(rho). This is used
175  only in conjunction with a root finder to
176  bracket the zero in a narrower interval. */
177 /* ********************************************************************* */
179 /*!
180  * Pre-calculate a 2D table of temperature <tt>T(rhoe,rho)</tt> by
181  * inverting, at specified values of \c p and \c rho, the nonlinear
182  * equation
183  * \f[
184  * f(T) = \rho e - \rho e(T,\rho) = 0
185  * \qquad\Longrightarrow\qquad
186  * T_{ij} = T(x_i, y_j) \qquad
187  * \left(x=\log_{10}\rho e\,,\quad y=\log_{10}\rho\right)
188  * \f]
189  * For convenience, the table is constructed using equally
190  * spaced bins of <tt>x=Log(rhoe)</tt> and \c y=Log(rho)
191  * where \c rhoe and \c rho are in code units.
192  * This function must be called only once to initialize the table
193  * \c ::Trhoe_tab which is private to this file only.
194  *
195  * This table is required only by the root-finder methods and it is
196  * useless for the tabulated version (default).
197  *
198  *********************************************************************** */
199 {
200  int i,j, status;
201  double rhoe, rho, Tlo, Thi, T;
202  struct func_param par;
203 
204  print1 ("> MakeEV_TemperatureTable(): Generating table...\n");
205 
206  InitializeTable2D(&Trhoe_tab, 1.e-9, 1.e9, 1200, 1.e-12, 1.e12, 1200);
207  Tlo = 1.0;
208  Thi = 1.e12;
209 
210  for (j = 0; j < Trhoe_tab.ny; j++){
211  for (i = 0; i < Trhoe_tab.nx; i++){
212 
213  par.rhoe = rhoe = Trhoe_tab.x[i];
214  par.v[RHO] = rho = Trhoe_tab.y[j];
215 
216 /* status = Ridder(rhoeFunc, &param, Tlo, Thi, -1, 1.0e-12, &T); */
217  status = Brent(rhoeFunc, &par, Tlo, Thi, -1, 1.e-12, &T);
218 
219  if (status != 0) T = -1.0;
220 
221  Trhoe_tab.f[j][i] = T;
222  }}
223 
224 
225 /* let's plot the exact solution and the fundamental derivative */
226 #if 0
227 int ii;
228 double G, lnT, v[256];
229 FILE *fp;
230 
231 /* -- write exact internal energy, rhoe(T) -- */
232 fp = fopen("rhoe.dat","w");
233 v[RHO] = rho = 1.245197084735e+00;
234 for (lnT = 2.0; lnT < 4.5; lnT += 1.e-3){
235  T = pow(10.0, lnT);
236  rhoe = InternalEnergyFunc(v,T);
237  G = FundamentalDerivative(v,T);
238  fprintf (fp,"%12.6e %12.6e %12.6e\n",T,rhoe,G);
239 }
240 fclose(fp);
241 #endif
242 
243 /* -------------------------------------------------------
244  Compute forward differences
245  ------------------------------------------------------- */
246 
247  FinalizeTable2D(&Trhoe_tab);
248  if (prank == 0) WriteBinaryTable2D("Trhoe_tab.bin",&Trhoe_tab);
249 }
250 #undef NRHO
251 #undef NRHOE
252 #endif /* NIONS == 0 && TV_ENERGY_TABLE == NO */
253 
254 /* ********************************************************************* */
255 double InternalEnergy(double *v, double T)
256 /*!
257  * Compute and return the gas internal energy as a function of
258  * temperature and density or fractions:
259  * <tt> rhoe = rhoe(T,rho) </tt> or <tt> rhoe = rhoe(T,X) </tt>.
260  *
261  * \param [in] v 1D Array of primitive variables containing
262  * density and species. Other variables are
263  * ignored.
264  * \param [in] T Gas temperature
265  *
266  * \return The gas internal energy (rhoe) in code units.
267  *********************************************************************** */
268 {
269 #if TV_ENERGY_TABLE == YES
270 
271  int status;
272  double rho, rhoe;
273 
274  rho = v[RHO];
275  status = Table2DInterpolate(&rhoe_tab, T, rho, &rhoe);
276  if (status != 0){
277  print ("! InternalEnergy(): table interpolation failure (bound exceeded)\n");
278  QUIT_PLUTO(1);
279  }
280  return rhoe;
281 
282 #else
283 
284  return InternalEnergyFunc (v,T);
285 
286 #endif /* TV_ENERGY_TABLE == NO */
287 }
288 
289 /* ********************************************************************* */
290 int GetEV_Temperature(double rhoe, double *v, double *T)
291 /*!
292  * Compute temperature from internal energy, density and fractions by
293  * solving either
294  * \f[
295  * \begin{array}{ll}
296  * \rho e - \rho e(T,\vec{X}) = 0 & \quad{(\rm with\; chemistry)}
297  * \\ \noalign{\medskip}
298  * \rho e - \rho e(T,\vec{X}(T,\rho)) = 0 & \quad{(\rm without\; chemistry)}
299  * \end{array}
300  * \f]
301  *
302  * The previous equations are solved using a root finder algorithm
303  * (default is Brent or Ridder) or by lookup table / interpolation methods.
304  *
305  * \param [in] rhoe Internal energy of gas in code units.
306  * \param [in] v 1D array of primitive variables (only density
307  * and species need to be set).
308  * \param [out] T Temperature in K
309  *
310  * \return 0 on success, 1 on failure.
311  *********************************************************************** */
312 {
313 #if TV_ENERGY_TABLE == YES
314  int status;
315  double rho;
316 
317  if (rhoe < 0.0) return 1;
318 
319  rho = v[RHO];
320  status = InverseLookupTable2D(&rhoe_tab, rho, rhoe, T);
321  if (status != 0){
322  WARNING(
323  print ("! GetEV_Temperature(): table interpolation failure");
324  print (" [rho = %12.6e, rhoe = %12.6e]\n",rho,rhoe);
325  )
326  return 1;
327  }
328 
329  if (*T < T_CUT_RHOE) return 1;
330  return 0;
331 #else
332 
333  int nv, status, i, j;
334  double Tmin, Tmax,rho, lnx, lny;
335  struct func_param param;
336 
337  if (rhoe < 0.0) return 1;
338 
339 /* ---------------------------------------------------
340  Constrain species to lie between [0,1]
341  --------------------------------------------------- */
342 
343 #if NIONS > 0
344  NIONS_LOOP(nv) {
345  v[nv] = MAX(v[nv],0.0);
346  v[nv] = MIN(v[nv],1.0);
347  }
348  #if COOLING == H2_COOL
349  v[X_H2] = MIN(v[X_H2], 0.5);
350  #endif
351 #endif
352 
353  param.v[RHO] = v[RHO]; /* maybe set param.v to point to v ?? */
354  param.rhoe = rhoe;
355  NSCL_LOOP(nv) param.v[nv] = v[nv];
356 
357  #if NIONS == 0 /* No chemistry */
358 
359  rho = v[RHO];
360  lnx = log10(rhoe);
361  lny = log10(rho);
362  i = INT_FLOOR((lnx - Trhoe_tab.lnxmin)*Trhoe_tab.dlnx_1);
363  j = INT_FLOOR((lny - Trhoe_tab.lnymin)*Trhoe_tab.dlny_1);
364 
365 /* ------------------------------------------------------------------
366  Since Trhoe_tab[j][i] increases with i but decrease with j,
367  the min and max between four adjacent node values are the two
368  opposite points of the secondary diagonal (i,j+1) and (i+1,j),
369  respectively.
370  ------------------------------------------------------------------ */
371 
372  Tmin = Trhoe_tab.f[j+1][i];
373  Tmax = Trhoe_tab.f[j][i+1];
374 
375  #else /* Chemistry */
376  InternalEnergyBracket(rhoe, v, &Tmin, &Tmax);
377  #endif
378 
379  if (Tmin < 0.0 || Tmax < 0.0) return 1;
380 
381 /* status = Ridder(rhoeFunc, &param, Tmin, Tmax,-1, 1.0e-7, &T); */
382  status = Brent(rhoeFunc, &param, Tmin, Tmax, -1, 1.e-7, T);
383 
384  if (*T < T_CUT_RHOE || status != 0) return 1;
385  return 0;
386 
387 #endif /* TV_ENERGY_TABLE == NO */
388 }
389 /* ********************************************************************* */
390 double rhoeFunc(double T, void *par)
391 /*!
392  * Return the nonlinear function <tt>f(T)=rhoe(T,rho)-rhoe </tt> used
393  * by the root finder to find temperature \c T.
394  *
395  * \param [in] T The temperature in Kelvin
396  * \param [in] par A pointer to a \c func_param structure
397  * containing quantities required for the computation.
398  * \return f(T)
399  *********************************************************************** */
400 {
401  double func, rhoe;
402  struct func_param *p = (struct func_param *) par;
403 
404  if (T < 0.0){
405  printf ("! rhoeFunc: T = %12.6e\n",T);
406  exit(1);
407  }
408  rhoe = InternalEnergyFunc(p->v, T);
409  func = rhoe - p->rhoe;
410  return func;
411 }
412 
413 /* ********************************************************************* */
414 void SoundSpeed2 (double **v, double *cs2, double *h, int beg, int end,
415  int pos, Grid *grid)
416 /*!
417  * Define the square of the sound speed.
418  *
419  * \param [in] v 1D array of primitive quantities
420  * \param [out] cs2 1D array containing the square of the sound speed
421  * \param [in] h 1D array of enthalpy values
422  * \param [in] beg initial index of computation
423  * \param [in] end final index of computation
424  * \param [in] pos an integer specifying the spatial position
425  * inside the cell (only for spatially-dependent EOS)
426  * \param [in] grid pointer to an array of Grid structures
427  *
428  * \return This function has no return value.
429  *********************************************************************** */
430 {
431  int i;
432 
433  for (i = beg; i <= end; i++){
434  cs2[i] = Gamma1(v[i])*v[i][PRS]/v[i][RHO];
435 /* cs2[i] = 1.6667*v[i][PRS]/v[i][RHO]; */
436  }
437 }
#define MAX(a, b)
Definition: macros.h:101
tuple T
Definition: Sph_disk.py:33
#define NIONS_LOOP(n)
Definition: pluto.h:614
#define NSCL_LOOP(n)
Definition: pluto.h:616
double * y
array of y-values (not uniform)
Definition: structs.h:181
#define SPLINE2
Definition: pluto.h:220
#define T_CUT_RHOE
Sets the lowest cut-off temperature used in the PVTE_LAW equation of state.
Definition: eos.h:69
double InternalEnergy(double *v, double T)
double FundamentalDerivative(double *v, double T)
void print1(const char *fmt,...)
Definition: amrPluto.cpp:511
#define SPLINE1
Definition: pluto.h:219
int nx
Number of columns or points in the x direction.
Definition: structs.h:174
#define RHO
Definition: mod_defs.h:19
#define WARNING(a)
Definition: macros.h:217
double rhoe
Definition: eos.h:107
double dlny_1
Definition: structs.h:205
double v[NVAR]
Definition: eos.h:106
double ** f
Definition: structs.h:186
#define TV_ENERGY_TABLE_NX
double ** a
Spline coefficient (x^3)
Definition: structs.h:188
double ** c
Spline coefficient (x)
Definition: structs.h:190
int prank
Processor rank.
Definition: globals.h:33
double ** b
Spline coefficient (x^2)
Definition: structs.h:189
void SplineCoeffs(double *x, double *f, double dfL, double dfR, int n, double *a, double *b, double *c, double *d)
Definition: math_interp.c:95
void WriteBinaryTable2D(char *fname, Table2D *tab)
Definition: math_table2D.c:528
#define MIN(a, b)
Definition: macros.h:104
int Brent(double(*Func)(double, void *), void *param, double x1, double x2, double abs_acc, double rel_acc, double *xroot)
double dlnx_1
Definition: structs.h:204
int InverseLookupTable2D(Table2D *tab, double y, double f, double *x)
Definition: math_table2D.c:196
int GetEV_Temperature(double rhoe, double *v, double *T)
#define INT_FLOOR(z)
Definition: macros.h:98
void MonotoneSplineCoeffs(double *x, double *y, double *dydx, int n, double *a, double *b, double *c, double *d)
Definition: math_interp.c:13
Definition: structs.h:78
static Table2D Trhoe_tab
A 2D table containing pre-computed values of temperature by inverting e=e(T,rho) at equally spaced no...
int j
Definition: analysis.c:2
static Table2D rhoe_tab
A 2D table containing pre-computed values of internal energy stored at equally spaced node values of ...
int ny
Number of rows or points in the y direction.
Definition: structs.h:175
int Table2DInterpolate(Table2D *tab, double x, double y, double *f)
Definition: math_table2D.c:430
static double rhoeFunc(double, void *)
void print(const char *fmt,...)
Definition: amrPluto.cpp:497
static double InternalEnergyDeriv(double rho, double T)
void MakeEV_TemperatureTable()
int interpolation
LINEAR/SPLINE1.
Definition: structs.h:177
double Gamma1(double *v)
Definition: pvte_law.c:231
PLUTO main header file.
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
void InitializeTable2D(Table2D *tab, double xmin, double xmax, int nx, double ymin, double ymax, int ny)
Definition: math_table2D.c:15
int i
Definition: analysis.c:2
void MakeInternalEnergyTable()
FILE * fp
Definition: analysis.c:7
void SoundSpeed2(double **v, double *cs2, double *h, int beg, int end, int pos, Grid *grid)
double lnxmin
lower limit (in log10) in the x-direction
Definition: structs.h:198
void FinalizeTable2D(Table2D *tab)
Definition: math_table2D.c:121
#define X_H2
Definition: cooling.h:30
double lnymin
lower limit (in log10) in the y-direction
Definition: structs.h:200
double ** d
Spline coefficiten (1)
Definition: structs.h:191
double * dx
grid spacing array in the x direction (not uniform)
Definition: structs.h:182
#define NVAR
Definition: pluto.h:609
#define TV_ENERGY_TABLE_NY
static Runtime q
#define QUIT_PLUTO(e_code)
Definition: macros.h:125
double * x
array of x-values (not uniform)
Definition: structs.h:180
double InternalEnergyFunc(double *v, double T)
Definition: pvte_law.c:47