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