MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_mhd_eos.t
Go to the documentation of this file.
1!=============================================================================
2!> MHD <-> EoS seam: binds the eos% authority into magnetohydrodynamics.
3!>
4!> mhd_link_eos wires the eos%/phys_ procedure pointers (conversions, pthermal,
5!> csound2/gamma1, get_Rfactor, temperature, update_temperature) per eos_type
6!> (FI / LTE / PI, with PI energy- and prominence-mode overrides) and per energy
7!> formulation (origin / internal_e / hydrodynamic_e / semirelativistic).
8!> bind_eos_to_source wires the thermal-conduction / radiative-cooling / thermal-
9!> emission / FLD fluid-port callbacks from eos%.
10!>
11!> Holds the MHD block routines that wrap the shared thermodynamics with MHD's
12!> mechanical-energy bookkeeping (kinetic + MAGNETIC energy): the FI/LTE/PI
13!> conversions, p_to_e, the pthermal variants, csound2/gamma1, and the PI energy
14!> + prominence R-factor / temperature kernels.
15!=============================================================================
18 use mod_physics
19 use mod_eos
20 !> The mode-specific scalar kernels are reached from their sub-modules, not the
21 !> mod_eos facade (which no longer re-exports them). Each kernel mpistops if
22 !> called under the wrong eos_type/method.
23 use mod_eos_lte
25 use mod_eos_pi
27 use mod_mhd_phys
28 use mod_timing
30
31 use mod_comm_lib, only: mpistop
32
33 implicit none
34 private
35
36 !> Thermal pressure pointer: set by mhd_link_eos based on energy formulation.
37 !> Internal to mod_mhd_eos — external callers use eos%get_thermal_pressure.
38 procedure(sub_get_pthermal), pointer, public :: mhd_get_pthermal => null()
39
40 !> Temperature pointer: set by mhd_link_eos based on EoS type and energy formulation.
41 procedure(sub_get_pthermal), pointer, public :: mhd_get_temperature => null()
42 !> use habitual name of converting to primitive
43 procedure(sub_convert), pointer, public :: mhd_to_primitive => null()
44 !> use habitual name of converting to conserved
45 procedure(sub_convert), pointer, public :: mhd_to_conserved => null()
46
47 public :: mhd_link_eos
48contains
49
50 !> Link the appropriate EOS conversion routines based on the selected EoS type
51 subroutine mhd_link_eos()
53
54 !> Primitive <-> Conserved routing
55 ! PI (partial approximations) takes the FI conversions as its BASE: in
56 ! no-energy mode this is exact (e_int = p/(gamma-1); the variable R-factor
57 ! enters only via eos%get_Rfactor, below). In energy mode (eos%ionE) the
58 ! PI override block at the end of this routine repoints to_conserved/
59 ! to_primitive (and p_to_e/pthermal/csound) at the PI-energy variants, so
60 ! the FI assignment here is just a harmless base that gets replaced.
61 if (eos%eos_type == 'FI' .or. eos%eos_type == 'PI') then
62 ! PI takes its electron count from a variable R factor evaluated on
63 ! the rho slot, which under splitting holds only the perturbation.
64 if (eos%eos_type == 'PI' .and. has_equi_rho_and_p) &
65 call mpistop('PI EoS not supported with equilibrium splitting')
66 if(mhd_hydrodynamic_e) then
67 eos%to_primitive => mhd_to_primitive_hde
68 eos%to_conserved => mhd_to_conserved_hde
69 else if(mhd_semirelativistic) then
70 if(mhd_energy) then
71 eos%to_primitive => mhd_to_primitive_semirelati
72 eos%to_conserved => mhd_to_conserved_semirelati
73 else
74 eos%to_primitive => mhd_to_primitive_semirelati_noe
75 eos%to_conserved => mhd_to_conserved_semirelati_noe
76 end if
77 else
78 if(has_equi_rho_and_p) then
79 eos%to_primitive => mhd_to_primitive_split_rho
80 eos%to_conserved => mhd_to_conserved_split_rho
81 else if(mhd_internal_e) then
82 eos%to_primitive => mhd_to_primitive_inte
83 eos%to_conserved => mhd_to_conserved_inte
84 else if(mhd_energy) then
85 eos%to_primitive => mhd_to_primitive_origin
86 eos%to_conserved => mhd_to_conserved_origin
87 else
88 eos%to_primitive => mhd_to_primitive_origin_noe
89 eos%to_conserved => mhd_to_conserved_origin_noe
90 end if
91 end if
92 else if (eos%eos_type == 'LTE') then
93 ! Guard unsupported combinations
95 call mpistop('LTE EoS not supported with mhd_hydrodynamic_e')
97 call mpistop('LTE EoS not supported with mhd_semirelativistic')
99 call mpistop('LTE EoS not supported with equilibrium splitting')
100 if (.not. mhd_energy) &
101 call mpistop('LTE EoS requires mhd_energy=.true.')
102 ! Route LTE conversion based on energy formulation
103 if (mhd_internal_e) then
104 eos%to_primitive => mhd_to_primitive_inte_lte
105 eos%to_conserved => mhd_to_conserved_inte_lte
106 else
107 eos%to_primitive => mhd_to_primitive_origin_lte
108 eos%to_conserved => mhd_to_conserved_origin_lte
109 end if
110 else
111 call mpistop('Error: Unknown MHD EOS type: ' // trim(eos%eos_type))
112 end if
113
114 phys_to_primitive => eos%to_primitive
115 phys_to_conserved => eos%to_conserved
116 phys_bind_eos_to_source => bind_eos_to_source
117
118 !> p_to_e (pressure -> total energy for origin, or eint for inte)
119 if (mhd_internal_e) then
120 eos%p_to_e => mhd_p_to_eint
121 else
122 eos%p_to_e => mhd_p_to_e
123 end if
124
125 !> Sound speed and Gamma1
126 if (eos%eos_type == 'LTE' .and. eos%ionE) then
127 eos%get_csound2 => mhd_get_csound2_lte
128 phys_get_gamma1 => mhd_get_gamma1_lte
129 else
130 eos%get_csound2 => mhd_get_csound2_fi
131 phys_get_gamma1 => get_gamma1_fi
132 end if
133
134 !> Prolongation
135 if (eos%eos_type == 'LTE' .and. eos%ionE) then
136 phys_to_prolong => mhd_to_prolong_lte
137 phys_from_prolong => mhd_from_prolong_lte
138 end if
139
140 !> Rfactor: only the FI case is physics-dependent (the usr_Rfactor user
141 !> hook). The LTE and PI bindings are pure eos% routines, so they are set
142 !> in eos_finalise_{LTE,PI} (which run after this and before
143 !> bind_eos_to_source, so they win) -- keeping those targets private.
144 if(associated(usr_rfactor)) then
145 eos%get_Rfactor => usr_rfactor
146 else
147 eos%get_Rfactor => rfactor_from_constant_ionization
148 end if
149
150
151 !> Thermal pressure routing
152 if(mhd_internal_e) then
153 phys_get_pthermal => mhd_get_pthermal_inte
154 mhd_get_pthermal => mhd_get_pthermal_inte
155 else if(mhd_hydrodynamic_e) then
156 phys_get_pthermal => mhd_get_pthermal_hde
157 mhd_get_pthermal => mhd_get_pthermal_hde
158 else if(mhd_semirelativistic) then
159 phys_get_pthermal => mhd_get_pthermal_semirelati
160 mhd_get_pthermal => mhd_get_pthermal_semirelati
161 else if(mhd_energy) then
162 phys_get_pthermal => mhd_get_pthermal_origin
163 mhd_get_pthermal => mhd_get_pthermal_origin
164 else
165 phys_get_pthermal => mhd_get_pthermal_noe
166 mhd_get_pthermal => mhd_get_pthermal_noe
167 end if
168
169 ! For LTE, override with version that delegates to eos%get_thermal_pressure
170 if (eos%eos_type == 'LTE') then
171 phys_get_pthermal => mhd_get_pthermal_lte
172 mhd_get_pthermal => mhd_get_pthermal_lte
173 end if
174 ! Single entry point: all callers use eos%get_thermal_pressure
175 eos%get_thermal_pressure => mhd_get_pthermal
176
177 !> Temperature routing
178 if(eos%eos_type == 'PI' .or. eos%eos_type == 'LTE') then
179 mhd_get_temperature => mhd_get_temperature_from_te
180 else
181 if(mhd_internal_e) then
182 if(has_equi_rho_and_p) then
183 mhd_get_temperature => mhd_get_temperature_from_eint_with_equi
184 else
185 mhd_get_temperature => mhd_get_temperature_from_eint
186 end if
187 else
188 if(has_equi_rho_and_p) then
189 mhd_get_temperature => mhd_get_temperature_from_etot_with_equi
190 else
191 mhd_get_temperature => mhd_get_temperature_from_etot
192 end if
193 end if
194 end if
195
196 !> Internal energy extraction
197 if(mhd_internal_e) then
198 phys_get_ei => mhd_get_ei_inte
199 else if(mhd_energy) then
200 phys_get_ei => mhd_get_ei_origin
201 end if
202
203 !> PI energy-mode overrides (eos_type='PI', ionE=.true.)
204 ! PI shares FI's normalisation and no-energy path verbatim; energy mode
205 ! differs ONLY in the eint<->p relation (eint carries the ionisation
206 ! energy). Override exactly the routines that touch that relation, all
207 ! delegating to the portable scalar backend in mod_eos_PI. FI
208 ! routines stay pristine (no flag branch in the hot path).
209 if (eos%eos_type == 'PI' .and. eos%ionE) then
210 if (.not. mhd_energy) &
211 call mpistop('PI energy EoS requires mhd_energy=.true.')
212 if (mhd_hydrodynamic_e) &
213 call mpistop('PI energy EoS not supported with mhd_hydrodynamic_e')
215 call mpistop('PI energy EoS not supported with mhd_semirelativistic')
216 if (has_equi_rho_and_p) &
217 call mpistop('PI energy EoS not supported with equilibrium splitting')
218
219 if (mhd_internal_e) then
220 eos%to_conserved => mhd_to_conserved_inte_pi
221 eos%to_primitive => mhd_to_primitive_inte_pi
222 eos%p_to_e => mhd_p_to_eint_pi
223 phys_get_pthermal => mhd_get_pthermal_inte_pi
224 mhd_get_pthermal => mhd_get_pthermal_inte_pi
225 else
226 eos%to_conserved => mhd_to_conserved_origin_pi
227 eos%to_primitive => mhd_to_primitive_origin_pi
228 eos%p_to_e => mhd_p_to_e_pi
229 phys_get_pthermal => mhd_get_pthermal_origin_pi
230 mhd_get_pthermal => mhd_get_pthermal_origin_pi
231 end if
232 phys_to_primitive => eos%to_primitive
233 phys_to_conserved => eos%to_conserved
234 eos%get_thermal_pressure => mhd_get_pthermal
235
236 !> eos%get_csound2 => get_csound2_PI is physics-independent: set in
237 !> eos_finalise_PI (ionE arm) so the target stays private.
239
240 ! Te_ refreshed from eint each substep (direct inversion, no lag).
241 ! Module-specific (uses MHD's Te_ index): PI registers Te via
242 ! var_set_auxvar, which does NOT set the generic iw_te, so the
243 ! temperature aux must be addressed through the module's own Te_.
244 end if
245
246 ! phys_e_to_ei / phys_ei_to_e assigned in mhd_phys_init (mod_mhd_phys.t)
247 mhd_to_primitive => eos%to_primitive
248 mhd_to_conserved => eos%to_conserved
249
250 end subroutine mhd_link_eos
251
252 !> Called by eos_finalise via phys_bind_eos_to_source to link
253 !> TC and RC modules to EoS-aware function pointers.
254 subroutine bind_eos_to_source()
255
256 ! Override eos%get_temperature_from_{etot,eint} per (eos_type, internal_e, equi).
257 ! Runs AFTER eos_finalise's unconditional generic-helper assignment.
258 ! Two semantically distinct hooks:
259 ! - from_etot: caller's w(:,e_) is total energy; subtract KE+ME before T.
260 ! - from_eint: caller's w(:,e_) is gas internal energy; compute T directly.
261 ! In mhd_internal_e mode w(:,e_) IS already eint, so the etot hook is bound
262 ! to the same routine as the eint hook (no subtraction). Required because
263 ! eos_finalise's generic helper calls phys_e_to_ei, which is left unbound
264 ! by mhd_phys_init when mhd_internal_e=.true.
265 if (eos%eos_type == 'LTE') then
266 if (mhd_internal_e) then
267 ! w(:,e_) is eint; both hooks do the LTE table lookup directly.
268 eos%get_temperature_from_etot => eos%get_temperature_from_eint
269 else
270 ! Total-energy: subtract KE+ME (via phys_e_to_ei) then LTE table lookup.
271 eos%get_temperature_from_etot => mhd_get_temperature_from_etot_lte
272 end if
273 else ! FI
274 if (mhd_internal_e) then
275 ! w(:,e_) is eint; both hooks share the eint variant.
276 if (has_equi_rho_and_p) then
277 eos%get_temperature_from_etot => mhd_get_temperature_from_eint_with_equi
278 eos%get_temperature_from_eint => mhd_get_temperature_from_eint_with_equi
279 else
280 eos%get_temperature_from_etot => mhd_get_temperature_from_eint
281 eos%get_temperature_from_eint => mhd_get_temperature_from_eint
282 end if
283 else
284 ! Total-energy: distinct etot/eint paths.
285 if (has_equi_rho_and_p) then
286 eos%get_temperature_from_etot => mhd_get_temperature_from_etot_with_equi
287 eos%get_temperature_from_eint => mhd_get_temperature_from_eint_with_equi
288 else
289 eos%get_temperature_from_etot => mhd_get_temperature_from_etot
290 eos%get_temperature_from_eint => mhd_get_temperature_from_eint
291 end if
292 end if
293 end if
294
295 if (allocated(tc_fl)) then
296 tc_fl%get_temperature_from_conserved => eos%get_temperature_from_etot
297 if (eos%eos_type == 'LTE' .and. eos%ionE) then
298 tc_fl%get_temperature_from_eint => get_temperature_from_eint_fast_lte
299 else
300 tc_fl%get_temperature_from_eint => eos%get_temperature_from_eint
301 end if
302 tc_fl%get_rho => eos%get_rho
303 tc_fl%get_ne_nH => eos%get_ne_nH
304 tc_fl%get_var_Rfactor => eos%get_Rfactor
305 tc_fl%inv_gamma_minus_1 = eos%inv_gamma_minus_1
306 tc_fl%nH2rhoFactor = eos%nH2rhoFactor
307 tc_fl%log_T_floor = eos_get_log_t_floor()
308 tc_fl%eint_from_T => eint_nh_from_t
309 ! Equilibrium-specific pointers
311 tc_fl%subtract_equi = .true.
312 tc_fl%get_temperature_equi => mhd_get_temperature_equi
313 tc_fl%get_rho_equi => mhd_get_rho_equi
314 else
315 tc_fl%subtract_equi = .false.
316 end if
317 end if
318
319 if (allocated(rc_fl)) then
320 rc_fl%get_rho => eos%get_rho
321 rc_fl%get_pthermal => eos%get_thermal_pressure
322 rc_fl%get_var_Rfactor => eos%get_Rfactor
323 rc_fl%get_Te => eos%get_Te
324 rc_fl%get_ne_nH => eos%get_ne_nH
325 nullify(rc_fl%get_rho2_factor)
326 if(mhd_uawsom) rc_fl%get_rho2_factor => mhd_uawsom_rho2_factor
327 rc_fl%ionE = eos%ionE
328 rc_fl%method = eos%method
329 rc_fl%inv_gamma_minus_1 = eos%inv_gamma_minus_1
330 rc_fl%nH2rhoFactor = eos%nH2rhoFactor
331 rc_fl%eion_per_nH = eos%eion_per_nH
332 rc_fl%eint_from_T => eint_nh_from_t
333 rc_fl%p2eint => p2eint_from_nh_p
334 rc_fl%T_from_eint => t_from_nh_eint
335 rc_fl%y_from_eint => y_from_nh_eint
336 ! Equilibrium-specific pointers
338 rc_fl%subtract_equi = .true.
339 rc_fl%get_rho_equi => mhd_get_rho_equi
340 rc_fl%get_pthermal_equi => mhd_get_pe_equi
341 rc_fl%get_ne_nH_equi => mhd_get_ne_nh_equi
342 rc_fl%get_temperature_equi => mhd_get_temperature_equi
343 else
344 rc_fl%subtract_equi = .false.
345 end if
346 !> Build the variable-c_V Townsend Y_mod table now that all
347 !> EoS tables (eint_from_T, T, neOnH) are in code units.
348 !> build_Y_mod_table checks coolmethod=='exact' and .not.isPPL
349 !> internally and early-returns otherwise. Feed it the inverse-table nH
350 !> grid via the port so it never touches eos% directly. LTE only:
351 !> eos_get_eintT_grid reads the LTE eintT grid, and PI (T-only) cooling
352 !> runs the classical Townsend path (Y_mod-for-PI is a later refinement).
353 if (eos%ionE .and. eos%eos_type == 'LTE') then
354 call eos_get_eintt_grid(rc_fl%Y_mod_n_nH, &
355 rc_fl%Y_mod_lg_nH_min, rc_fl%Y_mod_lg_nH_max)
357 end if
358 end if
359
360 !> PI energy mode: the eint<->T scalar callbacks wired above are the
361 !> LTE-table lookups, which PI does not load. Repoint cooling/conduction
362 !> at the ionisation backend (rho=nH=1 per H). Classical Townsend; Y_mod
363 !> is not built for PI (guard above), so the classical branch is used.
364 if (eos%eos_type == 'PI' .and. eos%ionE) then
365 if (allocated(tc_fl)) tc_fl%eint_from_T => eint_from_t_pi
366 if (allocated(rc_fl)) then
367 rc_fl%eint_from_T => eint_from_t_pi
368 rc_fl%p2eint => p2eint_pi
369 rc_fl%T_from_eint => t_from_eint_pi
370 rc_fl%y_from_eint => y_from_eint_pi
371 end if
372 end if
373
374 if (allocated(te_fl_mhd)) then
375 te_fl_mhd%get_rho => eos%get_rho
376 te_fl_mhd%get_pthermal => eos%get_thermal_pressure
377 te_fl_mhd%get_var_Rfactor => eos%get_Rfactor
378 te_fl_mhd%get_ne_nH => eos%get_ne_nH
379 end if
380
381 if (allocated(fld_fl)) then
382 !> Radiation (FLD) fluid: gas-EoS callbacks. get_temperature_from_pressure
383 !> is the FI T=p/(R*rho) routine (the LTE variant is a later pass).
384 fld_fl%gamma = eos%gamma
385 fld_fl%get_tgas => eos%get_temperature_from_pressure
386 fld_fl%get_Rfactor => eos%get_Rfactor
387 end if
388
389 end subroutine bind_eos_to_source
390
391 !> FI conversion routines (signatures updated for convert_condition interface)
392
393 !> Transform primitive variables into conservative ones (origin, total energy)
394 subroutine mhd_to_conserved_origin(ixI^L,ixO^L,w,x)
396 integer, intent(in) :: ixi^l, ixo^l
397 double precision, intent(inout) :: w(ixi^s, nw)
398 double precision, intent(in) :: x(ixi^s, 1:ndim)
399
400 integer :: ix^d
401
402 {do ix^db=ixomin^db,ixomax^db\}
403 ! Calculate total energy from pressure, kinetic and magnetic energy
404 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1&
405 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
406 +(^c&w(ix^d,b^c_)**2+))
407 if(mhd_uawsom) w(ix^d,e_)=w(ix^d,e_)+&
408 w(ix^d,waplus_)+w(ix^d,waminus_)+w(ix^d,wkplus_)+w(ix^d,wkminus_)
409 ! Convert velocity to momentum
410 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
411 {end do\}
412
413 end subroutine mhd_to_conserved_origin
414
415 !> Transform primitive variables into conservative ones (no energy)
416 subroutine mhd_to_conserved_origin_noe(ixI^L,ixO^L,w,x)
418 integer, intent(in) :: ixi^l, ixo^l
419 double precision, intent(inout) :: w(ixi^s, nw)
420 double precision, intent(in) :: x(ixi^s, 1:ndim)
421
422 integer :: ix^d
423
424 {do ix^db=ixomin^db,ixomax^db\}
425 ! Convert velocity to momentum
426 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
427 {end do\}
428
429 end subroutine mhd_to_conserved_origin_noe
430
431 !> Transform primitive variables into conservative ones (hydrodynamic energy)
432 subroutine mhd_to_conserved_hde(ixI^L,ixO^L,w,x)
434 integer, intent(in) :: ixi^l, ixo^l
435 double precision, intent(inout) :: w(ixi^s, nw)
436 double precision, intent(in) :: x(ixi^s, 1:ndim)
437
438 integer :: ix^d
439
440 {do ix^db=ixomin^db,ixomax^db\}
441 ! Calculate total energy from pressure, kinetic and magnetic energy
442 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1&
443 +half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
444 ! Convert velocity to momentum
445 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
446 {end do\}
447
448 end subroutine mhd_to_conserved_hde
449
450 !> Transform primitive variables into conservative ones (internal energy)
451 subroutine mhd_to_conserved_inte(ixI^L,ixO^L,w,x)
453 integer, intent(in) :: ixi^l, ixo^l
454 double precision, intent(inout) :: w(ixi^s, nw)
455 double precision, intent(in) :: x(ixi^s, 1:ndim)
456
457 integer :: ix^d
458
459 {do ix^db=ixomin^db,ixomax^db\}
460 ! Calculate internal energy from pressure
461 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1
462 ! Convert velocity to momentum
463 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
464 {end do\}
465
466 end subroutine mhd_to_conserved_inte
467
468 !> Transform primitive variables into conservative ones (split rho)
469 subroutine mhd_to_conserved_split_rho(ixI^L,ixO^L,w,x)
471 integer, intent(in) :: ixi^l, ixo^l
472 double precision, intent(inout) :: w(ixi^s, nw)
473 double precision, intent(in) :: x(ixi^s, 1:ndim)
474
475 double precision :: rho
476 integer :: ix^d
477
478 {do ix^db=ixomin^db,ixomax^db\}
479 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i)
480 ! Calculate total energy from pressure, kinetic and magnetic energy
481 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1&
482 +half*((^c&w(ix^d,m^c_)**2+)*rho&
483 +(^c&w(ix^d,b^c_)**2+))
484 ! Convert velocity to momentum
485 ^c&w(ix^d,m^c_)=rho*w(ix^d,m^c_)\
486 {end do\}
487
488 end subroutine mhd_to_conserved_split_rho
489
490 !> Transform primitive variables into conservative ones (semirelativistic)
491 subroutine mhd_to_conserved_semirelati(ixI^L,ixO^L,w,x)
493 integer, intent(in) :: ixi^l, ixo^l
494 double precision, intent(inout) :: w(ixi^s, nw)
495 double precision, intent(in) :: x(ixi^s, 1:ndim)
496
497 double precision :: e(ixo^s,1:ndir), s(ixo^s,1:ndir)
498 integer :: ix^d
499
500 {do ix^db=ixomin^db,ixomax^db\}
501 {^ifthreec
502 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
503 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
504 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
505 s(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
506 s(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
507 s(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
508 }
509 {^iftwoc
510 e(ix^d,1)=zero
511 ! switch 3 with 2 to add 3 when ^C from 1 to 2
512 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
513 s(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
514 s(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
515 }
516 {^ifonec
517 e(ix^d,1)=zero
518 s(ix^d,1)=zero
519 }
520 if(mhd_internal_e) then
521 ! internal energy
522 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1
523 else
524 ! equation (9)
525 ! Calculate total energy from internal, kinetic and magnetic energy
526 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1&
527 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
528 +(^c&w(ix^d,b^c_)**2+)&
529 +(^c&e(ix^d,^c)**2+)*eos%inv_squared_c)
530 end if
531
532 ! Convert velocity to momentum, equation (9)
533 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*eos%inv_squared_c\
534
535 {end do\}
536
537 end subroutine mhd_to_conserved_semirelati
538
539 subroutine mhd_to_conserved_semirelati_noe(ixI^L,ixO^L,w,x)
541 integer, intent(in) :: ixi^l, ixo^l
542 double precision, intent(inout) :: w(ixi^s, nw)
543 double precision, intent(in) :: x(ixi^s, 1:ndim)
544
545 double precision :: e(ixo^s,1:ndir), s(ixo^s,1:ndir)
546 integer :: ix^d
547
548 {do ix^db=ixomin^db,ixomax^db\}
549 {^ifthreec
550 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
551 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
552 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
553 s(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
554 s(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
555 s(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
556 }
557 {^iftwoc
558 e(ix^d,1)=zero
559 ! switch 3 with 2 to add 3 when ^C from 1 to 2
560 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
561 s(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
562 s(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
563 }
564 {^ifonec
565 s(ix^d,1)=zero
566 }
567 ! Convert velocity to momentum, equation (9)
568 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*eos%inv_squared_c\
569
570 {end do\}
571
572 end subroutine mhd_to_conserved_semirelati_noe
573
574 !> Transform conservative variables into primitive ones (origin)
575 subroutine mhd_to_primitive_origin(ixI^L,ixO^L,w,x)
577 integer, intent(in) :: ixi^l, ixo^l
578 double precision, intent(inout) :: w(ixi^s, nw)
579 double precision, intent(in) :: x(ixi^s, 1:ndim)
580
581 double precision :: inv_rho
582 integer :: ix^d
583
584 if (fix_small_values) then
585 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin')
586 end if
587
588 {do ix^db=ixomin^db,ixomax^db\}
589 inv_rho = 1.d0/w(ix^d,rho_)
590 ! Convert momentum to velocity
591 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
592 ! Calculate pressure = (gamma-1) * (e-ek-eb)
593 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
594 -half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)&
595 +(^c&w(ix^d,b^c_)**2+))&
596 -mhd_uawsom_wave_energy_cell(w(ix^d,:)))
597 {end do\}
598
599 end subroutine mhd_to_primitive_origin
600
601 !> Transform conservative variables into primitive ones (no energy)
602 subroutine mhd_to_primitive_origin_noe(ixI^L,ixO^L,w,x)
604 integer, intent(in) :: ixi^l, ixo^l
605 double precision, intent(inout) :: w(ixi^s, nw)
606 double precision, intent(in) :: x(ixi^s, 1:ndim)
607
608 double precision :: inv_rho
609 integer :: ix^d
610
611 if (fix_small_values) then
612 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin_noe')
613 end if
614
615 {do ix^db=ixomin^db,ixomax^db\}
616 inv_rho = 1.d0/w(ix^d,rho_)
617 ! Convert momentum to velocity
618 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
619 {end do\}
620
621 end subroutine mhd_to_primitive_origin_noe
622
623 !> Transform conservative variables into primitive ones (hde)
624 subroutine mhd_to_primitive_hde(ixI^L,ixO^L,w,x)
626 integer, intent(in) :: ixi^l, ixo^l
627 double precision, intent(inout) :: w(ixi^s, nw)
628 double precision, intent(in) :: x(ixi^s, 1:ndim)
629
630 double precision :: inv_rho
631 integer :: ix^d
632
633 if (fix_small_values) then
634 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_hde')
635 end if
636
637 {do ix^db=ixomin^db,ixomax^db\}
638 inv_rho = 1.d0/w(ix^d,rho_)
639 ! Convert momentum to velocity
640 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
641 ! Calculate pressure = (gamma-1) * (e-ek)
642 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)-half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+))
643 {end do\}
644
645 end subroutine mhd_to_primitive_hde
646
647 !> Transform conservative variables into primitive ones (internal energy)
648 subroutine mhd_to_primitive_inte(ixI^L,ixO^L,w,x)
650 integer, intent(in) :: ixi^l, ixo^l
651 double precision, intent(inout) :: w(ixi^s, nw)
652 double precision, intent(in) :: x(ixi^s, 1:ndim)
653
654 double precision :: inv_rho
655 integer :: ix^d
656
657 if (fix_small_values) then
658 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_inte')
659 end if
660
661 {do ix^db=ixomin^db,ixomax^db\}
662 ! Calculate pressure = (gamma-1) * e_internal
663 w(ix^d,p_)=w(ix^d,e_)*eos%gamma_minus_1
664 ! Convert momentum to velocity
665 inv_rho = 1.d0/w(ix^d,rho_)
666 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
667 {end do\}
668
669 end subroutine mhd_to_primitive_inte
670
671 !> Transform conservative variables into primitive ones (split rho)
672 subroutine mhd_to_primitive_split_rho(ixI^L,ixO^L,w,x)
674 integer, intent(in) :: ixi^l, ixo^l
675 double precision, intent(inout) :: w(ixi^s, nw)
676 double precision, intent(in) :: x(ixi^s, 1:ndim)
677
678 double precision :: inv_rho
679 integer :: ix^d
680
681 if (fix_small_values) then
682 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_split_rho')
683 end if
684
685 {do ix^db=ixomin^db,ixomax^db\}
686 inv_rho=1.d0/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
687 ! Convert momentum to velocity
688 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
689 ! Calculate pressure = (gamma-1) * (e-ek-eb)
690 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
691 -half*((w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))*&
692 (^c&w(ix^d,m^c_)**2+)+(^c&w(ix^d,b^c_)**2+)))
693 {end do\}
694
695 end subroutine mhd_to_primitive_split_rho
696
697 !> Transform conservative variables into primitive ones (semirelativistic)
698 subroutine mhd_to_primitive_semirelati(ixI^L,ixO^L,w,x)
700 integer, intent(in) :: ixi^l, ixo^l
701 double precision, intent(inout) :: w(ixi^s, nw)
702 double precision, intent(in) :: x(ixi^s, 1:ndim)
703
704 double precision :: b(ixo^s,1:ndir), tmp, b2, gamma2, inv_rho
705 integer :: ix^d
706
707 if (fix_small_values) then
708 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati')
709 end if
710
711 {do ix^db=ixomin^db,ixomax^db\}
712 b2=(^c&w(ix^d,b^c_)**2+)
713 if(b2>smalldouble) then
714 tmp=1.d0/sqrt(b2)
715 else
716 tmp=0.d0
717 end if
718 ^c&b(ix^d,^c)=w(ix^d,b^c_)*tmp\
719 tmp=(^c&b(ix^d,^c)*w(ix^d,m^c_)+)
720
721 inv_rho=1.d0/w(ix^d,rho_)
722 ! Va^2/c^2
723 b2=b2*inv_rho*eos%inv_squared_c
724 ! equation (15)
725 gamma2=1.d0/(1.d0+b2)
726 ! Convert momentum to velocity
727 ^c&w(ix^d,m^c_)=gamma2*(w(ix^d,m^c_)+b2*b(ix^d,^c)*tmp)*inv_rho\
728
729 if(mhd_internal_e) then
730 ! internal energy to pressure
731 w(ix^d,p_)=eos%gamma_minus_1*w(ix^d,e_)
732 else
733 ! E=Bxv
734 {^ifthreec
735 b(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
736 b(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
737 b(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
738 }
739 {^iftwoc
740 b(ix^d,1)=zero
741 b(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
742 }
743 {^ifonec
744 b(ix^d,1)=zero
745 }
746 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
747 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
748 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
749 +(^c&w(ix^d,b^c_)**2+)&
750 +(^c&b(ix^d,^c)**2+)*eos%inv_squared_c))
751 end if
752 {end do\}
753
754 end subroutine mhd_to_primitive_semirelati
755
756 !> Transform conservative variables into primitive ones (semirelativistic noe)
757 subroutine mhd_to_primitive_semirelati_noe(ixI^L,ixO^L,w,x)
759 integer, intent(in) :: ixi^l, ixo^l
760 double precision, intent(inout) :: w(ixi^s, nw)
761 double precision, intent(in) :: x(ixi^s, 1:ndim)
762
763 double precision :: b(ixo^s,1:ndir),tmp,b2,gamma2,inv_rho
764 integer :: ix^d, idir
765
766 if (fix_small_values) then
767 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati_noe')
768 end if
769
770 {do ix^db=ixomin^db,ixomax^db\}
771 b2=(^c&w(ix^d,b^c_)**2+)
772 if(b2>smalldouble) then
773 tmp=1.d0/sqrt(b2)
774 else
775 tmp=0.d0
776 end if
777 ^c&b(ix^d,^c)=w(ix^d,b^c_)*tmp\
778 tmp=(^c&b(ix^d,^c)*w(ix^d,m^c_)+)
779
780 inv_rho=1.d0/w(ix^d,rho_)
781 ! Va^2/c^2
782 b2=b2*inv_rho*eos%inv_squared_c
783 ! equation (15)
784 gamma2=1.d0/(1.d0+b2)
785 ! Convert momentum to velocity
786 ^c&w(ix^d,m^c_)=gamma2*(w(ix^d,m^c_)+b2*b(ix^d,^c)*tmp)*inv_rho\
787 {end do\}
788
789 end subroutine mhd_to_primitive_semirelati_noe
790
791 !> LTE conversion routines
792
793 !> LTE: Primitive (rho, v, p, B) -> Conserved (rho, rho*v, E_total, B)
794 !> E_total = eint + 0.5*rho*v^2 + 0.5*B^2
795 subroutine mhd_to_conserved_origin_lte(ixI^L,ixO^L,w,x)
797 integer, intent(in) :: ixi^l, ixo^l
798 double precision, intent(inout) :: w(ixi^s, nw)
799 double precision, intent(in) :: x(ixi^s, 1:ndim)
800
801 timeeos0 = mpi_wtime()
802
803 ! Convert p -> E_total (eint + eK + eB) via EoS table
804 call mhd_p_to_e(ixi^l, ixo^l, w, x)
805 ! Convert velocity to momentum
806 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
807
808 timeeos_conv=timeeos_conv+(mpi_wtime()-timeeos0)
809
810 end subroutine mhd_to_conserved_origin_lte
811
812 !> LTE: Primitive (rho, v, p, B) -> Conserved (rho, rho*v, eint, B)
813 !> Internal energy formulation: e_ stores eint only
814 subroutine mhd_to_conserved_inte_lte(ixI^L,ixO^L,w,x)
816 integer, intent(in) :: ixi^l, ixo^l
817 double precision, intent(inout) :: w(ixi^s, nw)
818 double precision, intent(in) :: x(ixi^s, 1:ndim)
819
820 timeeos0 = mpi_wtime()
821
822 ! Convert p -> eint via EoS table (no mechanical energy)
823 call mhd_p_to_eint(ixi^l, ixo^l, w, x)
824 ! Convert velocity to momentum
825 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
826
827 timeeos_conv=timeeos_conv+(mpi_wtime()-timeeos0)
828
829 end subroutine mhd_to_conserved_inte_lte
830
831 !> Convert pressure to total energy (eint + eK + eB) for origin formulation.
832 !> Uses p2eint table for LTE ionE, with FI bypass for hot cells.
833 subroutine mhd_p_to_e(ixI^L,ixO^L,w,x)
835 integer, intent(in) :: ixi^l, ixo^l
836 double precision, intent(inout) :: w(ixi^s, nw)
837 double precision, intent(in) :: x(ixi^s, 1:ndim)
838
839 integer :: ix^d
840 double precision :: p_to_eint, p_over_rho
841 double precision :: nh(ixi^s), nh_in(ixi^s), p_in(ixi^s)
842 double precision :: t_solve, y_solve, eint_nh_solve
843 double precision :: log_eint_mid, eint_total
844
845 if (eos%ionE) then
846 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
847 nh_in(ixo^s) = dlog10(nh(ixo^s))
848 if (eos%p2eint_method /= 'bisect') then
849 p_in(ixo^s) = dlog10(w(ixo^s,p_)) - nh_in(ixo^s)
850 end if
851 endif
852
853 p_to_eint = eos%inv_gamma_minus_1
854 {do ix^db=ixomin^db,ixomax^db\}
855 if (eos%ionE) then
856 p_over_rho = w(ix^d,p_) / w(ix^d,rho_)
857 if (p_over_rho > eos%p_rho_FI_threshold) then
858 p_to_eint = eos%inv_gamma_minus_1 &
859 + eos%eion_per_nH * nh(ix^d) / w(ix^d,p_)
860 w(ix^d,e_)=w(ix^d,p_)*p_to_eint&
861 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
862 +(^c&w(ix^d,b^c_)**2+))
863 else if (eos%method == 'analytic') then
864 call saha_state_from_nh_p(nh(ix^d), w(ix^d,p_), &
865 t_solve, y_solve, eint_nh_solve)
866 w(ix^d,e_) = eint_nh_solve * nh(ix^d) &
867 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
868 +(^c&w(ix^d,b^c_)**2+))
869 else if (eos%p2eint_method == 'bisect') then
870 call eint_from_p_bisect(nh_in(ix^d), &
871 dlog10(w(ix^d,p_)), log_eint_mid)
872 eint_total = nh(ix^d) * 10.0d0**log_eint_mid
873 eint_total = max(eint_total, &
874 nh(ix^d) * 10.0d0**eos%T%var2_min)
875 w(ix^d,e_) = eint_total + &
876 half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
877 +(^c&w(ix^d,b^c_)**2+))
878 else
879 p_to_eint = p2eint_from_nh_p(nh_in(ix^d), p_in(ix^d))
880 w(ix^d,e_)=w(ix^d,p_)*p_to_eint&
881 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
882 +(^c&w(ix^d,b^c_)**2+))
883 end if
884 else
885 w(ix^d,e_)=w(ix^d,p_)*p_to_eint&
886 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
887 +(^c&w(ix^d,b^c_)**2+))
888 end if
889 if(mhd_uawsom) w(ix^d,e_)=w(ix^d,e_)+&
890 w(ix^d,waplus_)+w(ix^d,waminus_)+w(ix^d,wkplus_)+w(ix^d,wkminus_)
891 {end do\}
892
893 end subroutine mhd_p_to_e
894
895 !> Convert pressure to internal energy only (for internal_e formulation).
896 !> Uses p2eint table for LTE ionE, with FI bypass for hot cells.
897 subroutine mhd_p_to_eint(ixI^L,ixO^L,w,x)
899 integer, intent(in) :: ixi^l, ixo^l
900 double precision, intent(inout) :: w(ixi^s, nw)
901 double precision, intent(in) :: x(ixi^s, 1:ndim)
902
903 integer :: ix^d
904 double precision :: p_to_eint, p_over_rho
905 double precision :: nh(ixi^s), nh_in(ixi^s), p_in(ixi^s)
906 double precision :: t_solve, y_solve, eint_nh_solve
907 double precision :: log_eint_mid, eint_total
908
909 if (eos%ionE) then
910 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
911 nh_in(ixo^s) = dlog10(nh(ixo^s))
912 if (eos%p2eint_method /= 'bisect') then
913 p_in(ixo^s) = dlog10(w(ixo^s,p_)) - nh_in(ixo^s)
914 end if
915 endif
916
917 p_to_eint = eos%inv_gamma_minus_1
918 {do ix^db=ixomin^db,ixomax^db\}
919 if (eos%ionE) then
920 p_over_rho = w(ix^d,p_) / w(ix^d,rho_)
921 if (p_over_rho > eos%p_rho_FI_threshold) then
922 p_to_eint = eos%inv_gamma_minus_1 &
923 + eos%eion_per_nH * nh(ix^d) / w(ix^d,p_)
924 w(ix^d,e_) = w(ix^d,p_) * p_to_eint
925 else if (eos%method == 'analytic') then
926 call saha_state_from_nh_p(nh(ix^d), w(ix^d,p_), &
927 t_solve, y_solve, eint_nh_solve)
928 w(ix^d,e_) = eint_nh_solve * nh(ix^d)
929 else if (eos%p2eint_method == 'bisect') then
930 call eint_from_p_bisect(nh_in(ix^d), &
931 dlog10(w(ix^d,p_)), log_eint_mid)
932 eint_total = nh(ix^d) * 10.0d0**log_eint_mid
933 eint_total = max(eint_total, &
934 nh(ix^d) * 10.0d0**eos%T%var2_min)
935 w(ix^d,e_) = eint_total
936 else
937 p_to_eint = p2eint_from_nh_p(nh_in(ix^d), p_in(ix^d))
938 w(ix^d,e_) = w(ix^d,p_) * p_to_eint
939 end if
940 else
941 w(ix^d,e_) = w(ix^d,p_) * p_to_eint
942 end if
943 {end do\}
944
945 end subroutine mhd_p_to_eint
946
947 !> LTE: Conserved (rho, rho*v, E_total, B) -> Primitive (rho, v, p, B)
948 !> Uses T and neOnH tables with FI bypass for hot cells.
949 subroutine mhd_to_primitive_origin_lte(ixI^L,ixO^L,w,x)
951 integer, intent(in) :: ixi^l, ixo^l
952 double precision, intent(inout) :: w(ixi^s, nw)
953 double precision, intent(in) :: x(ixi^s, 1:ndim)
954
955 double precision :: inv_rho, eint_val, eint_in
956 double precision :: nh(ixi^s), log_nh(ixi^s)
957 integer :: ix^d
958
959 timeeos0 = mpi_wtime()
960
961 if (fix_small_values) then
962 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, &
963 'mhd_to_primitive_origin_LTE')
964 end if
965
966 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
967 if (eos%ionE) then
968 log_nh(ixo^s) = dlog10(nh(ixo^s))
969 end if
970
971 {do ix^db=ixomin^db,ixomax^db\}
972 inv_rho = 1.d0/w(ix^d,rho_)
973 ! Convert momentum to velocity
974 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
975 ! Extract internal energy: eint = E - 0.5*rho*v^2 - 0.5*B^2
976 eint_val = w(ix^d,e_) &
977 - half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+) &
978 + (^c&w(ix^d,b^c_)**2+))
979 ! Floor eint to prevent unphysical values
980 if (eos%method /= 'analytic') then
981 eint_val = max(eint_val, nh(ix^d) * 10.0d0**eos%T%var2_min)
982 end if
983 eint_val = max(eint_val, smalldouble)
984
985 if (eos%ionE) then
986 if (eint_val * inv_rho > eos%eint_rho_FI_threshold) then
987 ! FI bypass: p = (gamma-1) * (eint - eion*nH)
988 w(ix^d,p_) = eos%gamma_minus_1 &
989 * (eint_val - eos%eion_per_nH * nh(ix^d))
990 else
991 ! Ionisation zone: single p/nH lookup (replaces separate T + y)
992 eint_in = dlog10(eint_val) - log_nh(ix^d)
993 w(ix^d,p_) = nh(ix^d) * p_nh_from_eint(log_nh(ix^d), eint_in)
994 end if
995 else
996 ! FI without ionE tables
997 w(ix^d,p_) = eos%gamma_minus_1 * eint_val
998 end if
999 {end do\}
1000
1001 timeeos_conv=timeeos_conv+(mpi_wtime()-timeeos0)
1002
1003 end subroutine mhd_to_primitive_origin_lte
1004
1005 !> LTE: Conserved (rho, rho*v, eint, B) -> Primitive (rho, v, p, B)
1006 !> Internal energy formulation: eint = w(e_) directly.
1007 subroutine mhd_to_primitive_inte_lte(ixI^L,ixO^L,w,x)
1009 integer, intent(in) :: ixi^l, ixo^l
1010 double precision, intent(inout) :: w(ixi^s, nw)
1011 double precision, intent(in) :: x(ixi^s, 1:ndim)
1012
1013 double precision :: inv_rho, eint_val, eint_in, t_loc, y_loc
1014 double precision :: nh(ixi^s), log_nh(ixi^s)
1015 integer :: ix^d
1016
1017 timeeos0 = mpi_wtime()
1018
1019 if (fix_small_values) then
1020 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, &
1021 'mhd_to_primitive_inte_LTE')
1022 end if
1023
1024 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
1025 if (eos%ionE) then
1026 log_nh(ixo^s) = dlog10(nh(ixo^s))
1027 end if
1028
1029 {do ix^db=ixomin^db,ixomax^db\}
1030 ! eint = w(e_) directly for internal energy formulation
1031 eint_val = w(ix^d,e_)
1032 eint_val = max(eint_val, nh(ix^d) * 10.0d0**eos%T%var2_min)
1033
1034 if (eos%ionE) then
1035 if (eint_val / w(ix^d,rho_) > eos%eint_rho_FI_threshold) then
1036 w(ix^d,p_) = eos%gamma_minus_1 &
1037 * (eint_val - eos%eion_per_nH * nh(ix^d))
1038 else
1039 eint_in = dlog10(eint_val) - log_nh(ix^d)
1040 w(ix^d,p_) = nh(ix^d) * p_nh_from_eint(log_nh(ix^d), eint_in)
1041 end if
1042 else
1043 w(ix^d,p_) = eos%gamma_minus_1 * eint_val
1044 end if
1045
1046 ! Convert momentum to velocity
1047 inv_rho = 1.d0/w(ix^d,rho_)
1048 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1049 {end do\}
1050
1051 timeeos_conv=timeeos_conv+(mpi_wtime()-timeeos0)
1052
1053 end subroutine mhd_to_primitive_inte_lte
1054
1055 !> LTE prolongation routines
1056
1057 !> Convert conserved (rho, rho*v, E_total, B) to prolongation form (rho, v, T, B).
1058 !> Temperature is stored in the p_ slot for AMR interpolation.
1059 !> T is smoothest through the ionisation zone (conduction-dominated, linear gradient).
1060 subroutine mhd_to_prolong_lte(ixI^L,ixO^L,w,x)
1062 integer, intent(in) :: ixi^l, ixo^l
1063 double precision, intent(inout) :: w(ixi^s, nw)
1064 double precision, intent(in) :: x(ixi^s, 1:ndim)
1065
1066 double precision :: inv_rho, eint_val, t_loc, y_loc
1067 double precision :: nh(ixi^s), log_nh(ixi^s)
1068 integer :: ix^d
1069
1070 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
1071 log_nh(ixo^s) = dlog10(nh(ixo^s))
1072
1073 {do ix^db=ixomin^db,ixomax^db\}
1074 inv_rho = 1.d0/w(ix^d,rho_)
1075 ! Convert momentum to velocity
1076 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1077 if (mhd_internal_e) then
1078 eint_val = w(ix^d,e_)
1079 else
1080 ! Compute eint = E - 0.5*rho*v^2 - 0.5*B^2
1081 eint_val = w(ix^d,e_) &
1082 - half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+) &
1083 + (^c&w(ix^d,b^c_)**2+))
1084 end if
1085 ! Floor eint to prevent unphysical values
1086 if (eos%method /= 'analytic') then
1087 eint_val = max(eint_val, nh(ix^d) * 10.0d0**eos%T%var2_min)
1088 end if
1089 eint_val = max(eint_val, smalldouble)
1090
1091 if (eint_val * inv_rho > eos%eint_rho_FI_threshold) then
1092 ! FI: T = (gamma-1)*(eint - eion*nH) / (nH * n_per_nH_FI)
1093 w(ix^d,p_) = eos%gamma_minus_1 &
1094 * (eint_val - eos%eion_per_nH * nh(ix^d)) &
1095 / (nh(ix^d) * eos%n_per_nH_FI)
1096 else if (eos%method == 'analytic') then
1097 ! Analytical Saha: solve for T from eint
1098 call saha_t_from_nh_eint(nh(ix^d), &
1099 eint_val / nh(ix^d), t_loc, y_loc)
1100 w(ix^d,p_) = t_loc
1101 else
1102 ! Ionisation zone: T from table
1103 w(ix^d,p_) = t_from_nh_eint( &
1104 log_nh(ix^d), &
1105 dlog10(eint_val) - log_nh(ix^d))
1106 end if
1107 {end do\}
1108
1109 end subroutine mhd_to_prolong_lte
1110
1111 !> Convert prolongation form (rho, v, T, B) to conserved (rho, rho*v, E_total, B).
1112 !> T is read from the p_ slot. Uses eint_nH_from_T table for back-conversion.
1113 subroutine mhd_from_prolong_lte(ixI^L,ixO^L,w,x)
1115 integer, intent(in) :: ixi^l, ixo^l
1116 double precision, intent(inout) :: w(ixi^s, nw)
1117 double precision, intent(in) :: x(ixi^s, 1:ndim)
1118
1119 double precision :: t_val, eint_val, t_fi, log_t_min
1120 double precision :: nh(ixi^s), log_nh(ixi^s)
1121 integer :: ix^d
1122
1123 ! Temperature above which gas is fully ionised
1124 t_fi = (eos%eint_rho_FI_threshold &
1125 * eos%nH2rhoFactor - eos%eion_per_nH) &
1126 * eos%gamma_minus_1 / eos%n_per_nH_FI
1127
1128 ! Floor for log_T into the (rho, T) inverse table; entropy method uses
1129 ! eos%eintT, legacy 'tables' method uses eos%eint_from_T. Picking the
1130 ! wrong container leaves var2_min = 0 → floors T at 10^6 K.
1131 if (eos%method == 'entropy') then
1132 log_t_min = eos%eintT%var2_min
1133 else
1134 log_t_min = eos%eint_from_T%var2_min
1135 end if
1136
1137 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
1138 log_nh(ixo^s) = dlog10(nh(ixo^s))
1139
1140 {do ix^db=ixomin^db,ixomax^db\}
1141 t_val = w(ix^d,p_) ! T stored in p_ slot
1142 if (t_val > t_fi) then
1143 ! FI: eint = nH*(n_per_nH*T/(gamma-1) + eion)
1144 eint_val = nh(ix^d) &
1145 * (eos%n_per_nH_FI * t_val * eos%inv_gamma_minus_1 &
1146 + eos%eion_per_nH)
1147 else if (eos%method == 'analytic') then
1148 ! Analytical Saha: eint from T directly
1149 eint_val = saha_eint_from_nh_t(nh(ix^d), t_val) * nh(ix^d)
1150 else
1151 ! Ionisation zone: eint/nH from T table
1152 eint_val = eint_nh_from_t( &
1153 log_nh(ix^d), &
1154 dlog10(max(t_val, 10.0d0**log_t_min))) &
1155 * nh(ix^d)
1156 end if
1157 if (mhd_internal_e) then
1158 w(ix^d,e_) = eint_val
1159 else
1160 ! E = eint + 0.5*rho*v^2 + 0.5*B^2
1161 w(ix^d,e_) = eint_val &
1162 + half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+) &
1163 + (^c&w(ix^d,b^c_)**2+))
1164 end if
1165 ! Convert velocity to momentum
1166 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1167 {end do\}
1168
1169 end subroutine mhd_from_prolong_lte
1170
1171 !> Sound speed routines
1172
1173 !> Acoustic sound speed squared for FI (constant gamma) EoS.
1174 !> Expects w in primitive form: w(p_) = pressure, w(rho_) = density.
1175 subroutine mhd_get_csound2_fi(w, x, ixI^L, ixO^L, cs2)
1177 integer, intent(in) :: ixi^l, ixo^l
1178 double precision, intent(in) :: w(ixi^s, nw)
1179 double precision, intent(in) :: x(ixi^s, 1:ndim)
1180 double precision, intent(out) :: cs2(ixi^s)
1181
1182 double precision :: rho(ixi^s), pth(ixi^s)
1183
1184 timeeos0 = mpi_wtime()
1185
1186 !> Both slots hold perturbations under equilibrium splitting, so the
1187 !> background is restored before the ratio is formed.
1188 call eos%get_rho(w, x, ixi^l, ixo^l, rho)
1189 pth(ixo^s) = w(ixo^s, p_)
1190 if (iw_equi_p > 0) pth(ixo^s) = pth(ixo^s) &
1191 + block%equi_vars(ixo^s, iw_equi_p, b0i)
1192 cs2(ixo^s) = eos%gamma * pth(ixo^s) / rho(ixo^s)
1193
1194 timeeos_csound = timeeos_csound + (mpi_wtime()-timeeos0)
1195
1196 end subroutine mhd_get_csound2_fi
1197
1198 !> Acoustic sound speed squared for LTE+IonE EoS using Gamma_1 table.
1199 !> Expects w in primitive form. Uses FI bypass for hot cells.
1200 subroutine mhd_get_csound2_lte(w, x, ixI^L, ixO^L, cs2)
1202 integer, intent(in) :: ixi^l, ixo^l
1203 double precision, intent(in) :: w(ixi^s, nw)
1204 double precision, intent(in) :: x(ixi^s, 1:ndim)
1205 double precision, intent(out) :: cs2(ixi^s)
1206
1207 double precision :: nh_val, log_nh, log_p_nh, g1, p_over_rho
1208 integer :: ix^d
1209
1210 timeeos0 = mpi_wtime()
1211
1212 if (eos%gamma1_method == 'constant') then
1213 cs2(ixo^s) = eos%gamma * w(ixo^s, p_) / w(ixo^s, rho_)
1214 else
1215 {do ix^db=ixomin^db,ixomax^db\}
1216 p_over_rho = w(ix^d, p_) / w(ix^d, rho_)
1217 if (p_over_rho > eos%p_rho_FI_threshold) then
1218 cs2(ix^d) = eos%gamma * p_over_rho
1219 else
1220 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
1221 if (eos%method == 'analytic') then
1222 if (iw_te > 0 .and. w(ix^d,iw_te) > 0.0d0) then
1223 g1 = saha_gamma1_from_nh_t(nh_val, w(ix^d,iw_te))
1224 else
1225 g1 = eos%gamma
1226 end if
1227 else
1228 log_nh = dlog10(nh_val)
1229 log_p_nh = dlog10(w(ix^d, p_) / nh_val)
1230 g1 = gamma1_from_nh_p(log_nh, log_p_nh)
1231 end if
1232 cs2(ix^d) = g1 * p_over_rho
1233 end if
1234 {end do\}
1235 end if
1236
1237 timeeos_csound = timeeos_csound + (mpi_wtime()-timeeos0)
1238
1239 end subroutine mhd_get_csound2_lte
1240
1241 subroutine mhd_get_gamma1_lte(w, x, ixI^L, ixO^L, gamma1)
1243 integer, intent(in) :: ixi^l, ixo^l
1244 double precision, intent(in) :: w(ixi^s, nw)
1245 double precision, intent(in) :: x(ixi^s, 1:ndim)
1246 double precision, intent(out) :: gamma1(ixi^s)
1247
1248 double precision :: nh_val, p_over_rho
1249 integer :: ix^d
1250
1251 if (eos%gamma1_method == 'constant') then
1252 gamma1(ixo^s) = eos%gamma
1253 return
1254 end if
1255
1256 {do ix^db=ixomin^db,ixomax^db\}
1257 p_over_rho = w(ix^d, p_) / w(ix^d, rho_)
1258 if (p_over_rho > eos%p_rho_FI_threshold) then
1259 gamma1(ix^d) = eos%gamma
1260 else
1261 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
1262 if (eos%method == 'analytic') then
1263 if (iw_te > 0 .and. w(ix^d,iw_te) > 0.0d0) then
1264 gamma1(ix^d) = saha_gamma1_from_nh_t(nh_val, w(ix^d,iw_te))
1265 else
1266 gamma1(ix^d) = eos%gamma
1267 end if
1268 else
1269 gamma1(ix^d) = gamma1_from_nh_p(dlog10(nh_val), &
1270 dlog10(w(ix^d, p_) / nh_val))
1271 end if
1272 end if
1273 {end do\}
1274
1275 end subroutine mhd_get_gamma1_lte
1276
1277 !> Rfactor routines (matching HD: EoS functions live in EoS module)
1278
1279 !> Rfactor = p/(rho*T) for constant ionisation degree (FI/PI no-energy).
1280 !> Stays in the seam: RR is the physics module's gas-constant factor, not
1281 !> visible to mod_eos. Rfactor_from_LTE lives in mod_eos (no RR).
1282 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
1284 integer, intent(in) :: ixi^l, ixo^l
1285 double precision, intent(in) :: w(ixi^s,1:nw)
1286 double precision, intent(in) :: x(ixi^s,1:ndim)
1287 double precision, intent(out):: rfactor(ixi^s)
1288
1289 rfactor(ixo^s)=rr
1290
1291 end subroutine rfactor_from_constant_ionization
1292
1293 !> Rfactor from partial ionisation temperature lookup (Leenaarts et al. 2012)
1294
1295 !> Thermal pressure routines (moved from mod_mhd_phys.t)
1296
1297 !> Calculate isothermal thermal pressure
1298 subroutine mhd_get_pthermal_noe(w,x,ixI^L,ixO^L,pth)
1300
1301 integer, intent(in) :: ixi^l, ixo^l
1302 double precision, intent(in) :: w(ixi^s,nw)
1303 double precision, intent(in) :: x(ixi^s,1:ndim)
1304 double precision, intent(out):: pth(ixi^s)
1305
1306 if(has_equi_rho_and_p) then
1307 pth(ixo^s)=mhd_adiab*(w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0))**eos%gamma
1308 else
1309 pth(ixo^s)=mhd_adiab*w(ixo^s,rho_)**eos%gamma
1310 end if
1311
1312 end subroutine mhd_get_pthermal_noe
1313
1314 !> Calculate thermal pressure from internal energy
1315 subroutine mhd_get_pthermal_inte(w,x,ixI^L,ixO^L,pth)
1318
1319 integer, intent(in) :: ixi^l, ixo^l
1320 double precision, intent(in) :: w(ixi^s,nw)
1321 double precision, intent(in) :: x(ixi^s,1:ndim)
1322 double precision, intent(out):: pth(ixi^s)
1323
1324 integer :: iw, ix^d
1325
1326 {do ix^db= ixomin^db,ixomax^db\}
1327 if(has_equi_rho_and_p) then
1328 pth(ix^d)=eos%gamma_minus_1*w(ix^d,e_)+block%equi_vars(ix^d,equi_pe0_,0)
1329 else
1330 pth(ix^d)=eos%gamma_minus_1*w(ix^d,e_)
1331 end if
1332 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1333 {end do\}
1334
1335 if(check_small_values.and..not.fix_small_values) then
1336 {do ix^db= ixomin^db,ixomax^db\}
1337 if(pth(ix^d)<small_pressure) then
1338 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1339 " encountered when call mhd_get_pthermal_inte"
1340 write(*,*) "Iteration: ", it, " Time: ", global_time
1341 write(*,*) "Location: ", x(ix^d,:)
1342 write(*,*) "Cell number: ", ix^d
1343 do iw=1,nw
1344 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1345 end do
1346 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1347 write(*,*) "Saving status at the previous time step"
1348 crash=.true.
1349 end if
1350 {end do\}
1351 end if
1352
1353 end subroutine mhd_get_pthermal_inte
1354
1355 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L
1356 subroutine mhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
1359
1360 integer, intent(in) :: ixi^l, ixo^l
1361 double precision, intent(in) :: w(ixi^s,nw)
1362 double precision, intent(in) :: x(ixi^s,1:ndim)
1363 double precision, intent(out):: pth(ixi^s)
1364
1365 integer :: iw, ix^d
1366
1367 {do ix^db=ixomin^db,ixomax^db\}
1368 if(has_equi_rho_and_p) then
1369 pth(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
1370 +(^c&w(ix^d,b^c_)**2+)))+block%equi_vars(ix^d,equi_pe0_,0)
1371 else
1372 pth(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
1373 +(^c&w(ix^d,b^c_)**2+))-mhd_uawsom_wave_energy_cell(w(ix^d,:)))
1374 end if
1375 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1376 {end do\}
1377
1378 if(check_small_values.and..not.fix_small_values) then
1379 {do ix^db=ixomin^db,ixomax^db\}
1380 if(pth(ix^d)<small_pressure) then
1381 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1382 " encountered when call mhd_get_pthermal"
1383 write(*,*) "Iteration: ", it, " Time: ", global_time
1384 write(*,*) "Location: ", x(ix^d,:)
1385 write(*,*) "Cell number: ", ix^d
1386 do iw=1,nw
1387 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1388 end do
1389 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1390 write(*,*) "Saving status at the previous time step"
1391 crash=.true.
1392 end if
1393 {end do\}
1394 end if
1395
1396 end subroutine mhd_get_pthermal_origin
1397
1398 !> Calculate thermal pressure for LTE EoS (delegates to eos%get_thermal_pressure)
1399 subroutine mhd_get_pthermal_lte(w,x,ixI^L,ixO^L,pth)
1402
1403 integer, intent(in) :: ixi^l, ixo^l
1404 double precision, intent(in) :: w(ixi^s,nw)
1405 double precision, intent(in) :: x(ixi^s,1:ndim)
1406 double precision, intent(out):: pth(ixi^s)
1407 double precision :: nh(ixi^s)
1408
1409 integer :: iw, ix^d
1410
1411 ! LTE: p = nH * (1 + He + ne/nH) * T from stored state variables
1412 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
1413 pth(ixo^s) = nh(ixo^s) * (1.0d0 + eos%He_abundance &
1414 + (w(ixo^s,ne_) / nh(ixo^s))) * w(ixo^s,te_)
1415
1416 if(fix_small_values) then
1417 {do ix^db=ixomin^db,ixomax^db\}
1418 if(pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1419 {end do\}
1420 else if(check_small_values) then
1421 {do ix^db=ixomin^db,ixomax^db\}
1422 if(pth(ix^d)<small_pressure) then
1423 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1424 " encountered when call mhd_get_pthermal_LTE"
1425 write(*,*) "Iteration: ", it, " Time: ", global_time
1426 write(*,*) "Location: ", x(ix^d,:)
1427 write(*,*) "Cell number: ", ix^d
1428 do iw=1,nw
1429 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1430 end do
1431 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1432 write(*,*) "Saving status at the previous time step"
1433 crash=.true.
1434 end if
1435 {end do\}
1436 end if
1437
1438 end subroutine mhd_get_pthermal_lte
1439
1440 !> Calculate thermal pressure for semirelativistic MHD
1441 subroutine mhd_get_pthermal_semirelati(w,x,ixI^L,ixO^L,pth)
1444
1445 integer, intent(in) :: ixi^l, ixo^l
1446 double precision, intent(in) :: w(ixi^s,nw)
1447 double precision, intent(in) :: x(ixi^s,1:ndim)
1448 double precision, intent(out):: pth(ixi^s)
1449
1450 double precision :: b(ixo^s,1:ndir), v(ixo^s,1:ndir), tmp, b2, gamma2, inv_rho
1451 integer :: iw, ix^d
1452
1453 {do ix^db=ixomin^db,ixomax^db\}
1454 b2=(^c&w(ix^d,b^c_)**2+)
1455 if(b2>smalldouble) then
1456 tmp=1.d0/sqrt(b2)
1457 else
1458 tmp=0.d0
1459 end if
1460 ^c&b(ix^d,^c)=w(ix^d,b^c_)*tmp\
1461 tmp=(^c&b(ix^d,^c)*w(ix^d,m^c_)+)
1462
1463 inv_rho=1.d0/w(ix^d,rho_)
1464 ! Va^2/c^2
1465 b2=b2*inv_rho*eos%inv_squared_c
1466 ! equation (15)
1467 gamma2=1.d0/(1.d0+b2)
1468 ! Convert momentum to velocity
1469 ^c&v(ix^d,^c)=gamma2*(w(ix^d,m^c_)+b2*b(ix^d,^c)*tmp)*inv_rho\
1470
1471 ! E=Bxv
1472 {^ifthreec
1473 b(ix^d,1)=w(ix^d,b2_)*v(ix^d,3)-w(ix^d,b3_)*v(ix^d,2)
1474 b(ix^d,2)=w(ix^d,b3_)*v(ix^d,1)-w(ix^d,b1_)*v(ix^d,3)
1475 b(ix^d,3)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
1476 }
1477 {^iftwoc
1478 b(ix^d,1)=zero
1479 b(ix^d,2)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
1480 }
1481 {^ifonec
1482 b(ix^d,1)=zero
1483 }
1484 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
1485 pth(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)&
1486 -half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
1487 +(^c&w(ix^d,b^c_)**2+)&
1488 +(^c&b(ix^d,^c)**2+)*eos%inv_squared_c))
1489 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1490 {end do\}
1491
1492 if(check_small_values.and..not.fix_small_values) then
1493 {do ix^db=ixomin^db,ixomax^db\}
1494 if(pth(ix^d)<small_pressure) then
1495 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1496 " encountered when call mhd_get_pthermal_semirelati"
1497 write(*,*) "Iteration: ", it, " Time: ", global_time
1498 write(*,*) "Location: ", x(ix^d,:)
1499 write(*,*) "Cell number: ", ix^d
1500 do iw=1,nw
1501 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1502 end do
1503 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1504 write(*,*) "Saving status at the previous time step"
1505 crash=.true.
1506 end if
1507 {end do\}
1508 end if
1509
1510 end subroutine mhd_get_pthermal_semirelati
1511
1512 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho) within ixO^L
1513 subroutine mhd_get_pthermal_hde(w,x,ixI^L,ixO^L,pth)
1516
1517 integer, intent(in) :: ixi^l, ixo^l
1518 double precision, intent(in) :: w(ixi^s,nw)
1519 double precision, intent(in) :: x(ixi^s,1:ndim)
1520 double precision, intent(out):: pth(ixi^s)
1521
1522 integer :: iw, ix^d
1523
1524 {do ix^db= ixomin^db,ixomax^db\}
1525 pth(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)))
1526 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1527 {end do\}
1528 if(check_small_values.and..not.fix_small_values) then
1529 {do ix^db= ixomin^db,ixomax^db\}
1530 if(pth(ix^d)<small_pressure) then
1531 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1532 " encountered when call mhd_get_pthermal_hde"
1533 write(*,*) "Iteration: ", it, " Time: ", global_time
1534 write(*,*) "Location: ", x(ix^d,:)
1535 write(*,*) "Cell number: ", ix^d
1536 do iw=1,nw
1537 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1538 end do
1539 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1540 write(*,*) "Saving status at the previous time step"
1541 crash=.true.
1542 end if
1543 {end do\}
1544 end if
1545
1546 end subroutine mhd_get_pthermal_hde
1547
1548 !> Temperature routines (moved from mod_mhd_phys.t)
1549
1550 !> Copy temperature from stored Te variable
1551 subroutine mhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
1553 integer, intent(in) :: ixi^l, ixo^l
1554 double precision, intent(in) :: w(ixi^s, 1:nw)
1555 double precision, intent(in) :: x(ixi^s, 1:ndim)
1556 double precision, intent(out):: res(ixi^s)
1557 res(ixo^s) = w(ixo^s, te_)
1558 end subroutine mhd_get_temperature_from_te
1559
1560 !> Calculate temperature=p/rho when in e_ the internal energy is stored
1561 subroutine mhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
1563 integer, intent(in) :: ixi^l, ixo^l
1564 double precision, intent(in) :: w(ixi^s, 1:nw)
1565 double precision, intent(in) :: x(ixi^s, 1:ndim)
1566 double precision, intent(out):: res(ixi^s)
1567
1568 double precision :: r(ixi^s)
1569
1570 call eos%get_Rfactor(w,x,ixi^l,ixo^l,r)
1571 res(ixo^s) = eos%gamma_minus_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
1572 end subroutine mhd_get_temperature_from_eint
1573
1574 !> Calculate temperature=p/rho when in e_ the total energy is stored
1575 subroutine mhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
1577 integer, intent(in) :: ixi^l, ixo^l
1578 double precision, intent(in) :: w(ixi^s, 1:nw)
1579 double precision, intent(in) :: x(ixi^s, 1:ndim)
1580 double precision, intent(out):: res(ixi^s)
1581
1582 double precision :: r(ixi^s)
1583
1584 call eos%get_Rfactor(w,x,ixi^l,ixo^l,r)
1585 call mhd_get_pthermal(w,x,ixi^l,ixo^l,res)
1586 res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
1587
1588 end subroutine mhd_get_temperature_from_etot
1589
1590 subroutine mhd_get_temperature_from_etot_with_equi(w, x, ixI^L, ixO^L, res)
1592 integer, intent(in) :: ixi^l, ixo^l
1593 double precision, intent(in) :: w(ixi^s, 1:nw)
1594 double precision, intent(in) :: x(ixi^s, 1:ndim)
1595 double precision, intent(out):: res(ixi^s)
1596
1597 double precision :: r(ixi^s)
1598
1599 call eos%get_Rfactor(w,x,ixi^l,ixo^l,r)
1600 call mhd_get_pthermal(w,x,ixi^l,ixo^l,res)
1601 res(ixo^s)=res(ixo^s)/(r(ixo^s)*(w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,b0i)))
1602
1603 end subroutine mhd_get_temperature_from_etot_with_equi
1604
1605 subroutine mhd_get_temperature_from_eint_with_equi(w, x, ixI^L, ixO^L, res)
1607 integer, intent(in) :: ixi^l, ixo^l
1608 double precision, intent(in) :: w(ixi^s, 1:nw)
1609 double precision, intent(in) :: x(ixi^s, 1:ndim)
1610 double precision, intent(out):: res(ixi^s)
1611
1612 double precision :: r(ixi^s)
1613
1614 call eos%get_Rfactor(w,x,ixi^l,ixo^l,r)
1615 res(ixo^s) = (eos%gamma_minus_1 * w(ixo^s, e_) + block%equi_vars(ixo^s,equi_pe0_,b0i)) /&
1616 ((w(ixo^s,rho_) +block%equi_vars(ixo^s,equi_rho0_,b0i))*r(ixo^s))
1617
1618 end subroutine mhd_get_temperature_from_eint_with_equi
1619
1620 !> LTE+MHD: T from total energy. Subtract KE+ME (via the MHD-aware
1621 !> phys_e_to_ei dispatcher) to get eint, then look up T in the LTE table
1622 !> through eos%get_temperature_from_eint (bound to get_temperature_from_eint_LTE
1623 !> by eos_finalise). Always fresh; does not use the iw_te cache.
1624 !> Should NOT be bound when mhd_internal_e=.true. (w(:,e_) is already eint
1625 !> and phys_e_to_ei is unbound) - use eos%get_temperature_from_eint directly.
1626 subroutine mhd_get_temperature_from_etot_lte(w, x, ixI^L, ixO^L, res)
1628 integer, intent(in) :: ixi^l, ixo^l
1629 double precision, intent(in) :: w(ixi^s, 1:nw)
1630 double precision, intent(in) :: x(ixi^s, 1:ndim)
1631 double precision, intent(out):: res(ixi^s)
1632
1633 double precision :: wlocal(ixi^s, 1:nw)
1634
1635 wlocal(ixi^s, 1:nw) = w(ixi^s, 1:nw)
1636 ! Subtract KE+ME from w(:,e_) via the MHD-aware dispatcher
1637 call phys_e_to_ei(ixi^l, ixo^l, wlocal, x)
1638 ! Now wlocal(:,e_) is the gas internal energy; LTE table lookup
1639 call eos%get_temperature_from_eint(wlocal, x, ixi^l, ixo^l, res)
1640
1641 end subroutine mhd_get_temperature_from_etot_lte
1642
1643 subroutine mhd_get_temperature_equi(w,x, ixI^L, ixO^L, res)
1645 integer, intent(in) :: ixi^l, ixo^l
1646 double precision, intent(in) :: w(ixi^s, 1:nw)
1647 double precision, intent(in) :: x(ixi^s, 1:ndim)
1648 double precision, intent(out):: res(ixi^s)
1649
1650 double precision :: r(ixi^s)
1651
1652 call eos%get_Rfactor(w,x,ixi^l,ixo^l,r)
1653 res(ixo^s)= block%equi_vars(ixo^s,equi_pe0_,b0i)/(block%equi_vars(ixo^s,equi_rho0_,b0i)*r(ixo^s))
1654
1655 end subroutine mhd_get_temperature_equi
1656
1657 !> Equilibrium extraction routines (moved from mod_mhd_phys.t)
1658
1659 subroutine mhd_get_rho_equi(w, x, ixI^L, ixO^L, res)
1661 integer, intent(in) :: ixi^l, ixo^l
1662 double precision, intent(in) :: w(ixi^s, 1:nw)
1663 double precision, intent(in) :: x(ixi^s, 1:ndim)
1664 double precision, intent(out):: res(ixi^s)
1665 res(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i)
1666 end subroutine mhd_get_rho_equi
1667
1668 subroutine mhd_get_pe_equi(w,x, ixI^L, ixO^L, res)
1670 integer, intent(in) :: ixi^l, ixo^l
1671 double precision, intent(in) :: w(ixi^s, 1:nw)
1672 double precision, intent(in) :: x(ixi^s, 1:ndim)
1673 double precision, intent(out):: res(ixi^s)
1674 res(ixo^s) = block%equi_vars(ixo^s,equi_pe0_,b0i)
1675 end subroutine mhd_get_pe_equi
1676
1677 !> Electron and hydrogen number densities of the background alone, for the
1678 !> equilibrium rate that subtract_equi removes. Splitting is restricted to
1679 !> the FI EoS, so the electron count is the fully ionised one.
1680 subroutine mhd_get_ne_nh_equi(ixI^L, ixO^L, w, x, ne, nH)
1682 integer, intent(in) :: ixi^l, ixo^l
1683 double precision, intent(in) :: w(ixi^s, nw)
1684 double precision, intent(in) :: x(ixi^s, 1:ndim)
1685 double precision, intent(out):: ne(ixi^s), nh(ixi^s)
1686 nh(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i) / eos%nH2rhoFactor
1687 ne(ixo^s) = nh(ixo^s) * eos%neOnH_FI
1688 end subroutine mhd_get_ne_nh_equi
1689
1690 !> Internal energy extraction + small value handling (moved from mod_mhd_phys.t)
1691
1692 !> Get internal energy from conserved state (origin formulation)
1693 function mhd_get_ei_origin(w, ixI^L, ixO^L) result(ei)
1695 integer, intent(in) :: ixi^l, ixo^l
1696 double precision, intent(in) :: w(ixi^s, nw)
1697 double precision :: ei(ixo^s)
1698
1699 ! ei = E_total - e_kinetic - e_magnetic
1700 ei(ixo^s) = w(ixo^s,e_) - half*((^c&w(ixo^s,m^c_)**2+)/w(ixo^s,rho_) &
1701 + (^c&w(ixo^s,b^c_)**2+))
1702 end function mhd_get_ei_origin
1703
1704 !> Get internal energy from conserved state (internal energy formulation)
1705 function mhd_get_ei_inte(w, ixI^L, ixO^L) result(ei)
1707 integer, intent(in) :: ixi^l, ixo^l
1708 double precision, intent(in) :: w(ixi^s, nw)
1709 double precision :: ei(ixo^s)
1710
1711 ! e_ already stores internal energy
1712 ei(ixo^s) = w(ixo^s,e_)
1713 end function mhd_get_ei_inte
1714
1715 ! mhd_handle_small_ei stays in mod_mhd_phys.t (callers are there)
1716
1717 !> Update temperature Te_ from pressure using partial ionization
1718
1719 !> PI energy-mode routines (eos_type='PI', ionE=.true.)
1720 !> Structural mirror of the FI conversion/pthermal/csound family, sharing
1721 !> FI's eq_state_units / RR=1 normalisation; the only difference is that the
1722 !> eint<->p relation is delegated to the portable scalar backend
1723 !> (mod_eos_PI), so eint carries the ionisation-energy term.
1724 !> Origin: w(e_) is total energy; inte: w(e_) is gas internal energy.
1725
1726 !> Primitive pressure -> total energy (origin). m^C_ is still velocity here
1727 !> (momentum conversion follows in to_conserved), so KE = half*rho*v^2.
1728 subroutine mhd_p_to_e_pi(ixI^L,ixO^L,w,x)
1730 integer, intent(in) :: ixi^l, ixo^l
1731 double precision, intent(inout) :: w(ixi^s, nw)
1732 double precision, intent(in) :: x(ixi^s, 1:ndim)
1733
1734 double precision :: eint
1735 integer :: ix^d
1736
1737 {do ix^db=ixomin^db,ixomax^db\}
1738 call eint_from_rho_p_pi(w(ix^d,rho_), w(ix^d,p_), eint)
1739 w(ix^d,e_)=eint &
1740 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
1741 +(^c&w(ix^d,b^c_)**2+))
1742 {end do\}
1743
1744 end subroutine mhd_p_to_e_pi
1745
1746 !> Primitive pressure -> gas internal energy (inte formulation)
1747 subroutine mhd_p_to_eint_pi(ixI^L,ixO^L,w,x)
1749 integer, intent(in) :: ixi^l, ixo^l
1750 double precision, intent(inout) :: w(ixi^s, nw)
1751 double precision, intent(in) :: x(ixi^s, 1:ndim)
1752
1753 double precision :: eint
1754 integer :: ix^d
1755
1756 {do ix^db=ixomin^db,ixomax^db\}
1757 call eint_from_rho_p_pi(w(ix^d,rho_), w(ix^d,p_), eint)
1758 w(ix^d,e_)=eint
1759 {end do\}
1760
1761 end subroutine mhd_p_to_eint_pi
1762
1763 !> Primitive -> conserved (origin, total energy)
1764 subroutine mhd_to_conserved_origin_pi(ixI^L,ixO^L,w,x)
1766 integer, intent(in) :: ixi^l, ixo^l
1767 double precision, intent(inout) :: w(ixi^s, nw)
1768 double precision, intent(in) :: x(ixi^s, 1:ndim)
1769
1770 call mhd_p_to_e_pi(ixi^l, ixo^l, w, x)
1771 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
1772
1773 end subroutine mhd_to_conserved_origin_pi
1774
1775 !> Primitive -> conserved (internal energy)
1776 subroutine mhd_to_conserved_inte_pi(ixI^L,ixO^L,w,x)
1778 integer, intent(in) :: ixi^l, ixo^l
1779 double precision, intent(inout) :: w(ixi^s, nw)
1780 double precision, intent(in) :: x(ixi^s, 1:ndim)
1781
1782 call mhd_p_to_eint_pi(ixi^l, ixo^l, w, x)
1783 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
1784
1785 end subroutine mhd_to_conserved_inte_pi
1786
1787 !> Conserved -> primitive (origin). Subtract KE+ME -> eint, invert -> p.
1788 subroutine mhd_to_primitive_origin_pi(ixI^L,ixO^L,w,x)
1790 integer, intent(in) :: ixi^l, ixo^l
1791 double precision, intent(inout) :: w(ixi^s, nw)
1792 double precision, intent(in) :: x(ixi^s, 1:ndim)
1793
1794 double precision :: inv_rho, eint_val, t, rfac
1795 integer :: ix^d
1796
1797 if (fix_small_values) then
1798 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, &
1799 'mhd_to_primitive_origin_PI')
1800 end if
1801
1802 {do ix^db=ixomin^db,ixomax^db\}
1803 inv_rho = 1.d0/w(ix^d,rho_)
1804 ! Convert momentum to velocity
1805 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1806 ! eint = E - 0.5*rho*v^2 - 0.5*B^2
1807 eint_val = w(ix^d,e_) &
1808 - half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+) &
1809 + (^c&w(ix^d,b^c_)**2+))
1810 eint_val = max(eint_val, smalldouble)
1811 call state_from_eint_pi(w(ix^d,rho_), eint_val, t, w(ix^d,p_), rfac)
1812 {end do\}
1813
1814 end subroutine mhd_to_primitive_origin_pi
1815
1816 !> Conserved -> primitive (internal energy). e_ already holds eint.
1817 subroutine mhd_to_primitive_inte_pi(ixI^L,ixO^L,w,x)
1819 integer, intent(in) :: ixi^l, ixo^l
1820 double precision, intent(inout) :: w(ixi^s, nw)
1821 double precision, intent(in) :: x(ixi^s, 1:ndim)
1822
1823 double precision :: inv_rho, eint_val, t, rfac
1824 integer :: ix^d
1825
1826 if (fix_small_values) then
1827 call phys_handle_small_values(.false., w, x, ixi^l, ixo^l, &
1828 'mhd_to_primitive_inte_PI')
1829 end if
1830
1831 {do ix^db=ixomin^db,ixomax^db\}
1832 eint_val = max(w(ix^d,e_), smalldouble)
1833 call state_from_eint_pi(w(ix^d,rho_), eint_val, t, w(ix^d,p_), rfac)
1834 ! Convert momentum to velocity
1835 inv_rho = 1.d0/w(ix^d,rho_)
1836 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1837 {end do\}
1838
1839 end subroutine mhd_to_primitive_inte_pi
1840
1841 !> Thermal pressure (origin): subtract KE+ME, invert eint -> p.
1842 subroutine mhd_get_pthermal_origin_pi(w,x,ixI^L,ixO^L,pth)
1844 integer, intent(in) :: ixi^l, ixo^l
1845 double precision, intent(in) :: w(ixi^s,nw)
1846 double precision, intent(in) :: x(ixi^s,1:ndim)
1847 double precision, intent(out):: pth(ixi^s)
1848
1849 double precision :: eint_val, t, rfac
1850 integer :: ix^d
1851
1852 {do ix^db=ixomin^db,ixomax^db\}
1853 eint_val = w(ix^d,e_) &
1854 - half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_) &
1855 + (^c&w(ix^d,b^c_)**2+))
1856 eint_val = max(eint_val, smalldouble)
1857 call state_from_eint_pi(w(ix^d,rho_), eint_val, t, pth(ix^d), rfac)
1858 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1859 {end do\}
1860
1861 end subroutine mhd_get_pthermal_origin_pi
1862
1863 !> Thermal pressure (inte): e_ holds eint, invert eint -> p.
1864 subroutine mhd_get_pthermal_inte_pi(w,x,ixI^L,ixO^L,pth)
1866 integer, intent(in) :: ixi^l, ixo^l
1867 double precision, intent(in) :: w(ixi^s,nw)
1868 double precision, intent(in) :: x(ixi^s,1:ndim)
1869 double precision, intent(out):: pth(ixi^s)
1870
1871 double precision :: eint_val, t, rfac
1872 integer :: ix^d
1873
1874 {do ix^db=ixomin^db,ixomax^db\}
1875 eint_val = max(w(ix^d,e_), smalldouble)
1876 call state_from_eint_pi(w(ix^d,rho_), eint_val, t, pth(ix^d), rfac)
1877 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
1878 {end do\}
1879
1880 end subroutine mhd_get_pthermal_inte_pi
1881
1882 !> Adiabatic sound speed squared from primitive (rho, p).
1883
1884 !> Effective Gamma1 = cs2 * rho / p (for the same primitive state).
1885
1886 !> PI energy mode: refresh Te_ from gas internal energy via the backend
1887 !> eint->T inversion (direct, so no lagged wCT -- unlike no-energy
1888 !> mhd_update_temperature which lags iz_H via wCT(Te_)). Uses MHD's Te_ index
1889 !> (PI registers Te via var_set_auxvar, so the generic iw_te is unset).
1890
1891 !> PI prominence (T,p) routines (eos_type='PI', pi_table='prominence').
1892 !> Prominence ionisation depends on (T,p), not T alone, so the chromosphere
1893 !> T-only seam does not apply. Following the collaborator's design, R and T
1894 !> are recomputed from (rho, pth) via ionization_get_state, which dispatches
1895 !> the prominence (pressure-bisection) inversion internally. No-energy only
1896 !> (guarded in eos_validate_params), so pth = (gamma-1)*eint is R-independent
1897 !> and obtained from phys_get_ei (conserved w; KE/ME removed).
1898
1899 !> R-factor for the prominence (T,p) table: recompute from (rho, pth).
1900
1901 !> Refresh stored Te_ for the prominence table from (rho, pth).
1902
1903end module mod_mhd_eos
1904!> Needs a line after to pass the preprocesor
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...
Analytic H-only Saha EoS (eos_method == 'analytic').
LTE (Saha-table) EoS kernels and finalise for the eos% family.
Definition mod_eos_LTE.t:12
double precision function, public p2eint_from_nh_p(nh, ponh)
Pressure-to-eint ratio from (log10 nH, log10 p/nH) in code units. Dispatches: analytic -> Saha solve ...
double precision function, public eint_nh_from_t(log_nh, log_t)
Internal energy per nH from (log10 nH, log10 T) in code units. Uses the bisection-built inverse table...
double precision function, public y_from_nh_eint(nh, eint_nh)
Ionization fraction from (log10 nH, log10 eint/nH) in code units. Dispatches: analytic -> Saha quadra...
subroutine, public get_temperature_from_eint_fast_lte(w, x, ixil, ixol, res)
subroutine, public eos_get_eintt_grid(n_nh, lg_nh_min, lg_nh_max)
log_nH grid metadata of the (log_nH, log_T) inverse table (eint from T), choosing the container by me...
double precision function, public t_from_nh_eint(nh, eint_nh)
Temperature from (log10 nH, log10 eint/nH) in code units. Dispatches: analytic -> Saha bisection/Newt...
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
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 get_gamma1_pi(w, x, ixil, ixol, gamma1)
Effective Gamma1 = cs2 * rho / p for the same primitive state.
Definition mod_eos_PI.t:146
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
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer b0i
background magnetic field location indicator
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision, dimension(:), allocatable, parameter d
logical fix_small_values
fix small values with average or replace methods
MHD <-> EoS seam: binds the eos% authority into magnetohydrodynamics.
Definition mod_mhd_eos.t:16
subroutine, public mhd_link_eos()
Link the appropriate EOS conversion routines based on the selected EoS type.
Definition mod_mhd_eos.t:52
procedure(sub_get_pthermal), pointer, public mhd_get_temperature
Temperature pointer: set by mhd_link_eos based on EoS type and energy formulation.
Definition mod_mhd_eos.t:41
procedure(sub_get_pthermal), pointer, public mhd_get_pthermal
Thermal pressure pointer: set by mhd_link_eos based on energy formulation. Internal to mod_mhd_eos — ...
Definition mod_mhd_eos.t:38
procedure(sub_convert), pointer, public mhd_to_conserved
use habitual name of converting to conserved
Definition mod_mhd_eos.t:45
procedure(sub_convert), pointer, public mhd_to_primitive
use habitual name of converting to primitive
Definition mod_mhd_eos.t:43
Magneto-hydrodynamics module.
Definition mod_mhd_phys.t:2
integer, public, protected c_
logical, public, protected mhd_internal_e
Whether internal energy is solved instead of total energy.
integer, public, protected wkminus_
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
logical, public, protected mhd_semirelativistic
Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved.
integer, public, protected m
type(te_fluid), allocatable, public te_fl_mhd
type of fluid for thermal emission synthesis
logical, public has_equi_rho_and_p
whether split off equilibrium density and pressure
integer, public, protected waminus_
logical, public, protected mhd_energy
Whether an energy equation is used.
type(fld_fluid), allocatable, public fld_fl
Radiation fluid object (gas-EoS callbacks for FLD), wired in mhd_link_eos.
integer, public, protected waplus_
Conserved wave-energy indices. The plus variables propagate against B.
subroutine, public mhd_uawsom_rho2_factor(ixil, ixol, w, x, factor)
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
integer, public, protected b
logical, public, protected mhd_hydrodynamic_e
Whether hydrodynamic energy is solved instead of total energy.
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
integer, public, protected wkplus_
integer, public, protected rho_
Index of the density (in the w array)
integer, public, protected e_
Index of the energy density (-1 if not present)
logical, public, protected mhd_uawsom
Enable the Uniturbulence and Alfven Wave Solar Model extension.
logical, public mhd_equi_thermal
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_check_params), pointer phys_bind_eos_to_source
Definition mod_physics.t:53
procedure(sub_convert), pointer phys_to_primitive
Definition mod_physics.t:52
procedure(sub_get_pthermal), pointer phys_get_gamma1
Definition mod_physics.t:78
procedure(sub_get_pthermal), pointer phys_get_pthermal
Definition mod_physics.t:77
procedure(sub_get_ei), pointer phys_get_ei
Definition mod_physics.t:68
procedure(sub_convert), pointer phys_to_prolong
Definition mod_physics.t:55
procedure(sub_convert), pointer phys_to_conserved
Definition mod_physics.t:51
procedure(sub_convert), pointer phys_from_prolong
Definition mod_physics.t:56
module radiative cooling – add optically thin radiative cooling
subroutine build_y_mod_table(fl)
===================================================================
Module for handling problematic values in simulations, such as negative pressures.
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor