MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_eos_lte_entropy.t
Go to the documentation of this file.
1!=============================================================================
2!> Entropy-method LTE EoS: every query is ONE bicubic Hermite evaluation.
3!>
4!> Each quantity is stored as four tables -- the value plus its three
5!> derivatives (d/dx, d/dy, d2/dxdy) at every node -- which fully determine
6!> the bicubic Hermite polynomial in each cell: exact at nodes, O(h^4) inside,
7!> no closure. No Newton, bisection, or iteration on the hot path; the
8!> iterative work is done offline against the analytic Saha solver (see
9!> entropy128/generate_entropy_tables.py).
10!>
11!> Forward tables, axes (log10 nH, log10 eint/nH):
12!> Tfwd -> T pfwd -> p neOnH -> ne/nH
13!> Inverse tables:
14!> eintP (log nH, log p/nH) -> log10(eint/nH)
15!> eintT (log nH, log T) -> log10(eint/nH)
16!> g1p (log nH, log p/nH) -> Gamma_1
17!>
18!> Gamma_1 is tabulated directly (g1p) rather than recovered from second
19!> derivatives, so the lookup stays smooth; values are Maxwell-consistent with
20!> (p, T) by construction.
21!=============================================================================
24 use mod_comm_lib, only: mpistop
30 implicit none
31 private
32
33 double precision, parameter :: LN10 = 2.302585092994046d0
34
35 !> Unit conversions fixed at finalise: log10 of the code-to-CGS factor of
36 !> eint/nH (= p/nH), and 1/unit_pressure
37 double precision :: ent_shift_pe = 0.0d0, ent_inv_up = 1.0d0
38
39 !> Value and derivative tables of each quantity interleaved as
40 !> (f, fx, fy, fxy) per node, built at finalise; axes stay in eos%<quantity>
41 double precision, allocatable :: il_neOnH(:,:,:), il_Tfwd(:,:,:), il_pfwd(:,:,:)
42 double precision, allocatable :: il_eintP(:,:,:), il_g1p(:,:,:), il_eintT(:,:,:)
43
45
46 !> Forward (log nH, log eint/nH) -> thermodynamic state
51 !> Inverse (log nH, log p/nH) -> eint/p ratio, Gamma_1
55 !> Inverse (log nH, log T) -> log10(eint/nH)
57
58contains
59
60 !> Entropy-method load: six quantities, each a value table plus its three
61 !> derivative tables, on the forward (nH, eint/nH), inverse-p (nH, p/nH) and
62 !> inverse-T (nH, T) grids. Every runtime query is one bicubic-Hermite
63 !> evaluation (see generate_entropy_tables.py).
64 subroutine load_entropy_lte()
65 integer :: iq, id
66 character(len=8), parameter :: quantity(6) = &
67 [character(8):: 'neOnH', 'Tfwd', 'pfwd', 'eintP', 'g1p', 'eintT']
68 character(len=3), parameter :: deriv(4) = &
69 [character(3):: '', '_x', '_y', '_xy']
70
71 if (mype == 0) write(*,*) &
72 'EoS method: entropy (bicubic Hermite, 4-derivative corners, no closure)'
73 do iq = 1, size(quantity)
74 do id = 1, size(deriv)
75 call load_tables_lte(trim(quantity(iq))//trim(deriv(id)))
76 end do
77 end do
78 end subroutine load_entropy_lte
79
80 !> Entropy-method finalise: shift each loaded table's axes from CGS to code
81 !> units and run the standard prepare. No aux builds -- every runtime quantity
82 !> is a single Hermite lookup. neOnH/Tfwd/pfwd/eintP/g1p are on (log nH,
83 !> log eint/nH) (axis2_is_T=.false.); eintT is on (log nH, log T)
84 !> (axis2_is_T=.true.). Each quantity ships value + three derivative tables.
86 call entropy_shift_prepare(eos%neOnH, .false.)
87 call entropy_shift_prepare(eos%neOnH_x, .false.)
88 call entropy_shift_prepare(eos%neOnH_y, .false.)
89 call entropy_shift_prepare(eos%neOnH_xy, .false.)
90 call entropy_shift_prepare(eos%Tfwd, .false.)
91 call entropy_shift_prepare(eos%Tfwd_x, .false.)
92 call entropy_shift_prepare(eos%Tfwd_y, .false.)
93 call entropy_shift_prepare(eos%Tfwd_xy, .false.)
94 call entropy_shift_prepare(eos%pfwd, .false.)
95 call entropy_shift_prepare(eos%pfwd_x, .false.)
96 call entropy_shift_prepare(eos%pfwd_y, .false.)
97 call entropy_shift_prepare(eos%pfwd_xy, .false.)
98 call entropy_shift_prepare(eos%eintP, .false.)
99 call entropy_shift_prepare(eos%eintP_x, .false.)
100 call entropy_shift_prepare(eos%eintP_y, .false.)
101 call entropy_shift_prepare(eos%eintP_xy, .false.)
102 call entropy_shift_prepare(eos%g1p, .false.)
103 call entropy_shift_prepare(eos%g1p_x, .false.)
104 call entropy_shift_prepare(eos%g1p_y, .false.)
105 call entropy_shift_prepare(eos%g1p_xy, .false.)
106 call entropy_shift_prepare(eos%eintT, .true.)
107 call entropy_shift_prepare(eos%eintT_x, .true.)
108 call entropy_shift_prepare(eos%eintT_y, .true.)
109 call entropy_shift_prepare(eos%eintT_xy, .true.)
111 ent_shift_pe = dlog10(unit_pressure / unit_numberdensity)
112 ent_inv_up = 1.0d0 / unit_pressure
113 call interleave(eos%neOnH, eos%neOnH_x, eos%neOnH_y, eos%neOnH_xy, il_neonh)
114 call interleave(eos%Tfwd, eos%Tfwd_x, eos%Tfwd_y, eos%Tfwd_xy, il_tfwd)
115 call interleave(eos%pfwd, eos%pfwd_x, eos%pfwd_y, eos%pfwd_xy, il_pfwd)
116 call interleave(eos%eintP, eos%eintP_x, eos%eintP_y, eos%eintP_xy, il_eintp)
117 call interleave(eos%g1p, eos%g1p_x, eos%g1p_y, eos%g1p_xy, il_g1p)
118 call interleave(eos%eintT, eos%eintT_x, eos%eintT_y, eos%eintT_xy, il_eintt)
119 !> The entropy method never loads eos%T, but several callers read
120 !> eos%T%var{1,2}_{min,max} (the cold-cell eint floor, FI-fallback
121 !> checks). Source them from eos%Tfwd, on the same forward grid.
122 eos%T%var2_min = eos%Tfwd%var2_min
123 eos%eint_nH_min = 10.0d0**eos%T%var2_min
124 eos%T%var2_max = eos%Tfwd%var2_max
125 eos%T%var1_min = eos%Tfwd%var1_min
126 eos%T%var1_max = eos%Tfwd%var1_max
127 if (mype == 0) write(*,'(A)') &
128 ' EoS entropy: forward + inverse tables loaded; no aux builds.'
129 end subroutine finalise_entropy_lte
130
131 !> Index location: uniform and non-uniform variants.
132 pure subroutine locate_idx_uniform(n, vmin, vmax, val, ix, t, h)
133 integer, intent(in) :: n
134 double precision, intent(in) :: vmin, vmax, val
135 integer, intent(out) :: ix
136 double precision, intent(out) :: t, h
137 h = (vmax - vmin) / dble(n - 1)
138 if (val <= vmin) then
139 ix = 1; t = 0.0d0; return
140 end if
141 if (val >= vmax) then
142 ix = n - 1; t = 1.0d0; return
143 end if
144 ix = 1 + int((val - vmin) / h)
145 if (ix < 1) ix = 1
146 if (ix > n - 1) ix = n - 1
147 t = (val - (vmin + (ix - 1) * h)) / h
148 if (t < 0.0d0) t = 0.0d0
149 if (t > 1.0d0) t = 1.0d0
150 end subroutine locate_idx_uniform
151
152 pure subroutine locate_idx_nodes(n, nodes, val, ix, t, h)
153 integer, intent(in) :: n
154 double precision, intent(in) :: nodes(n), val
155 integer, intent(out) :: ix
156 double precision, intent(out) :: t, h
157 integer :: lo, mid, hi
158 if (val <= nodes(1)) then
159 ix = 1; t = 0.0d0; h = nodes(2) - nodes(1); return
160 end if
161 if (val >= nodes(n)) then
162 ix = n - 1; t = 1.0d0; h = nodes(n) - nodes(n - 1); return
163 end if
164 ! Binary search for cell containing val.
165 lo = 1; hi = n
166 do
167 if (hi - lo <= 1) exit
168 mid = (lo + hi) / 2
169 if (nodes(mid) <= val) then
170 lo = mid
171 else
172 hi = mid
173 end if
174 end do
175 ix = lo
176 h = nodes(ix + 1) - nodes(ix)
177 t = (val - nodes(ix)) / h
178 if (t < 0.0d0) t = 0.0d0
179 if (t > 1.0d0) t = 1.0d0
180 end subroutine locate_idx_nodes
181
182 !> The bracket of locate_idx_nodes (largest node index lo <= n-1 with
183 !> nodes(lo) <= val) in O(1) from the guard buckets: guard(k) is the first node
184 !> at or above the start of bucket k, corrected forward to the first node
185 !> >= val and back across a bucket edge that rounding put above val
186 pure subroutine locate_idx_guard(n, nodes, guard, M, scale, val, ix, t, h)
187 integer, intent(in) :: n, m
188 double precision, intent(in) :: nodes(n), scale, val
189 integer, intent(in) :: guard(m)
190 integer, intent(out) :: ix
191 double precision, intent(out) :: t, h
192 integer :: k, j
193 if (val <= nodes(1)) then
194 ix = 1; t = 0.0d0; h = nodes(2) - nodes(1); return
195 end if
196 if (val >= nodes(n)) then
197 ix = n - 1; t = 1.0d0; h = nodes(n) - nodes(n - 1); return
198 end if
199 k = 1 + min(m-1, max(0, int((val - nodes(1)) * scale)))
200 j = guard(k)
201 do while (j < n .and. nodes(j) < val)
202 j = j + 1
203 end do
204 do while (j > 1 .and. nodes(j-1) >= val)
205 j = j - 1
206 end do
207 if (nodes(j) > val) j = j - 1
208 ix = min(max(j, 1), n - 1)
209 h = nodes(ix + 1) - nodes(ix)
210 t = (val - nodes(ix)) / h
211 if (t < 0.0d0) t = 0.0d0
212 if (t > 1.0d0) t = 1.0d0
213 end subroutine locate_idx_guard
214
215 pure subroutine locate_idx_axis1(tab, val, ix, t, h)
216 type(eos_table_container), intent(in) :: tab
217 double precision, intent(in) :: val
218 integer, intent(out) :: ix
219 double precision, intent(out) :: t, h
220 if (tab%is_uniform) then
221 call locate_idx_uniform(tab%dim1, tab%var1_min, tab%var1_max, val, ix, t, h)
222 else if (tab%guard_M_1 > 0) then
223 call locate_idx_guard(tab%dim1, tab%var1_nodes, tab%guard_1, tab%guard_M_1, &
224 tab%guard_scale_1, val, ix, t, h)
225 else
226 call locate_idx_nodes(tab%dim1, tab%var1_nodes, val, ix, t, h)
227 end if
228 end subroutine locate_idx_axis1
229
230 pure subroutine locate_idx_axis2(tab, val, ix, t, h)
231 type(eos_table_container), intent(in) :: tab
232 double precision, intent(in) :: val
233 integer, intent(out) :: ix
234 double precision, intent(out) :: t, h
235 if (tab%is_uniform) then
236 call locate_idx_uniform(tab%dim2, tab%var2_min, tab%var2_max, val, ix, t, h)
237 else if (tab%guard_M_2 > 0) then
238 call locate_idx_guard(tab%dim2, tab%var2_nodes, tab%guard_2, tab%guard_M_2, &
239 tab%guard_scale_2, val, ix, t, h)
240 else
241 call locate_idx_nodes(tab%dim2, tab%var2_nodes, val, ix, t, h)
242 end if
243 end subroutine locate_idx_axis2
244
245 !> 1D cubic Hermite basis on t in [0, 1] (value weights).
246 !> H0 = 2t^3 - 3t^2 + 1 value at t=0 H2 = -2t^3 + 3t^2 value at t=1
247 !> H1 = t^3 - 2t^2 + t slope at t=0 H3 = t^3 - t^2 slope at t=1
248 pure subroutine cubic_basis(t, H0, H1, H2, H3)
249 double precision, intent(in) :: t
250 double precision, intent(out) :: h0, h1, h2, h3
251 double precision :: t2, t3
252 t2 = t * t
253 t3 = t2 * t
254 h0 = 2.0d0*t3 - 3.0d0*t2 + 1.0d0
255 h1 = t3 - 2.0d0*t2 + t
256 h2 = -2.0d0*t3 + 3.0d0*t2
257 h3 = t3 - t2
258 end subroutine cubic_basis
259
260 !> Bicubic Hermite contraction at a located cell. c(1:4,i,j) holds
261 !> (f, df/dx, df/dy, d2f/dxdy) at node (i,j); the derivatives are physical-axis
262 !> derivatives, scaled by the local cell widths to unit-interval coordinates.
263 !> 4 stored values x 4 corners = 16 conditions, which fully determine the
264 !> degree-(3,3) polynomial in the cell
265 pure double precision function contract_il(c, ix, iy, dx, dy, &
266 H0x, H1x, H2x, H3x, &
267 H0y, H1y, H2y, H3y) result(val)
268 double precision, intent(in) :: c(:,:,:)
269 integer, intent(in) :: ix, iy
270 double precision, intent(in) :: dx, dy
271 double precision, intent(in) :: h0x, h1x, h2x, h3x
272 double precision, intent(in) :: h0y, h1y, h2y, h3y
273 double precision :: f00, f10, f01, f11
274 double precision :: fx00, fx10, fx01, fx11
275 double precision :: fy00, fy10, fy01, fy11
276 double precision :: fxy00, fxy10, fxy01, fxy11
277 f00 = c(1,ix, iy ); f10 = c(1,ix+1,iy )
278 f01 = c(1,ix, iy+1); f11 = c(1,ix+1,iy+1)
279 fx00 = c(2,ix, iy ) * dx
280 fx10 = c(2,ix+1,iy ) * dx
281 fx01 = c(2,ix, iy+1) * dx
282 fx11 = c(2,ix+1,iy+1) * dx
283 fy00 = c(3,ix, iy ) * dy
284 fy10 = c(3,ix+1,iy ) * dy
285 fy01 = c(3,ix, iy+1) * dy
286 fy11 = c(3,ix+1,iy+1) * dy
287 fxy00 = c(4,ix, iy ) * dx * dy
288 fxy10 = c(4,ix+1,iy ) * dx * dy
289 fxy01 = c(4,ix, iy+1) * dx * dy
290 fxy11 = c(4,ix+1,iy+1) * dx * dy
291 val = h0x*h0y*f00 + h2x*h0y*f10 + h0x*h2y*f01 + h2x*h2y*f11 &
292 + h1x*h0y*fx00 + h3x*h0y*fx10 + h1x*h2y*fx01 + h3x*h2y*fx11 &
293 + h0x*h1y*fy00 + h2x*h1y*fy10 + h0x*h3y*fy01 + h2x*h3y*fy11 &
294 + h1x*h1y*fxy00 + h3x*h1y*fxy10 + h1x*h3y*fxy01 + h3x*h3y*fxy11
295 end function contract_il
296
297 !> One bicubic Hermite evaluation of quantity c on the axes of container ax
298 pure double precision function hermite_eval(ax, c, x, y) result(val)
299 type(eos_table_container), intent(in) :: ax
300 double precision, intent(in) :: c(:,:,:)
301 double precision, intent(in) :: x, y
302 integer :: ix, iy
303 double precision :: tx, ty, dx, dy
304 double precision :: h0x, h1x, h2x, h3x
305 double precision :: h0y, h1y, h2y, h3y
306 call locate_idx_axis1(ax, x, ix, tx, dx)
307 call locate_idx_axis2(ax, y, iy, ty, dy)
308 call cubic_basis(tx, h0x, h1x, h2x, h3x)
309 call cubic_basis(ty, h0y, h1y, h2y, h3y)
310 val = contract_il(c, ix, iy, dx, dy, h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y)
311 end function hermite_eval
312
313 !> Interleave a quantity's value and three derivative tables node by node,
314 !> so the two corners of a cell row share one cache line
315 subroutine interleave(f_t, fx_t, fy_t, fxy_t, c)
316 type(eos_table_container), intent(in) :: f_t, fx_t, fy_t, fxy_t
317 double precision, allocatable, intent(out) :: c(:,:,:)
318 allocate(c(4, size(f_t%table,1), size(f_t%table,2)))
319 c(1,:,:) = f_t%table
320 c(2,:,:) = fx_t%table
321 c(3,:,:) = fy_t%table
322 c(4,:,:) = fxy_t%table
323 end subroutine interleave
324
325 !> Public lookups, code units in and out. Forward tables are on
326 !> (log nH, log eint/nH), eintP and g1p on (log nH, log p/nH), eintT on
327 !> (log nH, log T)
328 double precision function entropy_t_from_nh_eint(log_nH_code, log_e_nh_code) result(T_code)
329 double precision, intent(in) :: log_nh_code, log_e_nh_code
330 t_code = hermite_eval(eos%Tfwd, il_tfwd, log_nh_code, log_e_nh_code) / unit_temperature
331 end function entropy_t_from_nh_eint
332
333 pure double precision function entropy_p_nh_from_eint(log_nH_code, log_e_nh_code) result(p_nH_code)
334 double precision, intent(in) :: log_nh_code, log_e_nh_code
335 p_nh_code = hermite_eval(eos%pfwd, il_pfwd, log_nh_code, log_e_nh_code) &
336 * ent_inv_up / 10.0d0**log_nh_code
337 end function entropy_p_nh_from_eint
338
339 !> Pressure in code units from (log nH, log eint/nH); the pfwd table holds p itself
340 pure double precision function entropy_p_from_eint(log_nH_code, log_e_nh_code) result(p_code)
341 double precision, intent(in) :: log_nh_code, log_e_nh_code
342 p_code = hermite_eval(eos%pfwd, il_pfwd, log_nh_code, log_e_nh_code) * ent_inv_up
343 end function entropy_p_from_eint
344
345 double precision function entropy_y_from_nh_eint(log_nH_code, log_e_nh_code) result(y)
346 double precision, intent(in) :: log_nh_code, log_e_nh_code
347 y = hermite_eval(eos%neOnH, il_neonh, log_nh_code, log_e_nh_code)
348 end function entropy_y_from_nh_eint
349
350 !> T and ne/nH at one point: Tfwd and neOnH share the forward grid, so the
351 !> cell location and the basis are computed once
352 subroutine entropy_t_and_y_from_nh_eint(log_nH_code, log_e_nh_code, T_code, y_out)
353 double precision, intent(in) :: log_nh_code, log_e_nh_code
354 double precision, intent(out) :: t_code, y_out
355 integer :: ix, iy
356 double precision :: tx, ty, dx, dy
357 double precision :: h0x, h1x, h2x, h3x
358 double precision :: h0y, h1y, h2y, h3y
359 call locate_idx_axis1(eos%Tfwd, log_nh_code, ix, tx, dx)
360 call locate_idx_axis2(eos%Tfwd, log_e_nh_code, iy, ty, dy)
361 call cubic_basis(tx, h0x, h1x, h2x, h3x)
362 call cubic_basis(ty, h0y, h1y, h2y, h3y)
363 t_code = contract_il(il_tfwd, ix, iy, dx, dy, h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y) &
365 y_out = contract_il(il_neonh, ix, iy, dx, dy, h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y)
366 end subroutine entropy_t_and_y_from_nh_eint
367
368 !> eint/p in code units from (log nH, log p/nH). The table holds
369 !> log10(eint/nH) in CGS
370 double precision function entropy_eint_from_nh_p(log_nH_code, log_p_nH_code) result(ratio)
371 double precision, intent(in) :: log_nh_code, log_p_nh_code
372 double precision :: log_e_nh_code
373 log_e_nh_code = hermite_eval(eos%eintP, il_eintp, log_nh_code, log_p_nh_code) - ent_shift_pe
374 ratio = 10.0d0**(log_e_nh_code - log_p_nh_code)
375 end function entropy_eint_from_nh_p
376
377 !> Bisection inverse: log10(eint/nH) [code] such that the forward pressure
378 !> matches p exactly; the eintP table only supplies the initial guess
379 subroutine entropy_eint_from_p_bisect(log_nH_code, log_p_nH_code, log_eint_nH_code)
380 double precision, intent(in) :: log_nh_code, log_p_nh_code
381 double precision, intent(out) :: log_eint_nh_code
382 double precision :: ratio, guess, lo, hi, mid, f_lo, f_hi, f_mid
383 double precision :: lim_lo, lim_hi, log_p_code
384 integer :: iter
385
386 ! eint-axis limits of the forward table, uniform or adaptive
387 if (eos%pfwd%is_uniform) then
388 lim_lo = eos%pfwd%var2_min
389 lim_hi = eos%pfwd%var2_max
390 else
391 lim_lo = eos%pfwd%var2_nodes(1)
392 lim_hi = eos%pfwd%var2_nodes(eos%pfwd%dim2)
393 end if
394
395 ratio = entropy_eint_from_nh_p(log_nh_code, log_p_nh_code)
396 guess = dlog10(max(ratio, 1.0d-300)) + log_p_nh_code
397 guess = max(lim_lo, min(lim_hi, guess))
398
399 ! Bracket, expanding until the target is straddled
400 log_p_code = log_nh_code + log_p_nh_code
401 lo = max(lim_lo, guess - 2.0d-2)
402 hi = min(lim_hi, guess + 2.0d-2)
403 f_lo = resid(lo)
404 f_hi = resid(hi)
405 do iter = 1, 12
406 if (f_lo*f_hi <= 0.0d0) exit
407 lo = max(lim_lo, lo - 1.0d-1)
408 hi = min(lim_hi, hi + 1.0d-1)
409 f_lo = resid(lo)
410 f_hi = resid(hi)
411 if (lo <= lim_lo .and. hi >= lim_hi) exit
412 end do
413
414 ! No bracket, the target lies outside the table, so the table guess stands
415 if (f_lo*f_hi > 0.0d0) then
416 log_eint_nh_code = guess
417 return
418 end if
419
420 do iter = 1, 40
421 mid = 0.5d0*(lo + hi)
422 f_mid = resid(mid)
423 if (f_mid*f_lo <= 0.0d0) then
424 hi = mid; f_hi = f_mid
425 else
426 lo = mid; f_lo = f_mid
427 end if
428 if (hi - lo < 1.0d-12) exit
429 end do
430 log_eint_nh_code = 0.5d0*(lo + hi)
431
432 contains
433
434 !> Residual in log10 p of the forward table at log10(eint/nH) = x
435 double precision function resid(x)
436 double precision, intent(in) :: x
437 resid = dlog10(max(entropy_p_from_eint(log_nh_code, x), 1.0d-300)) - log_p_code
438 end function resid
439
440 end subroutine entropy_eint_from_p_bisect
441
442 double precision function entropy_gamma1_from_nh_p(log_nH_code, log_p_nH_code) result(g1)
443 double precision, intent(in) :: log_nh_code, log_p_nh_code
444 g1 = hermite_eval(eos%g1p, il_g1p, log_nh_code, log_p_nh_code)
445 end function entropy_gamma1_from_nh_p
446
447 !> log10(eint/nH) in code units from (log nH, log T); the table holds it in CGS
448 double precision function entropy_eint_from_nh_t(log_nH_code, log_T_code) result(log_e_nh_code)
449 double precision, intent(in) :: log_nh_code, log_t_code
450 log_e_nh_code = hermite_eval(eos%eintT, il_eintt, log_nh_code, log_t_code) - ent_shift_pe
451 end function entropy_eint_from_nh_t
452
453
454 !> Per-container code-unit shift + prepare for loaded entropy tables
455 !> (moved from mod_eos_lte_tables; uses the shared infra there).
456 subroutine entropy_table_prepare(tc)
457 !> Bundle ensure_axis_nodes + precompute_step_inv + build_guards + validate,
458 !> the identical four-step setup each loaded entropy table container needs.
459 type(eos_table_container), intent(inout) :: tc
460 call ensure_axis_nodes(tc)
461 call precompute_step_inv(tc)
462 call eos_build_guards(tc)
463 call eos_validate_table(tc, trim(tc%filename))
464 end subroutine entropy_table_prepare
465
466
467 subroutine entropy_shift_prepare(tc, axis2_is_T)
468 type(eos_table_container), intent(inout) :: tc
469 logical, intent(in) :: axis2_is_t
470 if (axis2_is_t) then
471 call shift_axis_to_code_t(tc)
472 else
473 call shift_axis_to_code(tc)
474 end if
475 call entropy_table_prepare(tc)
476 end subroutine entropy_shift_prepare
477
478end module mod_eos_lte_entropy
479!> Needs a line after to pass the preprocessor
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.
pure double precision function, public entropy_p_from_eint(log_nh_code, log_e_nh_code)
Pressure in code units from (log nH, log eint/nH); the pfwd table holds p itself.
double precision function, public entropy_t_from_nh_eint(log_nh_code, log_e_nh_code)
Public lookups, code units in and out. Forward tables are on (log nH, log eint/nH),...
double precision function, public entropy_y_from_nh_eint(log_nh_code, log_e_nh_code)
double precision function, public entropy_eint_from_nh_t(log_nh_code, log_t_code)
log10(eint/nH) in code units from (log nH, log T); the table holds it in CGS
double precision function, public entropy_eint_from_nh_p(log_nh_code, log_p_nh_code)
eint/p in code units from (log nH, log p/nH). The table holds log10(eint/nH) in CGS
subroutine, public finalise_entropy_lte()
Entropy-method finalise: shift each loaded table's axes from CGS to code units and run the standard p...
pure double precision function, public entropy_p_nh_from_eint(log_nh_code, log_e_nh_code)
double precision function, public entropy_gamma1_from_nh_p(log_nh_code, log_p_nh_code)
subroutine, public entropy_t_and_y_from_nh_eint(log_nh_code, log_e_nh_code, t_code, y_out)
T and ne/nH at one point: Tfwd and neOnH share the forward grid, so the cell location and the basis a...
subroutine, public load_entropy_lte()
Forward (log nH, log eint/nH) -> thermodynamic state.
subroutine, public entropy_eint_from_p_bisect(log_nh_code, log_p_nh_code, log_eint_nh_code)
Bisection inverse: log10(eint/nH) [code] such that the forward pressure matches p exactly; the eintP ...
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 precompute_fi_bypass_constants(chi_h_only)
Precompute constants for bypassing table lookups when gas is fully ionised. Physics: above T ~ 50 kK,...
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....
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