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