MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_hd_eos.t
Go to the documentation of this file.
1!=============================================================================
2!> HD <-> EoS seam: binds the eos% authority into hydrodynamics.
3!>
4!> hd_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).
7!> bind_eos_to_source wires the thermal-conduction / radiative-cooling / FLD
8!> fluid-port callbacks from eos%.
9!>
10!> Holds the HD block routines that wrap the shared thermodynamics with HD's
11!> mechanical-energy bookkeeping -- total-energy ("origin") formulation,
12!> dust-aware: FI/LTE/PI conversions, p_to_e, pthermal, csound2/gamma1, and the
13!> PI energy + prominence R-factor / temperature kernels.
14!=============================================================================
17 use mod_physics
18 use mod_eos
19 !> Mode-specific kernels come from their sub-modules (the facade no longer
20 !> re-exports them); each mpistops if called under the wrong eos_type/method.
21 use mod_eos_lte
23 use mod_eos_pi
25 use mod_hd_phys
27
28 use mod_comm_lib, only: mpistop
29
30 implicit none
31 private
32
33 procedure(sub_convert), pointer, public :: hd_to_primitive => null()
34 procedure(sub_convert), pointer, public :: hd_to_conserved => null()
35
37
38contains
39
40 !> Link the appropriate EOS conversion routines based on the selected EoS type
41 subroutine hd_link_eos()
43
44 ! PI (partial approximations) takes the FI ideal-gas conversions as
45 ! its BASE (e_int=p/(gamma-1); variable R via get_Rfactor). Energy
46 ! mode (ionE) overrides them with the PI-energy variants at the end
47 ! of this routine; FI conversions stay pristine.
48 if (eos%eos_type == 'FI' .or. eos%eos_type == 'PI') then
49 eos%to_conserved => hd_to_conserved_origin
50 eos%to_primitive => hd_to_primitive_origin
51 else if (eos%eos_type == 'LTE') then
52 eos%to_conserved => hd_to_conserved_lte
53 eos%to_primitive => hd_to_primitive_lte
54 else
55 call mpistop('Error: Unknown HD EOS type: ' // trim(eos%eos_type))
56 end if
57
58 phys_to_primitive => eos%to_primitive
59 phys_to_conserved => eos%to_conserved
60 phys_get_rho => eos%get_rho
62 eos%get_thermal_pressure => hd_get_pthermal
63 phys_bind_eos_to_source => bind_eos_to_source
64
65 eos%p_to_e => p_to_e !> suitable for both FI and LTE
66
67 ! Link sound speed and gamma1 computation
68 if (eos%eos_type == 'LTE' .and. eos%ionE) then
69 eos%get_csound2 => hd_get_csound2_lte
70 phys_get_gamma1 => hd_get_gamma1_lte
71 ! EoS-aware prolongation: interpolate in (rho, v, T) space
72 phys_to_prolong => hd_to_prolong_lte
73 phys_from_prolong => hd_from_prolong_lte
74 else
75 eos%get_csound2 => hd_get_csound2_fi
76 phys_get_gamma1 => get_gamma1_fi
77 end if
78
79 ! Rfactor: only the FI case is physics-dependent (the usr_Rfactor user
80 ! hook). LTE and PI bind pure eos% routines in eos_finalise_{LTE,PI},
81 ! which run after this and before bind_eos_to_source (so they win and
82 ! their targets stay private). Note: this makes usr_Rfactor apply only to
83 ! FI for HD -- consistent with MHD, where the EoS owns R for LTE/PI.
84 if(associated(usr_rfactor)) then
85 eos%get_Rfactor=>usr_rfactor
86 else
87 eos%get_Rfactor=>rfactor_from_constant_ionization
88 end if
89
90 !> PI energy-mode overrides (eos_type='PI', ionE=.true.)
91 ! Energy mode differs from no-energy PI only in the eint<->p relation,
92 ! so override exactly the routines that touch it (conversions, p_to_e,
93 ! csound2/gamma1, Te update), all via the portable backend. pthermal
94 ! is unchanged: hd_get_pthermal already carries a PI-energy branch.
95 if (eos%eos_type == 'PI' .and. eos%ionE) then
96 if (.not. hd_energy) &
97 call mpistop('PI energy EoS requires hd_energy=.true.')
98 eos%to_conserved => hd_to_conserved_pi
99 eos%to_primitive => hd_to_primitive_pi
100 phys_to_primitive => eos%to_primitive
101 phys_to_conserved => eos%to_conserved
102 eos%p_to_e => p_to_e_pi
103 !> eos%get_csound2 => get_csound2_PI set in eos_finalise_PI (private target)
105 ! Te_ from eint each substep (uses HD's Te_ index: PI registers
106 ! Te via var_set_auxvar, so the generic iw_te is unset).
107 end if
108 hd_to_primitive => eos%to_primitive
109 hd_to_conserved => eos%to_conserved
110
111 end subroutine hd_link_eos
112
113 !> Bind the EoS to the conduction and cooling fluids, called from eos_finalise
114 subroutine bind_eos_to_source()
115 if (allocated(tc_fl)) then
116 call eos_bind_tc(tc_fl, .not. associated(eos%get_Rfactor, rfactor_from_constant_ionization))
117 end if
118
119 if (allocated(rc_fl)) then
120 rc_fl%get_rho => eos%get_rho
121 rc_fl%get_pthermal => eos%get_thermal_pressure
122 rc_fl%get_var_Rfactor => eos%get_Rfactor
123 rc_fl%get_Te => eos%get_Te
124 rc_fl%get_ne_nH => eos%get_ne_nH
125 rc_fl%ionE = eos%ionE
126 rc_fl%method_analytic = (eos%method_id == eos_analytic)
127 rc_fl%inv_gamma_minus_1 = eos%inv_gamma_minus_1
128 rc_fl%nH2rhoFactor = eos%nH2rhoFactor
129 rc_fl%eion_per_nH = eos%eion_per_nH
130 rc_fl%eint_from_T => eint_nh_from_t
131 rc_fl%p2eint => p2eint_from_nh_p
132 rc_fl%T_from_eint => t_from_nh_eint
133 rc_fl%y_from_eint => y_from_nh_eint
134 rc_fl%log_T_floor = eos_get_log_t_floor()
136 !> Build the variable-c_V Townsend Y_mod table now that all
137 !> EoS tables (eint_from_T, T, neOnH) are in code units.
138 !> build_Y_mod_table checks coolmethod=='exact' and .not.isPPL
139 !> internally and early-returns otherwise. LTE only:
140 !> eos_get_eintT_grid reads the LTE eintT grid; PI runs classical
141 !> Townsend (Y_mod-for-PI is a later refinement).
142 if (eos%ionE .and. eos%eos_type == 'LTE') then
143 call eos_get_eintt_grid(rc_fl%Y_mod_n_nH, &
144 rc_fl%Y_mod_lg_nH_min, rc_fl%Y_mod_lg_nH_max)
146 end if
147 end if
148
149 !> PI energy mode: repoint cooling/conduction eint<->T callbacks at
150 !> the ionisation backend (the LTE-table versions above assume LTE
151 !> tables PI does not load). Classical Townsend; Y_mod not built (above).
152 if (eos%eos_type == 'PI' .and. eos%ionE) then
153 if (allocated(tc_fl)) tc_fl%eint_from_T => eint_from_t_pi
154 if (allocated(rc_fl)) then
155 rc_fl%eint_from_T => eint_from_t_pi
156 rc_fl%p2eint => p2eint_pi
157 rc_fl%T_from_eint => t_from_eint_pi
158 rc_fl%y_from_eint => y_from_eint_pi
159 end if
160 end if
161
162 te_fl_hd%get_rho => eos%get_rho
163 te_fl_hd%get_pthermal => eos%get_thermal_pressure
164 te_fl_hd%get_var_Rfactor => eos%get_Rfactor
165 te_fl_hd%get_ne_nH => eos%get_ne_nH
166
167 if (allocated(fld_fl)) then
168 !> Radiation (FLD) fluid: gas-EoS callbacks. get_temperature_from_pressure
169 !> is the FI T=p/(R*rho) routine (the LTE variant is a later pass).
170 fld_fl%gamma = eos%gamma
171 fld_fl%get_tgas => eos%get_temperature_from_pressure
172 fld_fl%get_Rfactor => eos%get_Rfactor
173 end if
174 end subroutine bind_eos_to_source
175
176 !> Transform primitive variables into conservative ones
177 subroutine hd_to_conserved_origin(ixI^L, ixO^L, w, x)
179 use mod_dust, only: dust_to_conserved
180 integer, intent(in) :: ixi^l, ixo^l
181 double precision, intent(inout) :: w(ixi^s, nw)
182 double precision, intent(in) :: x(ixi^s, 1:ndim)
183
184 integer :: ix^d
185
186 {do ix^db=ixomin^db,ixomax^db\}
187 if (hd_energy) then
188 ! Calculate total energy from pressure and kinetic energy
189 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1+&
190 half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
191 end if
192 ! Convert velocity to momentum
193 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
194 {end do\}
195
196 if (hd_dust) then
197 call dust_to_conserved(ixi^l, ixo^l, w, x)
198 end if
199
200 end subroutine hd_to_conserved_origin
201
202 !> Transform conservative variables into primitive ones
203 subroutine hd_to_primitive_origin(ixI^L, ixO^L, w, x)
205 use mod_dust, only: dust_to_primitive
206 integer, intent(in) :: ixi^l, ixo^l
207 double precision, intent(inout) :: w(ixi^s, nw)
208 double precision, intent(in) :: x(ixi^s, 1:ndim)
209
210 double precision :: inv_rho
211 integer :: ix^d
212
213 if (fix_small_values) then
214 call hd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'hd_to_primitive')
215 end if
216
217 {do ix^db=ixomin^db,ixomax^db\}
218 inv_rho = 1.d0/w(ix^d,rho_)
219 ! Convert momentum to velocity
220 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
221 ! Calculate pressure = (gamma-1) * (e-ek)
222 if(hd_energy) then
223 ! Compute pressure
224 w(ix^d,p_)=(eos%gamma_minus_1)*(w(ix^d,e_)&
225 -half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+))
226 end if
227 {end do\}
228
229 ! Convert dust momentum to dust velocity
230 if (hd_dust) then
231 call dust_to_primitive(ixi^l, ixo^l, w, x)
232 end if
233
234 end subroutine hd_to_primitive_origin
235
236 !> LTE primitive -> conserved conversion.
237 !>
238 !> On entry: rho_ = density, m_ = velocity, p_ = pressure.
239 !> On exit: rho_ = density (unchanged), m_ = momentum, e_ = total energy.
240 subroutine hd_to_conserved_lte(ixI^L, ixO^L, w, x)
242 use mod_dust, only: dust_to_conserved
243 integer, intent(in) :: ixi^l, ixo^l
244 double precision, intent(inout) :: w(ixi^s, nw)
245 double precision, intent(in) :: x(ixi^s, 1:ndim)
246
247 call p_to_e(ixi^l, ixo^l, w, x)
248
249 ! Convert velocity to momentum
250 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
251
252 if (hd_dust) then
253 call dust_to_conserved(ixi^l, ixo^l, w, x)
254 end if
255
256 end subroutine hd_to_conserved_lte
257
258 subroutine p_to_e(ixI^L, ixO^L, w, x)
259 !> Pressure to total energy, E = eint(rho, p) + KE, through lte_eint_from_p.
260 !> On entry w(p_) holds the pressure and w(m_) the velocity
262 integer, intent(in) :: ixi^l, ixo^l
263 double precision, intent(inout) :: w(ixi^s, nw)
264 double precision, intent(in) :: x(ixi^s, 1:ndim)
265
266 integer :: ix^d
267 double precision :: nh(ixi^s), log_nh(ixi^s)
268
269 if (.not. hd_energy) return
270 if (eos%ionE) then
271 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
272 log_nh(ixo^s) = dlog10(nh(ixo^s))
273 end if
274 {do ix^db=ixomin^db,ixomax^db\}
275 if (eos%ionE) then
276 w(ix^d,e_) = lte_eint_from_p(w(ix^d,p_), nh(ix^d), log_nh(ix^d), w(ix^d,rho_)) + &
277 half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
278 else
279 w(ix^d,e_) = w(ix^d,p_)*eos%inv_gamma_minus_1 + &
280 half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
281 end if
282 {end do\}
283
284 end subroutine p_to_e
285
286 !> LTE conserved -> primitive conversion.
287 !>
288 !> On entry: rho_ = density, m_ = momentum, e_ = total energy.
289 !> On exit: rho_ = density (unchanged), m_ = velocity, p_ = pressure.
290 !>
291 !> Pressure is computed energy-consistently from actual eint via EoS
292 !> table lookups (T and ne/nH). Cannot use stored Ne_/Te_ because
293 !> they may be stale after AMR prolongation/coarsening.
294 subroutine hd_to_primitive_lte(ixI^L, ixO^L, w, x)
296 use mod_dust, only: dust_to_primitive
297 integer, intent(in) :: ixi^l, ixo^l
298 double precision, intent(inout) :: w(ixi^s, nw)
299 double precision, intent(in) :: x(ixi^s, 1:ndim)
300
301 double precision :: inv_rho
302 double precision :: nh(ixi^s)
303 double precision :: log_nh(ixi^s)
304 double precision :: eint_val
305 integer :: ix^d
306
307 if (fix_small_values) then
308 call hd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'hd_to_primitive_LTE')
309 end if
310
311 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
312
313 ! Cache log10(nH) for all cells (used by table lookups for IonE)
314 if (eos%ionE) then
315 log_nh(ixo^s) = dlog10(nh(ixo^s))
316 end if
317
318 {do ix^db=ixomin^db,ixomax^db\}
319 inv_rho = 1.d0/w(ix^d,rho_)
320 ! Convert momentum to velocity
321 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
322 ! Calculate pressure
323 if(hd_energy) then
324 ! Energy-consistent pressure from the actual eint (not the cached Ne_/Te_,
325 ! which can be stale after prolongation)
326 eint_val = w(ix^d,e_) - half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)
327 w(ix^d,p_) = lte_p_from_eint(eint_val, nh(ix^d), log_nh(ix^d), inv_rho)
328 end if
329 {end do\}
330
331 ! Convert dust momentum to dust velocity
332 if (hd_dust) then
333 call dust_to_primitive(ixi^l, ixo^l, w, x)
334 end if
335
336 end subroutine hd_to_primitive_lte
337
338 !> Calculate thermal pressure within ixO^L.
339 !> For energy runs delegates to eos%get_thermal_pressure; for no-energy
340 !> (isothermal) uses the adiabatic relation p = adiab * rho^gamma.
341 subroutine hd_get_pthermal(w, x, ixI^L, ixO^L, pth)
343 use mod_physics, only: phys_get_ei
346
347 integer, intent(in) :: ixi^l, ixo^l
348 double precision, intent(in) :: w(ixi^s, 1:nw)
349 double precision, intent(in) :: x(ixi^s, 1:ndim)
350 double precision, intent(out):: pth(ixi^s)
351 integer :: iw, ix^d
352 double precision :: nh(ixi^s), ei(ixi^s), tpi, rpi
353
354 if (hd_energy) then
355 if (eos%eos_type == 'LTE') then
356 ! LTE: p = nH * (1 + He + ne/nH) * T from stored state
357 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
358 pth(ixo^s) = nh(ixo^s) * (1.0d0 + eos%He_abundance &
359 + (w(ixo^s,iw_ne) / nh(ixo^s))) * w(ixo^s,iw_te)
360 else if (eos%eos_type == 'PI' .and. eos%ionE) then
361 ! PI energy: invert eint (= e - KE, via phys_get_ei) -> p with
362 ! the ionisation backend (eint carries the ionisation energy).
363 ei(ixo^s) = phys_get_ei(w, ixi^l, ixo^l)
364 {do ix^db=ixomin^db,ixomax^db\}
365 call state_from_eint_pi(w(ix^d,rho_), ei(ix^d), &
366 tpi, pth(ix^d), rpi)
367 {end do\}
368 else
369 ! FI: p = (gamma-1) * (e - KE)
370 pth(ixo^s) = eos%gamma_minus_1 * phys_get_ei(w, ixi^l, ixo^l)
371 end if
372 else
373 if (.not. associated(usr_set_pthermal)) then
374 pth(ixo^s) = hd_adiab * w(ixo^s, rho_)**eos%gamma
375 else
376 call usr_set_pthermal(w,x,ixi^l,ixo^l,pth)
377 end if
378 end if
379
380 if (fix_small_values) then
381 {do ix^db= ixo^lim^db\}
382 if(pth(ix^d)<small_pressure) then
383 pth(ix^d)=small_pressure
384 endif
385 {enddo^d&\}
386 else if (check_small_values) then
387 {do ix^db= ixo^lim^db\}
388 if(pth(ix^d)<small_pressure) then
389 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
390 " encountered when call hd_get_pthermal"
391 write(*,*) "Iteration: ", it, " Time: ", global_time
392 write(*,*) "Location: ", x(ix^d,:)
393 write(*,*) "Cell number: ", ix^d
394 do iw=1,nw
395 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
396 end do
397 if(trace_small_values) write(*,*) dsqrt(pth(ix^d)-bigdouble)
398 write(*,*) "Saving status at the previous time step"
399 crash=.true.
400 end if
401 {enddo^d&\}
402 end if
403
404 end subroutine hd_get_pthermal
405
406 !> Sound speed squared for FI (fully ionized / constant gamma) EoS.
407 !> Expects w in primitive form: w(p_) = pressure, w(rho_) = density.
408 subroutine hd_get_csound2_fi(w, x, ixI^L, ixO^L, cs2)
410 integer, intent(in) :: ixi^l, ixo^l
411 double precision, intent(in) :: w(ixi^s, nw)
412 double precision, intent(in) :: x(ixi^s, 1:ndim)
413 double precision, intent(out) :: cs2(ixi^s)
414
415 cs2(ixo^s) = eos%gamma * w(ixo^s, p_) / w(ixo^s, rho_)
416
417 end subroutine hd_get_csound2_fi
418
419 !> Sound speed squared for LTE+IonE EoS.
420 !> Delegates Gamma_1 computation to hd_get_gamma1_LTE, then cs2 = Gamma_1 * p/rho.
421 subroutine hd_get_csound2_lte(w, x, ixI^L, ixO^L, cs2)
423 integer, intent(in) :: ixi^l, ixo^l
424 double precision, intent(in) :: w(ixi^s, nw)
425 double precision, intent(in) :: x(ixi^s, 1:ndim)
426 double precision, intent(out) :: cs2(ixi^s)
427 integer :: ix^d
428
429 call hd_get_gamma1_lte(w, x, ixi^l, ixo^l, cs2)
430 {do ix^db=ixomin^db,ixomax^db\}
431 cs2(ix^d) = cs2(ix^d) * w(ix^d, p_) / w(ix^d, rho_)
432 {end do\}
433
434 end subroutine hd_get_csound2_lte
435
436 !> PI energy-mode routines (eos_type='PI', ionE=.true.)
437 !> Mirror the HD FI/LTE family; the eint<->p relation is delegated to the
438 !> portable scalar backend (mod_eos_pi). Same eq_state_units /
439 !> RR=1 normalisation as FI. Origin (total-energy) only, as in HD. eint
440 !> carries the ionisation-energy term, so p=(gamma-1)*eint no longer holds.
441
442 !> Primitive pressure -> total energy via backend (m_ is velocity here).
443 subroutine p_to_e_pi(ixI^L, ixO^L, w, x)
445 integer, intent(in) :: ixi^l, ixo^l
446 double precision, intent(inout) :: w(ixi^s, nw)
447 double precision, intent(in) :: x(ixi^s, 1:ndim)
448 double precision :: eint
449 integer :: ix^d
450
451 {do ix^db=ixomin^db,ixomax^db\}
452 if (hd_energy) then
453 call eint_from_rho_p_pi(w(ix^d,rho_), w(ix^d,p_), eint)
454 w(ix^d,e_) = eint + half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
455 end if
456 {end do\}
457 end subroutine p_to_e_pi
458
459 !> Primitive -> conserved (PI energy)
460 subroutine hd_to_conserved_pi(ixI^L, ixO^L, w, x)
462 use mod_dust, only: dust_to_conserved
463 integer, intent(in) :: ixi^l, ixo^l
464 double precision, intent(inout) :: w(ixi^s, nw)
465 double precision, intent(in) :: x(ixi^s, 1:ndim)
466
467 call p_to_e_pi(ixi^l, ixo^l, w, x)
468 ! Convert velocity to momentum
469 ^c&w(ixo^s,m^c_)=w(ixo^s,rho_)*w(ixo^s,m^c_)\
470 if (hd_dust) call dust_to_conserved(ixi^l, ixo^l, w, x)
471 end subroutine hd_to_conserved_pi
472
473 !> Conserved -> primitive (PI energy): KE removed -> eint, backend -> p.
474 subroutine hd_to_primitive_pi(ixI^L, ixO^L, w, x)
476 use mod_dust, only: dust_to_primitive
477 integer, intent(in) :: ixi^l, ixo^l
478 double precision, intent(inout) :: w(ixi^s, nw)
479 double precision, intent(in) :: x(ixi^s, 1:ndim)
480 double precision :: inv_rho, eint_val, t, rfac
481 integer :: ix^d
482
483 if (fix_small_values) then
484 call hd_handle_small_values(.false., w, x, ixi^l, ixo^l, &
485 'hd_to_primitive_PI')
486 end if
487
488 {do ix^db=ixomin^db,ixomax^db\}
489 inv_rho = 1.d0/w(ix^d,rho_)
490 ! Convert momentum to velocity
491 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
492 if (hd_energy) then
493 eint_val = w(ix^d,e_) &
494 - half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)
495 eint_val = max(eint_val, smalldouble)
496 call state_from_eint_pi(w(ix^d,rho_), eint_val, &
497 t, w(ix^d,p_), rfac)
498 end if
499 {end do\}
500
501 if (hd_dust) call dust_to_primitive(ixi^l, ixo^l, w, x)
502 end subroutine hd_to_primitive_pi
503
504 !> Adiabatic sound speed squared from primitive (rho, p).
505
506 !> Effective Gamma1 = cs2 * rho / p.
507
508 !> PI energy mode: refresh Te_ from gas internal energy via the backend
509 !> eint->T inversion. Uses HD's Te_ index (PI registers Te via
510 !> var_set_auxvar, so the generic iw_te is unset). phys_get_ei supplies
511 !> eint (KE removed).
512
513 !> PI no-energy R-factor from the stored Te_ (HD's index). Mirrors MHD's
514 !> Rfactor_from_temperature_ionization. The generic mod_eos version uses
515 !> the global iw_te, which PI leaves unset (var_set_auxvar) -- so HD needs
516 !> its own Te_-addressed routine, exactly as MHD does.
517
518 !> PI no-energy Te_ update (pth/(rho*R) with lagged iz_H from wCT(Te_)).
519 !> HD's Te_-addressed mirror of MHD's mhd_update_temperature.
520
521 !> Prominence (T,p) R-factor: recompute from (rho, pth) via the module's
522 !> prominence inversion (no-energy only -> pth=(gamma-1)*eint, R-indep).
523
524 !> Prominence (T,p) Te_ update from (rho, pth).
525
526 !> Return effective adiabatic index for LTE+IonE EoS.
527 !> Dispatches on gamma1_method and eos%method.
528 subroutine hd_get_gamma1_lte(w, x, ixI^L, ixO^L, gamma1)
530 integer, intent(in) :: ixi^l, ixo^l
531 double precision, intent(in) :: w(ixi^s, nw)
532 double precision, intent(in) :: x(ixi^s, 1:ndim)
533 double precision, intent(out) :: gamma1(ixi^s)
534
535 integer :: ix^d
536
537 if (eos%gamma1_method == 'constant') then
538 gamma1(ixo^s) = eos%gamma
539 return
540 end if
541
542 {do ix^db=ixomin^db,ixomax^db\}
543 gamma1(ix^d) = lte_gamma1_from_p(w(ix^d,p_), w(ix^d,rho_))
544 {end do\}
545
546 end subroutine hd_get_gamma1_lte
547
548 !> Rfactor = p/(rho*T) for constant ionisation degree (FI/PI no-energy).
549 !> Stays in the seam: RR is the physics module's gas-constant factor, not
550 !> visible to mod_eos. Rfactor_from_LTE lives in mod_eos (no RR).
551 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
553 integer, intent(in) :: ixi^l, ixo^l
554 double precision, intent(in) :: w(ixi^s,1:nw)
555 double precision, intent(in) :: x(ixi^s,1:ndim)
556 double precision, intent(out):: rfactor(ixi^s)
557
558 rfactor(ixo^s)=rr
559
560 end subroutine rfactor_from_constant_ionization
561
562 !> Convert conserved (rho, rho*v, E) to prolong form (rho, v, T).
563 !> T is stored in the e_ slot. Interpolation in this space avoids
564 !> Jensen's inequality across the ionisation plateau.
565 subroutine hd_to_prolong_lte(ixI^L, ixO^L, w, x)
566 integer, intent(in) :: ixi^l, ixo^l
567 double precision, intent(inout) :: w(ixi^s, nw)
568 double precision, intent(in) :: x(ixi^s, 1:ndim)
569
570 double precision :: inv_rho, eint_val, nh_val, log_nh, t_loc, y_loc
571 integer :: ix^d
572
573 {do ix^db=ixomin^db,ixomax^db\}
574 inv_rho = 1.d0 / w(ix^d, rho_)
575 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
576 log_nh = dlog10(nh_val)
577
578 ! Convert momentum to velocity
579 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
580
581 ! Compute eint = E - 0.5*rho*v^2
582 eint_val = w(ix^d, e_) &
583 - half * w(ix^d, rho_) * (^c&w(ix^d,m^c_)**2+)
584 eint_val = max(eint_val, nh_val*eos%eint_nH_min, smalldouble)
585
586 ! Convert eint to T via EoS
587 if (eint_val * inv_rho > eos%eint_rho_FI_threshold) then
588 ! FI bypass: T = (gamma-1)*(eint - eion*nH) / (nH * n_per_nH_FI)
589 w(ix^d, e_) = eos%gamma_minus_1 &
590 * (eint_val - eos%eion_per_nH * nh_val) &
591 / (nh_val * eos%n_per_nH_FI)
592 else if (eos%method_id == eos_analytic) then
593 ! Analytical Saha: solve for T from eint
594 call saha_t_from_nh_eint(nh_val, &
595 eint_val / nh_val, t_loc, y_loc)
596 w(ix^d, e_) = t_loc
597 else
598 ! Ionisation zone: T from table
599 w(ix^d, e_) = t_from_nh_eint(log_nh, &
600 dlog10(eint_val) - log_nh)
601 end if
602 {end do\}
603
604 end subroutine hd_to_prolong_lte
605
606 !> Convert prolong form (rho, v, T) back to conserved (rho, rho*v, E).
607 !> T is read from the e_ slot. Uses eint_nH_from_T for back-conversion.
608 subroutine hd_from_prolong_lte(ixI^L, ixO^L, w, x)
609 integer, intent(in) :: ixi^l, ixo^l
610 double precision, intent(inout) :: w(ixi^s, nw)
611 double precision, intent(in) :: x(ixi^s, 1:ndim)
612
613 double precision :: t_val, eint_val, t_fi, nh_val, log_nh, t_min
614 integer :: ix^d
615
616 t_fi = (eos%eint_rho_FI_threshold &
617 * eos%nH2rhoFactor - eos%eion_per_nH) &
618 * eos%gamma_minus_1 / eos%n_per_nH_FI
619 ! Lower T bound of the (rho, T) inverse table
620 t_min = 10.0d0**eos_get_log_t_floor()
621
622 {do ix^db=ixomin^db,ixomax^db\}
623 t_val = w(ix^d, e_) ! T stored in e_ slot
624 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
625 log_nh = dlog10(nh_val)
626
627 if (t_val > t_fi) then
628 ! FI: eint = nH*(n_per_nH*T/(gamma-1) + eion)
629 eint_val = nh_val &
630 * (eos%n_per_nH_FI * t_val * eos%inv_gamma_minus_1 &
631 + eos%eion_per_nH)
632 else if (eos%method_id == eos_analytic) then
633 ! Analytical Saha: eint from T directly
634 eint_val = saha_eint_from_nh_t(nh_val, t_val) * nh_val
635 else
636 ! Ionisation zone: eint/nH from T table
637 eint_val = eint_nh_from_t(log_nh, &
638 dlog10(max(t_val, t_min))) &
639 * nh_val
640 end if
641
642 ! E = eint + 0.5*rho*v^2
643 w(ix^d, e_) = eint_val &
644 + half * w(ix^d, rho_) * (^c&w(ix^d,m^c_)**2+)
645 ! Convert velocity to momentum
646 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
647 {end do\}
648
649 end subroutine hd_from_prolong_lte
650
651end module mod_hd_eos
652!> Needs a line after to pass the preprocesor
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for including dust species, which interact with the gas through a drag force.
Definition mod_dust.t:3
subroutine, public dust_to_primitive(ixil, ixol, w, x)
Definition mod_dust.t:229
subroutine, public dust_to_conserved(ixil, ixol, w, x)
Definition mod_dust.t:209
EoS state container – the single thermodynamic authority for AMRVAC.
integer, parameter, public eos_analytic
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 hydrogen Saha EoS with neutral helium (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)
Ratio eint/p from (log10 nH, log10 p/nH).
double precision function, public eint_nh_from_t(log_nh, log_t)
eint/nH from (log10 nH, log10 T), from the inverse table when one is built and the Saha solve otherwi...
double precision function, public y_from_nh_eint(nh, eint_nh)
Scalar EoS kernels: one cell on (log10 nH, log10 eint/nH) or (log10 nH, log10 p/nH),...
subroutine, public eos_get_eintt_grid(n_nh, lg_nh_min, lg_nh_max)
####################################################################### Table-metadata helpers: expos...
double precision function, public t_from_nh_eint(nh, eint_nh)
Temperature from (log10 nH, log10 eint/nH).
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:322
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:315
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:340
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:143
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:331
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
subroutine, public eos_bind_tc(fl, sat_r_variable)
The EoS hooks of the conduction fluid fl. sat_R_variable is false when R is the constant 1,...
Definition mod_eos.t:420
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision, dimension(:), allocatable, parameter d
double precision unit_temperature
Physical scaling factor for temperature.
logical fix_small_values
fix small values with average or replace methods
HD <-> EoS seam: binds the eos% authority into hydrodynamics.
Definition mod_hd_eos.t:15
subroutine, public hd_get_pthermal(w, x, ixil, ixol, pth)
Calculate thermal pressure within ixO^L. For energy runs delegates to eosget_thermal_pressure; for no...
Definition mod_hd_eos.t:342
procedure(sub_convert), pointer, public hd_to_conserved
Definition mod_hd_eos.t:34
subroutine, public hd_link_eos()
Link the appropriate EOS conversion routines based on the selected EoS type.
Definition mod_hd_eos.t:42
procedure(sub_convert), pointer, public hd_to_primitive
Definition mod_hd_eos.t:33
Hydrodynamics physics module.
Definition mod_hd_phys.t:2
integer, public, protected m
Definition mod_hd_phys.t:73
logical, public, protected hd_energy
Whether an energy equation is used.
Definition mod_hd_phys.t:15
logical, public, protected hd_dust
Whether dust is added.
Definition mod_hd_phys.t:35
integer, public, protected e_
Index of the energy density (-1 if not present).
Definition mod_hd_phys.t:79
type(tc_fluid), allocatable, public tc_fl
Definition mod_hd_phys.t:25
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
Definition mod_hd_phys.t:73
integer, public, protected rho_
Whether plasma is partially ionized.
Definition mod_hd_phys.t:67
type(fld_fluid), allocatable, public fld_fl
Radiation fluid object (gas-EoS callbacks for FLD), wired in hd_link_eos.
Definition mod_hd_phys.t:44
integer, public, protected c_
Definition mod_hd_phys.t:73
type(rc_fluid), allocatable, public rc_fl
Definition mod_hd_phys.t:32
type(te_fluid), allocatable, public te_fl_hd
Definition mod_hd_phys.t:26
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
Definition mod_hd_phys.t:82
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
double precision, parameter rc_t_ymod_max_k
Temperature in K above which c_V is constant, the upper end of the Y_mod path.
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
procedure(hd_pthermal), pointer usr_set_pthermal