MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_eos_PI.t
Go to the documentation of this file.
1!=============================================================================
2!> PI (partial-ionisation, eos_type='PI') arm of the eos% family.
3!>
4!> The adapter between the ionisation backend (mod_eos_PI_tables) and the eos%
5!> authority. PI rides the FI fully-ionised ideal-gas closure (RR=1
6!> normalisation, p=(gamma-1) eint when ionE=F) and differs only through the
7!> variable mean-mass that enters via eos%get_Rfactor and -- in energy mode --
8!> the ionisation energy folded into eint. mod_eos_PI_tables has no mod_eos
9!> dependency, so eos% -> ionisation is acyclic.
10!>
11!> Structure mirrors mod_eos_FI / mod_eos_LTE:
12!> A. init / finalise -- wire the eos% pointer targets
13!> B. generic block getters -- the eos%-interface routines bound for PI
14!> (csound2, gamma1, Rfactor, Te update);
15!> module-agnostic via iw_rho/iw_e/iw_te,
16!> so the hd/mhd/ffhd seams share ONE copy
17!> instead of three. The seam keeps only
18!> the B/KE-specific conversions.
19!> C. scalar combined-solve backend -- one ionisation solve yields T,p,R(,iz)
20!> together; called per-cell by the seam
21!> conversions and by section D.
22!> D. fl-port scalar shims -- f(log_nH,log_x) callbacks for the
23!> cooling / conduction port objects.
24!> mod_eos re-exports the public names so the seams reach them through the single
25!> `use mod_eos` facade, exactly as for the FI/LTE kernels.
26!=============================================================================
33 use mod_timing
34 use mod_comm_lib, only: mpistop
35 implicit none
36 private
37
38 !> Lifecycle (PI arms of the eos_init / eos_finalise dispatchers). The eos%
39 !> block getters (update_eos_PI, get_Te_PI, get_csound2_PI, get_Rfactor_*_PI)
40 !> are PRIVATE: they are bound to eos% pointers inside eos_finalise_PI, so no
41 !> external module needs to name them.
43
44 !> get_gamma1_PI is bound to the phys_get_gamma1 pointer in the seam (the
45 !> phys layer owns that pointer), so it must stay public.
46 public :: get_gamma1_pi
47
48 !> Scalar combined-solve backend, called per-cell by the seam conversions
49 !> (rho = nH = 1 per H under the FI normalisation; eint is the GAS internal
50 !> energy, carrying the ionisation energy in energy mode).
51 public :: state_from_eint_pi !> rho,eint -> T, p, R (energy mode)
52 public :: p_eint_from_rho_t_pi !> rho,T -> p, eint, R
53 public :: eint_from_rho_p_pi !> rho,p -> eint (prim -> cons)
54 public :: csound2_prim_pi !> rho,p -> csound2
55
56 !> fl-port scalar callbacks (signature f(log_nH, log_x) -> scalar) for the
57 !> cooling / conduction port objects. PI's T-only ionisation is
58 !> nH-independent, so log_nH is ignored and quantities are evaluated per H.
59 public :: eint_from_t_pi !> (log_nH, log_T) -> eint/nH
60 public :: p2eint_pi !> (log_nH, log_p_nH) -> eint/p factor
61 public :: t_from_eint_pi !> (log_nH, log_eint_nH)-> T
62 public :: y_from_eint_pi !> (log_nH, log_eint_nH)-> ne/nH
63
64contains
65
66 !=========================================================================
67 ! A. Lifecycle
68 !=========================================================================
69
70 !> PI arm of eos_init (before units are known): PI shares the FI
71 !> temperature-from-pressure getter -- T=p/(R*rho) routed through
72 !> eos%get_Rfactor, which the seam points at the ionisation R-factor.
73 subroutine eos_init_pi()
74 eos%get_temperature_from_pressure => get_temperature_from_pressure_fi
75 end subroutine eos_init_pi
76
77 !> PI arm of eos_finalise (after unit_* are set): ride FI's ideal-gas getter
78 !> set and RR=1 normalisation (the variable mean-mass enters only via
79 !> eos%get_Rfactor, wired by the seam link arm), then initialise the
80 !> ionisation backend. In energy mode eint carries the ionisation energy, so
81 !> swap in the backend eint->T inversion.
82 subroutine eos_finalise_pi()
84 double precision :: rfactor_norm
85
86 eos%update_eos => update_eos_pi !> direct Te cache refresh each substep
87 eos%get_temperature_from_eint => get_temperature_from_eint_fi
88 eos%get_Te => get_te_pi !> read the cached Te (refreshed above)
89
90 !> R-factor: dispatch on pi_table. Physics-independent, so bound here
91 !> (was in the hd/mhd/ffhd link arms) -> these targets stay private.
92 if (eos%pi_table == 'prominence') then
93 eos%get_Rfactor => get_rfactor_prominence_pi
94 else
95 eos%get_Rfactor => get_rfactor_tonly_pi
96 end if
97 !> Fully-ionised particle counts (2 + 3*A_He per H; ne/nH = 1 + 2*A_He)
98 eos%n_per_nH_FI = 2.0d0 + 3.0d0 * eos%He_abundance
99 eos%neOnH_FI = 1.0d0 + 2.0d0 * eos%He_abundance
100
101 !> Initialise the ionisation backend. Under the FI normalisation the
102 !> (a,b) factors are absorbed into unit_*, RR=1, and b=(2+3 A_He) is the
103 !> full-ionisation reference in unit_pressure; the module's
104 !> R = (1+iz_H+A_He(...))/Rfactor_norm must reduce to 1 at full ionisation,
105 !> so Rfactor_norm = 2+3 A_He (the LTE a=b=1 value 1+4 A_He would be wrong).
106 rfactor_norm = 2.0d0 + 3.0d0 * eos%He_abundance
107 call ionization_degree_init(eos%He_abundance, rfactor_norm, &
108 trim(eos%pi_table), include_energy=eos%ionE)
109 if (mype == 0) write(*,*) "[eos PI] ionisation backend initialised: table=", &
110 trim(eos%pi_table), " ionE=", eos%ionE, " Rfactor_norm=", rfactor_norm
111
112 !> Energy mode: eint carries the ionisation energy, so swap in the
113 !> backend eint->T inversion and the energy-mode csound2 (both
114 !> physics-independent; get_csound2_PI was in the link arms).
115 if (eos%ionE) then
116 eos%get_temperature_from_eint => get_temperature_from_eint_pi
117 eos%get_csound2 => get_csound2_pi
118 end if
119 end subroutine eos_finalise_pi
120
121 !=========================================================================
122 ! B. Generic block getters (eos%-interface shape).
123 ! Module-agnostic: the primitive pressure is w(iw_e) (e_ aliases p_ in
124 ! primitive state) and the cached temperature is w(iw_te), published by
125 ! the phys module. One copy serves hd, mhd and ffhd.
126 !=========================================================================
127
128 !> Adiabatic sound speed squared from primitive (rho, p). PI energy mode.
129 subroutine get_csound2_pi(w, x, ixI^L, ixO^L, cs2)
130 integer, intent(in) :: ixi^l, ixo^l
131 double precision, intent(in) :: w(ixi^s, nw)
132 double precision, intent(in) :: x(ixi^s, 1:ndim)
133 double precision, intent(out):: cs2(ixi^s)
134
135 integer :: ix^d
136
137 timeeos0 = mpi_wtime()
138 {do ix^db=ixomin^db,ixomax^db\}
139 call csound2_prim_pi(w(ix^d,iw_rho), w(ix^d,iw_e), cs2(ix^d))
140 {end do\}
141 timeeos_csound = timeeos_csound + (mpi_wtime()-timeeos0)
142 end subroutine get_csound2_pi
143
144 !> Effective Gamma1 = cs2 * rho / p for the same primitive state.
145 subroutine get_gamma1_pi(w, x, ixI^L, ixO^L, gamma1)
146 integer, intent(in) :: ixi^l, ixo^l
147 double precision, intent(in) :: w(ixi^s, nw)
148 double precision, intent(in) :: x(ixi^s, 1:ndim)
149 double precision, intent(out):: gamma1(ixi^s)
150
151 double precision :: cs2
152 integer :: ix^d
153
154 {do ix^db=ixomin^db,ixomax^db\}
155 call csound2_prim_pi(w(ix^d,iw_rho), w(ix^d,iw_e), cs2)
156 gamma1(ix^d) = cs2 * w(ix^d,iw_rho) / w(ix^d,iw_e)
157 {end do\}
158 end subroutine get_gamma1_pi
159
160 !> No-energy R-factor (chromosphere/flare T-only tables) from the stored Te_.
161 !> Denominator (2+3 He) = b (full-ion reference) absorbed into unit_pressure
162 !> under the FI normalisation, RR=1 -> R->1 at full ionisation.
163 subroutine get_rfactor_tonly_pi(w, x, ixI^L, ixO^L, Rfactor)
164 integer, intent(in) :: ixi^l, ixo^l
165 double precision, intent(in) :: w(ixi^s,1:nw)
166 double precision, intent(in) :: x(ixi^s,1:ndim)
167 double precision, intent(out):: rfactor(ixi^s)
168 double precision :: iz_h(ixo^s), iz_he(ixo^s)
169
170 call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,iw_te),iz_h,iz_he)
171 rfactor(ixo^s) = (1.d0 + iz_h(ixo^s) + eos%He_abundance &
172 * (1.d0 + iz_he(ixo^s)*(1.d0+iz_he(ixo^s)))) / (2.d0 + 3.d0*eos%He_abundance)
173 end subroutine get_rfactor_tonly_pi
174
175 !> Prominence (T,p) R-factor: recompute from (rho, pth) via the backend's
176 !> prominence inversion (no-energy only -> pth=(gamma-1)*eint, R-independent).
177 subroutine get_rfactor_prominence_pi(w, x, ixI^L, ixO^L, Rfactor)
178 use mod_physics, only: phys_get_ei
179 integer, intent(in) :: ixi^l, ixo^l
180 double precision, intent(in) :: w(ixi^s,1:nw)
181 double precision, intent(in) :: x(ixi^s,1:ndim)
182 double precision, intent(out):: rfactor(ixi^s)
183 double precision :: ei(ixi^s), pth(ixi^s), rho(ixi^s), t(ixi^s)
184
185 ei(ixo^s) = phys_get_ei(w, ixi^l, ixo^l)
186 pth(ixo^s) = eos%gamma_minus_1 * ei(ixo^s)
187 rho(ixo^s) = w(ixo^s,iw_rho)
188 call ionization_get_state(ixi^l, ixo^l, rho, pth, t, rfactor)
189 end subroutine get_rfactor_prominence_pi
190
191 !> Direct (no-lag) temperature refresh: recompute the cached w(iw_te) from the
192 !> CURRENT conserved state, mirroring update_eos_LTE. Energy mode inverts the
193 !> gas internal energy (incl. ionisation energy) by Newton; no-energy modes
194 !> form pth=(gamma-1)*eint and invert (rho,pth)->T via the backend
195 !> (y-bisection for chromosphere/flare, p-bisection for prominence). Shared by
196 !> update_eos_PI (eos%update_eos) and the gated source/STS call sites.
197 subroutine refresh_te_pi(ixI^L, ixO^L, w, x)
198 use mod_physics, only: phys_get_ei
199 integer, intent(in) :: ixi^l, ixo^l
200 double precision, intent(in) :: x(ixi^s,1:ndim)
201 double precision, intent(inout) :: w(ixi^s,1:nw)
202 double precision :: ei(ixi^s), pth(ixi^s), rho(ixi^s), t(ixi^s), rf(ixi^s)
203 double precision :: tsc, psc, rsc
204 integer :: ix^d
205
206 ei(ixo^s) = phys_get_ei(w, ixi^l, ixo^l)
207 if (eos%ionE) then
208 !> energy mode (chromosphere/flare): eint carries the ionisation
209 !> energy, invert eint->T by Newton per cell.
210 {do ix^db=ixomin^db,ixomax^db\}
211 call state_from_eint_pi(w(ix^d,iw_rho), ei(ix^d), tsc, psc, rsc)
212 w(ix^d,iw_te) = tsc
213 {end do\}
214 else
215 !> no-energy: pth=(gamma-1)*eint; ionization_get_state inverts
216 !> (rho,pth)->T (T-only y-bisection or prominence p-bisection).
217 pth(ixo^s) = eos%gamma_minus_1 * ei(ixo^s)
218 rho(ixo^s) = w(ixo^s,iw_rho)
219 call ionization_get_state(ixi^l, ixo^l, rho, pth, t, rf)
220 w(ixo^s,iw_te) = t(ixo^s)
221 end if
222 end subroutine refresh_te_pi
223
224 !> eos%update_eos arm: per-RK-substep cache refresh (called from mod_advance,
225 !> exactly as update_eos_LTE). Direct, so the cached Te never lags.
226 subroutine update_eos_pi(ixI^L, ixO^L, w, x)
227 integer, intent(in) :: ixi^l, ixo^l
228 double precision, intent(in) :: x(ixi^s,1:ndim)
229 double precision, intent(inout) :: w(ixi^s,1:nw)
230 call refresh_te_pi(ixi^l, ixo^l, w, x)
231 end subroutine update_eos_pi
232
233 !> eos%get_Te arm: read the cached temperature (refreshed by update_eos_PI /
234 !> the gated source/STS sites), mirroring get_Te_LTE.
235 subroutine get_te_pi(w, x, ixI^L, ixO^L, T)
236 integer, intent(in) :: ixi^l, ixo^l
237 double precision, intent(in) :: w(ixi^s,1:nw)
238 double precision, intent(in) :: x(ixi^s,1:ndim)
239 double precision, intent(out) :: t(ixi^s)
240 t(ixo^s) = w(ixo^s,iw_te)
241 end subroutine get_te_pi
242
243 !> PI energy mode: temperature from GAS internal energy via the backend
244 !> eint->T inversion (eint carries the ionisation-energy term, so the FI
245 !> p=(gamma-1)*eint relation does not hold). w(iw_e) is assumed to be eint
246 !> already (the etot hook subtracts KE/ME via phys_e_to_ei before calling).
247 subroutine get_temperature_from_eint_pi(w, x, ixI^L, ixO^L, res)
248 integer, intent(in) :: ixi^l, ixo^l
249 double precision, intent(in) :: x(ixi^s,1:ndim)
250 double precision, intent(in) :: w(ixi^s,1:nw)
251 double precision, intent(out):: res(ixi^s)
252
253 double precision :: pth, rfac
254 integer :: ix^d
255
256 timeeos0 = mpi_wtime()
257 {do ix^db=ixomin^db,ixomax^db\}
258 call state_from_eint_pi(w(ix^d,iw_rho), w(ix^d,iw_e), &
259 res(ix^d), pth, rfac)
260 {end do\}
261 timeeos_tfromei=timeeos_tfromei+(mpi_wtime()-timeeos0)
262 end subroutine get_temperature_from_eint_pi
263
264 !=========================================================================
265 ! C. Scalar combined-solve backend (eos%inv_gamma_minus_1 throughout,
266 ! matching the FI ideal-gas split; the ionisation-energy term is folded
267 ! in by the ionisation module when ionE=.true.).
268 !=========================================================================
269
270 !> Conserved gas internal energy -> temperature, thermal pressure, R.
271 !> Inverse of p_eint_from_rho_T_PI. eint is the GAS internal energy
272 !> (mechanical energy already removed by the caller).
273 subroutine state_from_eint_pi(rho, eint, T, p, Rfactor, iz_H, iz_He)
274 double precision, intent(in) :: rho, eint
275 double precision, intent(out) :: t, p, rfactor
276 double precision, intent(out), optional :: iz_h, iz_he
277
278 if (eos%type_id /= eos_type_pi) call mpistop( &
279 "state_from_eint_PI called outside eos_type='PI'")
280 call ionization_get_state_from_eint(rho, eint, eos%inv_gamma_minus_1, &
281 t, p, rfactor, iz_h, iz_he)
282 end subroutine state_from_eint_pi
283
284 !> Temperature -> thermal pressure and GAS internal energy (incl. ion energy)
285 subroutine p_eint_from_rho_t_pi(rho, T, p, eint, Rfactor, iz_H, iz_He)
286 double precision, intent(in) :: rho, t
287 double precision, intent(out) :: p, eint, rfactor
288 double precision, intent(out), optional :: iz_h, iz_he
289
290 if (eos%type_id /= eos_type_pi) call mpistop( &
291 "p_eint_from_rho_T_PI called outside eos_type='PI'")
292 call ionization_get_p_eint_from_rho_t(rho, t, eos%inv_gamma_minus_1, &
293 p, eint, rfactor, iz_h, iz_he)
294 end subroutine p_eint_from_rho_t_pi
295
296 !> Primitive pressure -> GAS internal energy (prim -> conserved direction):
297 !> invert (rho,p)->T then map T->eint, so the forward/inverse pair stay consistent.
298 subroutine eint_from_rho_p_pi(rho, p, eint)
299 double precision, intent(in) :: rho, p
300 double precision, intent(out) :: eint
301 double precision :: t, pcheck, rfactor
302
303 if (eos%type_id /= eos_type_pi) call mpistop( &
304 "eint_from_rho_p_PI called outside eos_type='PI'")
305 call ionization_get_state_scalar(rho, p, t, rfactor)
306 call ionization_get_p_eint_from_rho_t(rho, t, eos%inv_gamma_minus_1, &
307 pcheck, eint, rfactor)
308 end subroutine eint_from_rho_p_pi
309
310 !> Adiabatic sound speed squared from primitive (rho, p).
311 subroutine csound2_prim_pi(rho, p, csound2)
312 double precision, intent(in) :: rho, p
313 double precision, intent(out) :: csound2
314 double precision :: t, rfactor
315
316 if (eos%type_id /= eos_type_pi) call mpistop( &
317 "csound2_prim_PI called outside eos_type='PI'")
318 call ionization_get_state_scalar(rho, p, t, rfactor)
319 call ionization_get_csound2_t(t, eos%inv_gamma_minus_1, csound2)
320 end subroutine csound2_prim_pi
321
322 !=========================================================================
323 ! D. fl-port scalar callbacks (rho = nH = 1 per H). Thin shims over the
324 ! section-C backend matching the cooling/conduction port signatures.
325 !=========================================================================
326
327 !> Internal energy per H from temperature: eint/nH(T).
328 double precision function eint_from_t_pi(log_nH, log_T) result(eint)
329 double precision, intent(in) :: log_nh, log_t
330 double precision :: p, rfactor
331 call p_eint_from_rho_t_pi(1.d0, 10.d0**log_t, p, eint, rfactor)
332 end function eint_from_t_pi
333
334 !> eint/p factor from pressure per H: maps p -> eint = p * (this).
335 double precision function p2eint_pi(log_nH, log_p_nH) result(factor)
336 double precision, intent(in) :: log_nh, log_p_nh
337 double precision :: p, eint
338 p = 10.d0**log_p_nh
339 call eint_from_rho_p_pi(1.d0, p, eint)
340 factor = eint / p
341 end function p2eint_pi
342
343 !> Temperature from internal energy per H.
344 double precision function t_from_eint_pi(log_nH, log_eint_nH) result(T)
345 double precision, intent(in) :: log_nh, log_eint_nh
346 double precision :: p, rfactor
347 call state_from_eint_pi(1.d0, 10.d0**log_eint_nh, t, p, rfactor)
348 end function t_from_eint_pi
349
350 !> Electron-to-hydrogen ratio ne/nH from internal energy per H.
351 !> ne/nH = iz_H + A_He*iz_He*(1+iz_He) (matches the R-factor numerator's
352 !> electron count; second He ionisation assumed equal to the first).
353 double precision function y_from_eint_pi(log_nH, log_eint_nH) result(y)
354 double precision, intent(in) :: log_nh, log_eint_nh
355 double precision :: t, p, rfactor, iz_h, iz_he
356 call state_from_eint_pi(1.d0, 10.d0**log_eint_nh, t, p, rfactor, iz_h, iz_he)
357 y = iz_h + eos%He_abundance*iz_he*(1.d0+iz_he)
358 end function y_from_eint_pi
359
360end module mod_eos_pi
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
EoS state container – the single thermodynamic authority for AMRVAC.
integer, parameter, public eos_type_pi
type(eos_container), allocatable, public eos
The single EoS state object, allocated in eos_init and shared (read-mostly) across all EoS sub-module...
FI (fully-ionised, constant-gamma) EoS kernels for the eos% family.
Definition mod_eos_FI.t:10
subroutine, public get_temperature_from_pressure_fi(w, x, ixil, ixol, res)
FI temperature from primitive pressure: T = p / (R * rho). w is PRIMITIVE here, so iw_e holds the the...
Definition mod_eos_FI.t:106
subroutine, public get_temperature_from_eint_fi(w, x, ixil, ixol, res)
Temperature from internal energy, fully-ionised ideal gas: T = pth/(rho*R).
Definition mod_eos_FI.t:84
PI (partial-ionisation) ionisation-degree backend for the eos% family.
subroutine, public ionization_degree_init(he_abundance, rfactor_norm, table_name, include_energy)
PI (partial-ionisation, eos_type='PI') arm of the eos% family.
Definition mod_eos_PI.t:27
double precision function, dimension(log_nh, log_p_nh), public p2eint_pi(log_nh, log_p_nh)
eint/p factor from pressure per H: maps p -> eint = p * (this).
Definition mod_eos_PI.t:336
double precision function, dimension(log_nh, log_t), public eint_from_t_pi(log_nh, log_t)
Internal energy per H from temperature: eint/nH(T).
Definition mod_eos_PI.t:329
subroutine, public eos_finalise_pi()
PI arm of eos_finalise (after unit_* are set): ride FI's ideal-gas getter set and RR=1 normalisation ...
Definition mod_eos_PI.t:83
subroutine, public csound2_prim_pi(rho, p, csound2)
Adiabatic sound speed squared from primitive (rho, p).
Definition mod_eos_PI.t:312
double precision function, dimension(log_nh, log_eint_nh), public y_from_eint_pi(log_nh, log_eint_nh)
Electron-to-hydrogen ratio ne/nH from internal energy per H. ne/nH = iz_H + A_He*iz_He*(1+iz_He) (mat...
Definition mod_eos_PI.t:354
subroutine, public eos_init_pi()
Lifecycle (PI arms of the eos_init / eos_finalise dispatchers). The eos% block getters (update_eos_PI...
Definition mod_eos_PI.t:74
subroutine, public p_eint_from_rho_t_pi(rho, t, p, eint, rfactor, iz_h, iz_he)
Temperature -> thermal pressure and GAS internal energy (incl. ion energy)
Definition mod_eos_PI.t:286
subroutine, public get_gamma1_pi(w, x, ixil, ixol, gamma1)
Effective Gamma1 = cs2 * rho / p for the same primitive state.
Definition mod_eos_PI.t:146
subroutine, public eint_from_rho_p_pi(rho, p, eint)
Primitive pressure -> GAS internal energy (prim -> conserved direction): invert (rho,...
Definition mod_eos_PI.t:299
double precision function, dimension(log_nh, log_eint_nh), public t_from_eint_pi(log_nh, log_eint_nh)
Temperature from internal energy per H.
Definition mod_eos_PI.t:345
subroutine, public state_from_eint_pi(rho, eint, t, p, rfactor, iz_h, iz_he)
Conserved gas internal energy -> temperature, thermal pressure, R. Inverse of p_eint_from_rho_T_PI....
Definition mod_eos_PI.t:274
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer mype
The rank of the current MPI task.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_get_ei), pointer phys_get_ei
Definition mod_physics.t:68
double precision timeeos0
Definition mod_timing.t:10
double precision timeeos_csound
Definition mod_timing.t:12