MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_eos_container.t
Go to the documentation of this file.
1!=============================================================================
2!> EoS state container -- the single thermodynamic authority for AMRVAC.
3!>
4!> Defines the eos_container derived type: its scalar fields (gamma, He_abundance,
5!> eos_type, method_id, ionE, the unit-normalisation factors) and its
6!> procedure-pointer slots -- to_conserved/to_primitive, p_to_e,
7!> get_thermal_pressure, get_csound2, get_Rfactor, get_temperature_from_{eint,
8!> etot,pressure}, get_Te, get_ne_nH, get_rho/get_nH, update_eos -- which ARE the
9!> EoS public API the physics modules call. Also defines eos_table_container (one
10!> lookup table + its axes/guards) and the global `eos` instance plus the
11!> cached-log10(nH) wextra index iw_log_nH.
12!>
13!> Pure declarations -- no logic. The routines bound to these pointers live in
14!> the EoS sub-modules (mod_eos*) and the physics seams (mod_(m)hd_eos).
15!=============================================================================
18 implicit none
19 private
20
22
23 !> LTE method selector, decoded once from eos%method into eos%method_id so
24 !> the runtime kernels dispatch on an integer rather than a string compare.
25 integer, parameter, public :: eos_state = 1, eos_analytic = 2, eos_entropy = 3
26
27 !> EoS-type selector, decoded once from eos%eos_type into eos%type_id. Used by
28 !> the mode-specific kernels to mpistop if called under the wrong eos_type
29 !> (e.g. an LTE table kernel invoked while running FI or PI).
30 integer, parameter, public :: eos_type_fi = 1, eos_type_lte = 2, eos_type_pi = 3
31
32 abstract interface
33 subroutine convert_condition(ixI^L, ixO^L, w, x)
35 integer, intent(in) :: ixi^l, ixo^l
36 double precision, intent(inout) :: w(ixi^s, nw)
37 double precision, intent(in) :: x(ixi^s, 1:ndim)
38 end subroutine convert_condition
39
40 subroutine update_eos_spaces(ixI^L, ixO^L, w, x)
42 integer, intent(in) :: ixi^l, ixo^l
43 double precision, intent(inout) :: w(ixi^s, nw)
44 double precision, intent(in) :: x(ixi^s, 1:ndim)
45 end subroutine update_eos_spaces
46
47 subroutine get_eos_variable(ixI^L, ixO^L, w, x, res)
49 integer, intent(in) :: ixi^l, ixo^l
50 double precision, intent(in) :: w(ixi^s, nw)
51 double precision, intent(in) :: x(ixi^s, 1:ndim)
52 double precision, intent(out) :: res(ixi^s)
53 end subroutine get_eos_variable
54
55 subroutine get_eos_variable_alt(w, x, ixI^L, ixO^L, res)
57 integer, intent(in) :: ixi^l, ixo^l
58 double precision, intent(in) :: w(ixi^s, nw)
59 double precision, intent(in) :: x(ixi^s, 1:ndim)
60 double precision, intent(out) :: res(ixi^s)
61 end subroutine get_eos_variable_alt
62
63 subroutine get_ne_nh_iface(ixI^L, ixO^L, w, x, ne, nH)
65 integer, intent(in) :: ixi^l, ixo^l
66 double precision, intent(in) :: w(ixi^s, nw)
67 double precision, intent(in) :: x(ixi^s, 1:ndim)
68 double precision, intent(out) :: ne(ixi^s), nh(ixi^s)
69 end subroutine get_ne_nh_iface
70 end interface
71
73
74 character(len=std_len) :: filename
75 double precision, allocatable :: table(:,:)
76 integer :: dim1, dim2
77 double precision :: var1_min, var1_max, var2_min, var2_max
78 double precision :: step_inv_1, step_inv_2 !> precomputed (dim-1)/(max-min) for each axis
79
80 !> Curvature-adaptive (non-uniform) grid support.
81 !> When .true. (default), the grid is uniform in log10 space and
82 !> the existing affine index calculation applies. When .false.,
83 !> the table file carries an explicit pair of axis node arrays
84 !> read from the binary trailer; index lookup uses binary search
85 !> and the local fractional coordinate becomes
86 !> t1 = (var1 - var1_nodes(i)) / (var1_nodes(i+1) - var1_nodes(i))
87 !> The PCHIP/bicubic kernels themselves are unchanged.
88 !>
89 !> Naming follows the existing var1/var2 convention:
90 !> var1_nodes has length dim1, var2_nodes has length dim2.
91 logical :: is_uniform = .true.
92 double precision, allocatable :: var1_nodes(:), var2_nodes(:)
93
94 !> Guard (bucket) array for O(1) adaptive index lookup. Built when
95 !> is_uniform = .false. via eos_build_guards. For each axis:
96 !> guard_M : number of buckets covering [v(1), v(N)]
97 !> guard_scale: M / (v(N) - v(1))
98 !> guard(:) : 1-based array, size M; guard(k) is the smallest
99 !> 1-based node index ii such that v(ii) >= left
100 !> edge of bucket k (i.e., v(1) + (k-1)*span/M).
101 !> Lookup:
102 !> k = 1 + min(M-1, max(0, floor((val - v(1)) * scale)))
103 !> ii = guard(k); while (ii < N .and. v(ii) < val) ii = ii + 1
104 !> M is sized at build time so the safety while-loop iterates at
105 !> most once for typical curvature-equidistributed grids.
106 integer :: guard_m_1 = 0, guard_m_2 = 0
107 double precision :: guard_scale_1 = 0.0d0, guard_scale_2 = 0.0d0
108 integer, allocatable :: guard_1(:), guard_2(:)
109
110 end type eos_table_container
111
113
114 character(len=std_len) :: eos_type
115 character(len=20) :: method = 'state' !> 'state', 'analytic' or 'entropy' ('tables' = legacy alias for 'state')
116 integer :: method_id = eos_state !> integer form of method (set at init)
117 integer :: type_id = eos_type_fi !> integer form of eos_type (set at init)
118 character(len=20) :: gamma1_method = 'exact' !> 'exact' or 'effective'
119 character(len=20) :: p2eint_method = 'table' !> 'table' (fast) or 'bisect' (accurate)
120 character(len=20) :: pi_table = 'chromosphere' !> PI backend table: 'chromosphere'|'flare'|'prominence'
121 logical :: ione
122 character(len=std_len) :: table_location
123 double precision :: he_abundance
124 double precision :: gamma
125 double precision :: gamma_minus_1
126 double precision :: inv_gamma
127 double precision :: inv_gamma_minus_1
128 double precision :: inv_squared_c0
129 double precision :: inv_squared_c
130 double precision :: nh2rhofactor
131
132 !> Fully-ionised regime bypass constants (precomputed in eos_finalise)
133 double precision :: eion_per_nh !> Total ionisation energy per nH [code units]
134 double precision :: eint_rho_fi_threshold !> eint/rho above which gas is fully ionised [code units]
135 double precision :: p_rho_fi_threshold !> p/rho above which gas is fully ionised [code units]
136 double precision :: n_per_nh_fi !> Total particles per nH when FI = 2 + 3*A_He
137 double precision :: neonh_fi !> ne/nH when fully ionised = 1 + 2*A_He
138
139 !>Leaving a comment here to remind me that it's a bad idea to have anything outside
140 !> of the w() array if one wants to /ensure/ the fields are consistent
141 !> given OMP directives and load balancing
142
143 ! Expected components of the EoS
144 type(eos_table_container) :: neonh
146 type(eos_table_container) :: p2eint
147 type(eos_table_container) :: gamma1 !> First adiabatic index Gamma_1(nH, eint/nH)
148 type(eos_table_container) :: gamma1_p !> First adiabatic index Gamma_1(nH, p/nH) for fast csound2
149 type(eos_table_container) :: eint_from_t !> Inverse T table: eint/nH(nH, T)
150 type(eos_table_container) :: log_p !> Merged log10(p/nH)(nH, eint/nH) for WB bisection
151 type(eos_table_container) :: p_over_nh !> (1+He+y)*T for direct p lookup in to_primitive
152
153 !> Entropy-method tables (eos%method == 'entropy'). Each quantity Q is
154 !> stored as four containers -- Q, Q_x, Q_y, Q_xy (value plus the two
155 !> first derivatives and the cross derivative) -- fully determining the
156 !> bicubic Hermite polynomial in each cell (mod_eos_LTE_entropy). Five
157 !> quantities:
158 !> Forward (log_nH, log_eint/nH): Tfwd, pfwd, neOnH.
159 !> Inverse (log_nH, log_p/nH): eintP, g1p (= Gamma_1).
160 !> Inverse (log_nH, log_T): eintT.
161 !> The inverse tables are bisected against the analytic Saha solver at
162 !> build time and frozen to disk, so every runtime query is one lookup.
163 !
164 !> Forward (lr, le): ionisation fraction. The neOnH value container
165 !> is the existing neOnH field above; add three derivative tables.
166 type(eos_table_container) :: neonh_x !> d(ne/nH)/dx
167 type(eos_table_container) :: neonh_y !> d(ne/nH)/dy
168 type(eos_table_container) :: neonh_xy !> d2(ne/nH)/(dx dy)
169 !
170 !> Forward (lr, le): direct T and p tables. We do NOT derive T from
171 !> ds/dy of the s polynomial at runtime; the bicubic Hermite gives
172 !> O(h^3) error in derivatives vs O(h^4) in values. Storing T and p
173 !> as their own bicubic Hermite tables (built from the same Saha
174 !> call as s) keeps O(h^4) accuracy and preserves Maxwell consistency
175 !> at every node (T, p, s, gamma1 all from one Saha state).
176 type(eos_table_container) :: tfwd !> T [K] (CGS-stored) at (lr, le)
177 type(eos_table_container) :: tfwd_x !> dT/dx
178 type(eos_table_container) :: tfwd_y !> dT/dy
179 type(eos_table_container) :: tfwd_xy !> d2T/(dx dy)
180 type(eos_table_container) :: pfwd !> p [erg/cm^3] (CGS-stored) at (lr, le)
181 type(eos_table_container) :: pfwd_x !> dp/dx
182 type(eos_table_container) :: pfwd_y !> dp/dy
183 type(eos_table_container) :: pfwd_xy !> d2p/(dx dy)
184 !
185 !> Inverse (lr, lp): eint from (rho, p), replaces p2eint bisection
186 !> at runtime. Stored as log10(eint/nH), CGS axis units before shift.
187 type(eos_table_container) :: eintp !> log10(eint/nH) [CGS log10]
188 type(eos_table_container) :: eintp_x !> d(eintP)/dx x = log10(nH)
189 type(eos_table_container) :: eintp_y !> d(eintP)/dy y = log10(p/nH)
190 type(eos_table_container) :: eintp_xy !> d2(eintP)/(dx dy)
191 !
192 !> Inverse (lr, lp): gamma_1 at (rho, p) for csound2-from-pressure paths
193 type(eos_table_container) :: g1p !> Gamma_1(rho, p) dimensionless
194 type(eos_table_container) :: g1p_x !> dGamma_1/dx
195 type(eos_table_container) :: g1p_y !> dGamma_1/dy y = log10(p/nH)
196 type(eos_table_container) :: g1p_xy !> d2Gamma_1/(dx dy)
197 !
198 !> Inverse (lr, lT): eint from (rho, T). Used by IC, HSE BC, cooling.
199 type(eos_table_container) :: eintt !> log10(eint/nH) [CGS log10]
200 type(eos_table_container) :: eintt_x !> d(eintT)/dx x = log10(nH)
201 type(eos_table_container) :: eintt_y !> d(eintT)/dy y = log10(T)
202 type(eos_table_container) :: eintt_xy !> d2(eintT)/(dx dy)
203 !> Interleaved Group A table: T, neOnH, p_over_nH at same (nH, eint/nH) grid
204 double precision, allocatable :: table_eint_il(:,:,:) !> (3, dim1, dim2)
205 integer :: il_nq = 3 !> number of interleaved quantities
206
207 procedure(convert_condition), pointer, nopass :: to_conserved => null()
208 procedure(convert_condition), pointer, nopass :: to_primitive => null()
209 procedure(convert_condition), pointer, nopass :: p_to_e => null()
210 procedure(update_eos_spaces), pointer, nopass :: update_eos => null()
211 procedure(get_eos_variable_alt), pointer, nopass :: get_thermal_pressure => null()
212 procedure(get_eos_variable_alt), pointer, nopass :: get_temperature_from_eint => null()
213 procedure(get_eos_variable_alt), pointer, nopass :: get_temperature_from_etot => null()
214 procedure(get_eos_variable_alt), pointer, nopass :: get_temperature_from_pressure => null()
215 procedure(get_eos_variable_alt), pointer, nopass :: get_rfactor => null()
216 procedure(get_eos_variable_alt), pointer, nopass :: get_rho => null()
217 procedure(get_eos_variable_alt), pointer, nopass :: get_nh => null()
218 procedure(get_ne_nh_iface), pointer, nopass :: get_ne_nh => null()
219 procedure(get_eos_variable_alt), pointer, nopass :: get_te => null()
220 procedure(get_eos_variable_alt), pointer, nopass :: get_csound2 => null()
221
222 contains
223
224 !> Internal setter for gamma: updates gamma + the three derived cached
225 !> values (gamma_minus_1, inv_gamma, inv_gamma_minus_1) atomically.
226 !> PRIVATE on purpose: gamma is set ONLY via the parfile (&eos_list gamma=),
227 !> read once at eos_init, so the derived constants can never go stale.
228 !> User code must not set gamma; assigning eos%gamma directly is caught by
229 !> the consistency check in (m)hd_check_params.
230 procedure, private :: set_gamma => eos_set_gamma
231
232 end type eos_container
233
234 !> The single EoS state object, allocated in eos_init and shared (read-mostly)
235 !> across all EoS sub-modules and the physics layer.
236 type(eos_container), allocatable, public :: eos
237
238 !> wextra index for the cached log10(nH) used during STS substeps
239 !> (-1 = not allocated). Set by the physics module that owns the wextra slot.
240 integer, public :: iw_log_nh = -1
241
242contains
243
244 subroutine eos_set_gamma(this, gamma_new)
245 class(eos_container), intent(inout) :: this
246 double precision, intent(in) :: gamma_new
247
248 this%gamma = gamma_new
249 this%gamma_minus_1 = this%gamma - 1.0d0
250 this%inv_gamma = 1.0d0 / this%gamma
251 if (abs(this%gamma_minus_1) > 1.0d-12) then
252 this%inv_gamma_minus_1 = 1.0d0 / this%gamma_minus_1
253 else
254 this%inv_gamma_minus_1 = 0.0d0
255 end if
256 end subroutine eos_set_gamma
257
258end module mod_eos_container
259!> Needs a line after to pass the preprocesor
EoS state container – the single thermodynamic authority for AMRVAC.
integer, parameter, public eos_analytic
integer, parameter, public eos_type_pi
integer, parameter, public eos_type_fi
EoS-type selector, decoded once from eoseos_type into eostype_id. Used by the mode-specific kernels t...
integer, parameter, public eos_state
LTE method selector, decoded once from eosmethod into eosmethod_id so the runtime kernels dispatch on...
integer, parameter, public eos_entropy
type(eos_container), allocatable, public eos
The single EoS state object, allocated in eos_init and shared (read-mostly) across all EoS sub-module...
integer, parameter, public eos_type_lte
integer, public iw_log_nh
wextra index for the cached log10(nH) used during STS substeps (-1 = not allocated)....
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer, parameter ndim
Number of spatial dimensions for grid variables.