33 double precision,
parameter :: LN10 = 2.302585092994046d0
57 character(len=8),
parameter :: quantity(6) = &
58 [character(8)::
'neOnH',
'Tfwd',
'pfwd',
'eintP',
'g1p',
'eintT']
59 character(len=3),
parameter :: deriv(4) = &
60 [character(3)::
'',
'_x',
'_y',
'_xy']
62 if (
mype == 0)
write(*,*) &
63 'EoS method: entropy (bicubic Hermite, 4-derivative corners, no closure)'
64 do iq = 1,
size(quantity)
65 do id = 1,
size(deriv)
77 call entropy_shift_prepare(
eos%neOnH, .false.)
78 call entropy_shift_prepare(
eos%neOnH_x, .false.)
79 call entropy_shift_prepare(
eos%neOnH_y, .false.)
80 call entropy_shift_prepare(
eos%neOnH_xy, .false.)
81 call entropy_shift_prepare(
eos%Tfwd, .false.)
82 call entropy_shift_prepare(
eos%Tfwd_x, .false.)
83 call entropy_shift_prepare(
eos%Tfwd_y, .false.)
84 call entropy_shift_prepare(
eos%Tfwd_xy, .false.)
85 call entropy_shift_prepare(
eos%pfwd, .false.)
86 call entropy_shift_prepare(
eos%pfwd_x, .false.)
87 call entropy_shift_prepare(
eos%pfwd_y, .false.)
88 call entropy_shift_prepare(
eos%pfwd_xy, .false.)
89 call entropy_shift_prepare(
eos%eintP, .false.)
90 call entropy_shift_prepare(
eos%eintP_x, .false.)
91 call entropy_shift_prepare(
eos%eintP_y, .false.)
92 call entropy_shift_prepare(
eos%eintP_xy, .false.)
93 call entropy_shift_prepare(
eos%g1p, .false.)
94 call entropy_shift_prepare(
eos%g1p_x, .false.)
95 call entropy_shift_prepare(
eos%g1p_y, .false.)
96 call entropy_shift_prepare(
eos%g1p_xy, .false.)
97 call entropy_shift_prepare(
eos%eintT, .true.)
98 call entropy_shift_prepare(
eos%eintT_x, .true.)
99 call entropy_shift_prepare(
eos%eintT_y, .true.)
100 call entropy_shift_prepare(
eos%eintT_xy, .true.)
105 eos%T%var2_min =
eos%Tfwd%var2_min
106 eos%T%var2_max =
eos%Tfwd%var2_max
107 eos%T%var1_min =
eos%Tfwd%var1_min
108 eos%T%var1_max =
eos%Tfwd%var1_max
109 if (
mype == 0)
write(*,
'(A)') &
110 ' EoS entropy: forward + inverse tables loaded; no aux builds.'
114 pure subroutine locate_idx_uniform(n, vmin, vmax, val, ix, t, h)
115 integer,
intent(in) :: n
116 double precision,
intent(in) :: vmin, vmax, val
117 integer,
intent(out) :: ix
118 double precision,
intent(out) :: t, h
119 h = (vmax - vmin) / dble(n - 1)
120 if (val <= vmin)
then
121 ix = 1; t = 0.0d0;
return
123 if (val >= vmax)
then
124 ix = n - 1; t = 1.0d0;
return
126 ix = 1 + int((val - vmin) / h)
128 if (ix > n - 1) ix = n - 1
129 t = (val - (vmin + (ix - 1) * h)) / h
130 if (t < 0.0d0) t = 0.0d0
131 if (t > 1.0d0) t = 1.0d0
132 end subroutine locate_idx_uniform
134 pure subroutine locate_idx_nodes(n, nodes, val, ix, t, h)
135 integer,
intent(in) :: n
136 double precision,
intent(in) :: nodes(n), val
137 integer,
intent(out) :: ix
138 double precision,
intent(out) :: t, h
139 integer :: lo, mid, hi
140 if (val <= nodes(1))
then
141 ix = 1; t = 0.0d0; h = nodes(2) - nodes(1);
return
143 if (val >= nodes(n))
then
144 ix = n - 1; t = 1.0d0; h = nodes(n) - nodes(n - 1);
return
149 if (hi - lo <= 1)
exit
151 if (nodes(mid) <= val)
then
158 h = nodes(ix + 1) - nodes(ix)
159 t = (val - nodes(ix)) / h
160 if (t < 0.0d0) t = 0.0d0
161 if (t > 1.0d0) t = 1.0d0
162 end subroutine locate_idx_nodes
164 pure subroutine locate_idx_axis1(tab, val, ix, t, h)
166 double precision,
intent(in) :: val
167 integer,
intent(out) :: ix
168 double precision,
intent(out) :: t, h
169 if (tab%is_uniform)
then
170 call locate_idx_uniform(tab%dim1, tab%var1_min, tab%var1_max, val, ix, t, h)
172 call locate_idx_nodes(tab%dim1, tab%var1_nodes, val, ix, t, h)
174 end subroutine locate_idx_axis1
176 pure subroutine locate_idx_axis2(tab, val, ix, t, h)
178 double precision,
intent(in) :: val
179 integer,
intent(out) :: ix
180 double precision,
intent(out) :: t, h
181 if (tab%is_uniform)
then
182 call locate_idx_uniform(tab%dim2, tab%var2_min, tab%var2_max, val, ix, t, h)
184 call locate_idx_nodes(tab%dim2, tab%var2_nodes, val, ix, t, h)
186 end subroutine locate_idx_axis2
191 pure subroutine cubic_basis(t, H0, H1, H2, H3)
192 double precision,
intent(in) :: t
193 double precision,
intent(out) :: h0, h1, h2, h3
194 double precision :: t2, t3
197 h0 = 2.0d0*t3 - 3.0d0*t2 + 1.0d0
198 h1 = t3 - 2.0d0*t2 + t
199 h2 = -2.0d0*t3 + 3.0d0*t2
201 end subroutine cubic_basis
210 pure subroutine bicubic_hermite_eval(f_t, fx_t, fy_t, fxy_t, x, y, val)
212 double precision,
intent(in) :: x, y
213 double precision,
intent(out) :: val
215 double precision :: tx, ty,
dx, dy
216 double precision :: h0x, h1x, h2x, h3x
217 double precision :: h0y, h1y, h2y, h3y
218 double precision :: f00, f10, f01, f11
219 double precision :: fx00, fx10, fx01, fx11
220 double precision :: fy00, fy10, fy01, fy11
221 double precision :: fxy00, fxy10, fxy01, fxy11
223 call locate_idx_axis1(f_t, x, ix, tx,
dx)
224 call locate_idx_axis2(f_t, y, iy, ty, dy)
226 call cubic_basis(tx, h0x, h1x, h2x, h3x)
227 call cubic_basis(ty, h0y, h1y, h2y, h3y)
229 f00 = f_t%table(ix, iy ); f10 = f_t%table(ix+1, iy )
230 f01 = f_t%table(ix, iy+1); f11 = f_t%table(ix+1, iy+1)
231 fx00 = fx_t%table(ix, iy ) *
dx
232 fx10 = fx_t%table(ix+1, iy ) *
dx
233 fx01 = fx_t%table(ix, iy+1) *
dx
234 fx11 = fx_t%table(ix+1, iy+1) *
dx
235 fy00 = fy_t%table(ix, iy ) * dy
236 fy10 = fy_t%table(ix+1, iy ) * dy
237 fy01 = fy_t%table(ix, iy+1) * dy
238 fy11 = fy_t%table(ix+1, iy+1) * dy
239 fxy00 = fxy_t%table(ix, iy ) *
dx * dy
240 fxy10 = fxy_t%table(ix+1, iy ) *
dx * dy
241 fxy01 = fxy_t%table(ix, iy+1) *
dx * dy
242 fxy11 = fxy_t%table(ix+1, iy+1) *
dx * dy
244 val = h0x*h0y*f00 + h2x*h0y*f10 + h0x*h2y*f01 + h2x*h2y*f11 &
245 + h1x*h0y*fx00 + h3x*h0y*fx10 + h1x*h2y*fx01 + h3x*h2y*fx11 &
246 + h0x*h1y*fy00 + h2x*h1y*fy10 + h0x*h3y*fy01 + h2x*h3y*fy11 &
247 + h1x*h1y*fxy00 + h3x*h1y*fxy10 + h1x*h3y*fxy01 + h3x*h3y*fxy11
248 end subroutine bicubic_hermite_eval
252 log_nH_code, log_e_nh_code) &
255 double precision,
intent(in) :: log_nh_code, log_e_nh_code
256 double precision :: t_cgs
257 call bicubic_hermite_eval(tfwd, tfwd_x, tfwd_y, tfwd_xy, &
258 log_nh_code, log_e_nh_code, t_cgs)
263 log_nH_code, log_e_nh_code) &
266 double precision,
intent(in) :: log_nh_code, log_e_nh_code
267 double precision :: p_cgs, nh_cgs
268 call bicubic_hermite_eval(pfwd, pfwd_x, pfwd_y, pfwd_xy, &
269 log_nh_code, log_e_nh_code, p_cgs)
277 neOnH_xy, log_nH_code, &
278 log_e_nh_code)
result(y)
280 double precision,
intent(in) :: log_nh_code, log_e_nh_code
281 call bicubic_hermite_eval(neonh, neonh_x, neonh_y, neonh_xy, &
282 log_nh_code, log_e_nh_code, y)
288 neOnH, neOnH_x, neOnH_y, neOnH_xy, &
289 log_nH_code, log_e_nh_code, &
299 double precision,
intent(in) :: log_nh_code, log_e_nh_code
300 double precision,
intent(out) :: t_code, y_out
301 double precision :: t_cgs
303 double precision :: tx, ty,
dx, dy
304 double precision :: h0x, h1x, h2x, h3x
305 double precision :: h0y, h1y, h2y, h3y
307 call locate_idx_axis1(tfwd, log_nh_code, ix, tx,
dx)
308 call locate_idx_axis2(tfwd, log_e_nh_code, iy, ty, dy)
309 call cubic_basis(tx, h0x, h1x, h2x, h3x)
310 call cubic_basis(ty, h0y, h1y, h2y, h3y)
312 t_cgs = contract_value(tfwd, tfwd_x, tfwd_y, tfwd_xy, ix, iy, &
313 dx, dy, h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y)
314 y_out = contract_value(neonh, neonh_x, neonh_y, neonh_xy, ix, iy, &
315 dx, dy, h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y)
322 pure double precision function contract_value(f_t, fx_t, fy_t, fxy_t, &
324 H0x, H1x, H2x, H3x, &
325 H0y, H1y, H2y, H3y)
result(val)
329 integer,
intent(in) :: ix, iy
330 double precision,
intent(in) ::
dx, dy
331 double precision,
intent(in) :: h0x, h1x, h2x, h3x
332 double precision,
intent(in) :: h0y, h1y, h2y, h3y
333 double precision :: f00, f10, f01, f11
334 double precision :: fx00, fx10, fx01, fx11
335 double precision :: fy00, fy10, fy01, fy11
336 double precision :: fxy00, fxy10, fxy01, fxy11
337 f00 = f_t%table(ix, iy ); f10 = f_t%table(ix+1, iy )
338 f01 = f_t%table(ix, iy+1); f11 = f_t%table(ix+1, iy+1)
339 fx00 = fx_t%table(ix, iy ) *
dx
340 fx10 = fx_t%table(ix+1, iy ) *
dx
341 fx01 = fx_t%table(ix, iy+1) *
dx
342 fx11 = fx_t%table(ix+1, iy+1) *
dx
343 fy00 = fy_t%table(ix, iy ) * dy
344 fy10 = fy_t%table(ix+1, iy ) * dy
345 fy01 = fy_t%table(ix, iy+1) * dy
346 fy11 = fy_t%table(ix+1, iy+1) * dy
347 fxy00 = fxy_t%table(ix, iy ) *
dx * dy
348 fxy10 = fxy_t%table(ix+1, iy ) *
dx * dy
349 fxy01 = fxy_t%table(ix, iy+1) *
dx * dy
350 fxy11 = fxy_t%table(ix+1, iy+1) *
dx * dy
351 val = h0x*h0y*f00 + h2x*h0y*f10 + h0x*h2y*f01 + h2x*h2y*f11 &
352 + h1x*h0y*fx00 + h3x*h0y*fx10 + h1x*h2y*fx01 + h3x*h2y*fx11 &
353 + h0x*h1y*fy00 + h2x*h1y*fy10 + h0x*h3y*fy01 + h2x*h3y*fy11 &
354 + h1x*h1y*fxy00 + h3x*h1y*fxy10 + h1x*h3y*fxy01 + h3x*h3y*fxy11
355 end function contract_value
364 log_nH_code, log_p_nH_code)
result(ratio)
370 double precision,
intent(in) :: log_nh_code, log_p_nh_code
371 double precision :: log_e_nh_cgs, log_e_nh_code
372 call bicubic_hermite_eval(eintp, eintp_x, eintp_y, eintp_xy, &
373 log_nh_code, log_p_nh_code, log_e_nh_cgs)
375 ratio = 10.0d0**(log_e_nh_code - log_p_nh_code)
384 eintP, eintP_x, eintP_y, eintP_xy, &
385 log_nH_code, log_p_nH_code, log_eint_nH_code)
388 double precision,
intent(in) :: log_nh_code, log_p_nh_code
389 double precision,
intent(out) :: log_eint_nh_code
390 double precision :: ratio, guess, lo, hi, mid, f_lo, f_hi, f_mid
391 double precision :: lim_lo, lim_hi
395 if (pfwd%is_uniform)
then
396 lim_lo = pfwd%var2_min
397 lim_hi = pfwd%var2_max
399 lim_lo = pfwd%var2_nodes(1)
400 lim_hi = pfwd%var2_nodes(pfwd%dim2)
405 log_nh_code, log_p_nh_code)
406 guess = dlog10(max(ratio, 1.0
d-300)) + log_p_nh_code
407 guess = max(lim_lo, min(lim_hi, guess))
410 lo = max(lim_lo, guess - 2.0
d-2)
411 hi = min(lim_hi, guess + 2.0
d-2)
413 log_nh_code, lo), 1.0
d-300)) - log_p_nh_code
415 log_nh_code, hi), 1.0
d-300)) - log_p_nh_code
417 if (f_lo*f_hi <= 0.0d0)
exit
418 lo = max(lim_lo, lo - 1.0
d-1)
419 hi = min(lim_hi, hi + 1.0
d-1)
421 log_nh_code, lo), 1.0
d-300)) - log_p_nh_code
423 log_nh_code, hi), 1.0
d-300)) - log_p_nh_code
424 if (lo <= lim_lo .and. hi >= lim_hi)
exit
428 if (f_lo*f_hi > 0.0d0)
then
429 log_eint_nh_code = guess
434 mid = 0.5d0*(lo + hi)
436 log_nh_code, mid), 1.0
d-300)) - log_p_nh_code
437 if (f_mid*f_lo <= 0.0d0)
then
438 hi = mid; f_hi = f_mid
440 lo = mid; f_lo = f_mid
442 if (hi - lo < 1.0
d-12)
exit
444 log_eint_nh_code = 0.5d0*(lo + hi)
449 log_nH_code, log_p_nH_code) &
452 double precision,
intent(in) :: log_nh_code, log_p_nh_code
453 call bicubic_hermite_eval(g1p, g1p_x, g1p_y, g1p_xy, &
454 log_nh_code, log_p_nh_code, g1)
460 log_nH_code, log_T_code) &
461 result(log_e_nh_code)
465 double precision,
intent(in) :: log_nh_code, log_t_code
466 double precision :: log_e_nh_cgs
467 call bicubic_hermite_eval(eintt, eintt_x, eintt_y, eintt_xy, &
468 log_nh_code, log_t_code, log_e_nh_cgs)
475 subroutine entropy_table_prepare(tc)
483 end subroutine entropy_table_prepare
486 subroutine entropy_shift_prepare(tc, axis2_is_T)
488 logical,
intent(in) :: axis2_is_t
494 call entropy_table_prepare(tc)
495 end subroutine entropy_shift_prepare
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
EoS state container – the single thermodynamic authority for AMRVAC.
type(eos_container), allocatable, public eos
The single EoS state object, allocated in eos_init and shared (read-mostly) across all EoS sub-module...
Interpolation kernels for the EoS tables (pure math; no EoS state).
subroutine, public precompute_step_inv(tc)
Entropy-method LTE EoS: every query is ONE bicubic Hermite evaluation.
double precision function, public entropy_eint_from_nh_t(eintt, eintt_x, eintt_y, eintt_xy, log_nh_code, log_t_code)
Inverse: log10(eint/nH) from (log nH, log T). Single bicubic Hermite eval of the eintT table.
pure double precision function, public entropy_p_nh_from_eint(pfwd, pfwd_x, pfwd_y, pfwd_xy, log_nh_code, log_e_nh_code)
subroutine, public entropy_eint_from_p_bisect(pfwd, pfwd_x, pfwd_y, pfwd_xy, eintp, eintp_x, eintp_y, eintp_xy, log_nh_code, log_p_nh_code, log_eint_nh_code)
Bisection inverse for the entropy table set: find log10(eint/nH) [code] such that p(nH,...
double precision function, public entropy_t_from_nh_eint(tfwd, tfwd_x, tfwd_y, tfwd_xy, log_nh_code, log_e_nh_code)
Public wrappers – code-unit out.
subroutine, public finalise_entropy_lte()
Entropy-method finalise: shift each loaded table's axes from CGS to code units and run the standard p...
double precision function, public entropy_gamma1_from_nh_p(g1p, g1p_x, g1p_y, g1p_xy, log_nh_code, log_p_nh_code)
Inverse: Gamma_1 from (log nH, log p/nH). Bicubic Hermite of g1p.
subroutine, public entropy_t_and_y_from_nh_eint(tfwd, tfwd_x, tfwd_y, tfwd_xy, neonh, neonh_x, neonh_y, neonh_xy, log_nh_code, log_e_nh_code, t_code, y_out)
Forward: T and y from (log nH, log eint/nH) – combined for the update_eos_LTE hot path that needs bot...
double precision function, public entropy_y_from_nh_eint(neonh, neonh_x, neonh_y, neonh_xy, log_nh_code, log_e_nh_code)
Forward: ne/nH from (log nH, log eint/nH). Single bicubic Hermite eval of the neOnH table.
double precision function, public entropy_eint_from_nh_p(eintp, eintp_x, eintp_y, eintp_xy, log_nh_code, log_p_nh_code)
Inverse: log10(eint/nH) from (log nH, log p/nH). Single bicubic Hermite eval of the eintP table....
subroutine, public load_entropy_lte()
Forward (log nH, log eint/nH) -> thermodynamic state.
Shared LTE lookup-table infrastructure (build/IO; not on the hot path).
subroutine, public eos_validate_table(tc, name)
Defensive consistency check for one table after init. Aborts with a diagnostic message if any silent-...
subroutine, public load_tables_lte(fieldname)
Read one named table file into its eos% container. The filename encodes the composition (H or HHe) an...
subroutine, public shift_axis_to_code(tc)
Shift a table's (log_nH, log_eint/nH) axes – and adaptive node arrays if present – from CGS storage t...
subroutine, public shift_axis_to_code_t(tc)
subroutine, public ensure_axis_nodes(tc)
Ensure tcvar1_nodes / tcvar2_nodes are allocated and populated so that build_*_table routines and oth...
subroutine, public eos_build_guards(tc)
Build guard (bucket) arrays so that adaptive index lookup is O(1). No-op for uniform tables....
subroutine, public precompute_fi_bypass_constants()
This module contains definitions of global parameters and variables and some generic functions/subrou...
double precision unit_numberdensity
Physical scaling factor for number density.
double precision unit_pressure
Physical scaling factor for pressure.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
double precision unit_temperature
Physical scaling factor for temperature.
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels