MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_ffhd_eos.t
Go to the documentation of this file.
1!=============================================================================
2!> FFHD <-> EoS seam: binds the eos% authority into force-free hydrodynamics.
3!>
4!> Mirrors mod_hd_eos.t, adapted to FFHD's structure: a single field-aligned
5!> momentum component mom(1) and NO magnetic energy (force-free, frozen B0), so
6!> every kinetic-energy term is half*rho*mom(1)**2. The B0 projection lives in
7!> the flux/cmax/velocity layer (mod_ffhd_phys.t) and is orthogonal to the EoS
8!> seam, so the thermodynamic conversions are HD-like with one momentum
9!> component.
10!>
11!> ffhd_link_eos -- wires eos%/phys_ pointers per eos_type (FI now;
12!> LTE/PI guarded until milestones 2/3).
13!> ffhd_bind_eos_to_source -- wires the thermal-conduction (tc_fl), radiative-
14!> cooling (rc_fl) and thermal-emission (te_fl_ffhd)
15!> fluid-port callbacks from eos%. This is what the
16!> pre-eos% hand-wiring was missing (rc_fl%get_Te /
17!> get_ne_nH), which caused the cooling SIGSEGV.
18!=============================================================================
21 use mod_physics
22 use mod_eos
23 !> Mode-specific kernels come from their sub-modules (the facade no longer
24 !> re-exports them); each mpistops if called under the wrong eos_type/method.
25 use mod_eos_lte
27 use mod_eos_pi
31
32 use mod_comm_lib, only: mpistop
33
34 implicit none
35 private
36
37 public :: ffhd_link_eos
38
39contains
40
41 !> Link the appropriate EoS conversion/closure routines per eos_type.
42 !> Called from ffhd_activate after ffhd_phys_init (mirrors hd_activate).
43 subroutine ffhd_link_eos()
45
46 ! Isothermal FFHD (no energy equation) has no thermodynamic state for
47 ! the EoS to close -- only FI is meaningful there.
48 if (.not. ffhd_energy .and. eos%eos_type /= 'FI') &
49 call mpistop("FFHD: ffhd_energy=.false. requires eos_type='FI'")
50
51 ! FI / PI base conversions = ffhd's origin routines (single-component
52 ! KE). PI energy mode overrides them below (milestone 3). LTE routes
53 ! primitive<->conserved through ffhd_p_to_e / table inversion.
54 if (eos%eos_type == 'FI' .or. eos%eos_type == 'PI') then
55 eos%to_conserved => ffhd_to_conserved_origin
56 eos%to_primitive => ffhd_to_primitive_origin
57 else if (eos%eos_type == 'LTE') then
58 eos%to_conserved => ffhd_to_conserved_lte
59 eos%to_primitive => ffhd_to_primitive_lte
60 else
61 call mpistop("Unknown FFHD EOS type: " // trim(eos%eos_type))
62 end if
63
64 phys_to_primitive => eos%to_primitive
65 phys_to_conserved => eos%to_conserved
66 ffhd_to_primitive => eos%to_primitive
67 ffhd_to_conserved => eos%to_conserved
68 phys_get_rho => eos%get_rho
69
70 ! suitable for both FI (origin inlines it) and LTE (conversions call it)
71 eos%p_to_e => ffhd_p_to_e
72
73 ! pthermal: the isothermal (no-energy) pointer is wired in phys_init and
74 ! left untouched; for the energy equation route through eos%. LTE reads
75 ! the stored Te_/Ne_ aux state; FI/PI use (gamma-1)*(e-KE).
76 if (ffhd_energy) then
77 if (eos%eos_type == 'LTE') then
78 phys_get_pthermal => ffhd_get_pthermal_lte
79 ffhd_get_pthermal => ffhd_get_pthermal_lte
80 eos%get_thermal_pressure => ffhd_get_pthermal_lte
81 else
84 eos%get_thermal_pressure => ffhd_get_pthermal_origin
85 end if
86 end if
87
88 phys_bind_eos_to_source => ffhd_bind_eos_to_source
89
90 ! Energy<->internal heads: ffhd previously handed these only to the TC
91 ! STS via set_conversion_methods_to_head; the LTE fast-T kernel and
92 ! phys_update_temperature also need the module-level phys_ pointers.
95 phys_get_ei => ffhd_get_ei ! LTE+ionE cooling recovers eint via this
96
97 ! sound speed / gamma1. LTE+ionE: Gamma_1(nH,p) from the EoS tables and
98 ! EoS-aware AMR prolongation (interpolate in (rho,v,T) to avoid Jensen's
99 ! inequality across the ionisation plateau). Otherwise FI: cs2=gamma*p/rho.
100 if (eos%eos_type == 'LTE' .and. eos%ionE) then
101 eos%get_csound2 => ffhd_get_csound2_lte
102 phys_get_gamma1 => ffhd_get_gamma1_lte
103 phys_to_prolong => ffhd_to_prolong_lte
104 phys_from_prolong => ffhd_from_prolong_lte
105 else
106 eos%get_csound2 => ffhd_get_csound2
107 phys_get_gamma1 => get_gamma1_fi
108 end if
109
110 ! ffhd_get_temperature (phys pointer) by eos_type: PI reads the cached
111 ! Te_, the others recompute from etot.
112 if (eos%eos_type == 'PI') then
114 else
116 end if
117 ! Rfactor: only the FI case is physics-dependent (usr_Rfactor). LTE and PI
118 ! bind pure eos% routines in eos_finalise_{LTE,PI} (run after this, before
119 ! ffhd_bind_eos_to_source -> targets stay private). usr_Rfactor thus applies
120 ! to FI only, consistent with mhd/hd.
121 if (associated(usr_rfactor)) then
122 eos%get_Rfactor => usr_rfactor
123 else
125 end if
126 ! ffhd_get_Rfactor (runtime alias) captured in ffhd_bind_eos_to_source,
127 ! AFTER eos_finalise has set eos%get_Rfactor for LTE/PI.
128
129 !> PI energy-mode overrides (eos_type='PI', ionE=.true.). Energy mode
130 !> differs from no-energy PI only in the eint<->p relation (eint carries
131 !> the ionisation energy), so override exactly the routines touching it,
132 !> all via the portable mod_eos_PI backend. get_Rfactor stays the
133 !> Te_-addressed routine above (Te_ refreshed each step by
134 !> ffhd_update_temperature_PI).
135 if (eos%eos_type == 'PI' .and. eos%ionE) then
136 if (.not. ffhd_energy) &
137 call mpistop('FFHD PI energy EoS requires ffhd_energy=.true.')
138 eos%to_conserved => ffhd_to_conserved_pi
139 eos%to_primitive => ffhd_to_primitive_pi
140 phys_to_primitive => eos%to_primitive
141 phys_to_conserved => eos%to_conserved
142 ffhd_to_primitive => eos%to_primitive
143 ffhd_to_conserved => eos%to_conserved
144 eos%p_to_e => ffhd_p_to_e_pi
145 phys_get_pthermal => ffhd_get_pthermal_pi
146 ffhd_get_pthermal => ffhd_get_pthermal_pi
147 eos%get_thermal_pressure => ffhd_get_pthermal_pi
148 !> eos%get_csound2 => get_csound2_PI set in eos_finalise_PI (private target)
150 end if
151
152 end subroutine ffhd_link_eos
153
154 !> Wire the source-term fluid ports from eos%. Called from eos_finalise via
155 !> phys_bind_eos_to_source, AFTER eos_finalise has set eos%get_Te,
156 !> get_ne_nH, eion_per_nH, n_per_nH_FI/neOnH_FI, get_temperature_from_*.
157 subroutine ffhd_bind_eos_to_source()
158
159 !> Runtime R-factor alias: eos%get_Rfactor is fully set by now
160 !> (eos_finalise ran before phys_bind_eos_to_source), incl. the LTE/PI
161 !> bindings done in eos_finalise_{LTE,PI}.
162 ffhd_get_rfactor => eos%get_Rfactor
163
164 if (allocated(tc_fl)) then
165 tc_fl%get_temperature_from_conserved => eos%get_temperature_from_etot
166 if (eos%eos_type == 'LTE' .and. eos%ionE) then
167 tc_fl%get_temperature_from_eint => get_temperature_from_eint_fast_lte
168 else
169 tc_fl%get_temperature_from_eint => eos%get_temperature_from_eint
170 end if
171 tc_fl%get_rho => eos%get_rho
172 tc_fl%get_ne_nH => eos%get_ne_nH
173 tc_fl%get_var_Rfactor => eos%get_Rfactor
174 tc_fl%inv_gamma_minus_1 = eos%inv_gamma_minus_1
175 tc_fl%nH2rhoFactor = eos%nH2rhoFactor
176 tc_fl%log_T_floor = eos_get_log_t_floor()
177 tc_fl%eint_from_T => eint_nh_from_t
178 end if
179
180 if (allocated(rc_fl)) then
181 rc_fl%get_rho => eos%get_rho
182 rc_fl%get_pthermal => eos%get_thermal_pressure
183 rc_fl%get_var_Rfactor => eos%get_Rfactor
184 rc_fl%get_Te => eos%get_Te
185 rc_fl%get_ne_nH => eos%get_ne_nH
186 rc_fl%ionE = eos%ionE
187 rc_fl%method = eos%method
188 rc_fl%inv_gamma_minus_1 = eos%inv_gamma_minus_1
189 rc_fl%nH2rhoFactor = eos%nH2rhoFactor
190 rc_fl%eion_per_nH = eos%eion_per_nH
191 rc_fl%eint_from_T => eint_nh_from_t
192 rc_fl%p2eint => p2eint_from_nh_p
193 rc_fl%T_from_eint => t_from_nh_eint
194 rc_fl%y_from_eint => y_from_nh_eint
195 if (eos%ionE .and. eos%eos_type == 'LTE') then
196 call eos_get_eintt_grid(rc_fl%Y_mod_n_nH, &
197 rc_fl%Y_mod_lg_nH_min, rc_fl%Y_mod_lg_nH_max)
199 end if
200 end if
201
202 !> PI energy-mode: repoint eint<->p kernels at the portable backend.
203 if (eos%eos_type == 'PI' .and. eos%ionE) then
204 if (allocated(tc_fl)) tc_fl%eint_from_T => eint_from_t_pi
205 if (allocated(rc_fl)) then
206 rc_fl%eint_from_T => eint_from_t_pi
207 rc_fl%p2eint => p2eint_pi
208 rc_fl%T_from_eint => t_from_eint_pi
209 rc_fl%y_from_eint => y_from_eint_pi
210 end if
211 end if
212
213 {^ifthreed
214 if (allocated(te_fl_ffhd)) then
215 te_fl_ffhd%get_rho => eos%get_rho
216 te_fl_ffhd%get_pthermal => eos%get_thermal_pressure
217 te_fl_ffhd%get_var_Rfactor => eos%get_Rfactor
218 te_fl_ffhd%get_ne_nH => eos%get_ne_nH
219 end if
220 }
221
222 end subroutine ffhd_bind_eos_to_source
223
224 !=========================================================================
225 !> LTE (Saha table) thermodynamics for FFHD. Mirrors mod_hd_eos.t adapted
226 !> to FFHD's single field-aligned momentum mom(1) and total-energy-only
227 !> ("origin") formulation; no dust, no magnetic energy.
228 !=========================================================================
229
230 !> LTE primitive -> conserved. On entry rho/v/p; on exit rho/mom/E.
231 subroutine ffhd_to_conserved_lte(ixI^L, ixO^L, w, x)
233 integer, intent(in) :: ixi^l, ixo^l
234 double precision, intent(inout) :: w(ixi^s, nw)
235 double precision, intent(in) :: x(ixi^s, 1:ndim)
236
237 call ffhd_p_to_e(ixi^l, ixo^l, w, x)
238 w(ixo^s,mom(1)) = w(ixo^s,rho_)*w(ixo^s,mom(1))
239 end subroutine ffhd_to_conserved_lte
240
241 !> Convert pressure to total energy: E = eint(rho, p) + KE.
242 !> On entry rho/v/p; on exit w(e_) = total energy (rho, mom unchanged).
243 !> Four ionE paths mirror hd p_to_e: FI bypass, analytic Saha, p-bisect,
244 !> p2eint table. Non-ionE LTE uses the constant inverse-gamma relation.
245 subroutine ffhd_p_to_e(ixI^L, ixO^L, w, x)
247 integer, intent(in) :: ixi^l, ixo^l
248 double precision, intent(inout) :: w(ixi^s, nw)
249 double precision, intent(in) :: x(ixi^s, 1:ndim)
250
251 integer :: ix^d
252 double precision :: p_to_eint, p_over_rho
253 double precision :: nh(ixi^s), nh_in(ixi^s), p_in(ixi^s)
254 double precision :: log_eint_mid, eint_total
255 double precision :: t_solve, y_solve, eint_nh_solve
256
257 if (.not. ffhd_energy) return
258
259 if (eos%ionE) then
260 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
261 nh_in(ixo^s) = dlog10(nh(ixo^s))
262 if (eos%p2eint_method /= 'bisect') then
263 p_in(ixo^s) = dlog10(w(ixo^s,p_)) - nh_in(ixo^s)
264 end if
265 endif
266
267 p_to_eint = eos%inv_gamma_minus_1
268 {do ix^db=ixomin^db,ixomax^db\}
269 if (eos%ionE) then
270 p_over_rho = w(ix^d,p_) / w(ix^d,rho_)
271 if (p_over_rho > eos%p_rho_FI_threshold) then
272 p_to_eint = eos%inv_gamma_minus_1 &
273 + eos%eion_per_nH * nh(ix^d) / w(ix^d,p_)
274 w(ix^d,e_) = w(ix^d,p_)*p_to_eint + &
275 half*w(ix^d,mom(1))**2*w(ix^d,rho_)
276 else if (eos%method == 'analytic') then
277 call saha_state_from_nh_p(nh(ix^d), w(ix^d,p_), &
278 t_solve, y_solve, eint_nh_solve)
279 w(ix^d,e_) = eint_nh_solve * nh(ix^d) + &
280 half*w(ix^d,mom(1))**2*w(ix^d,rho_)
281 else if (eos%p2eint_method == 'bisect') then
282 call eint_from_p_bisect(nh_in(ix^d), &
283 dlog10(w(ix^d,p_)), log_eint_mid)
284 eint_total = nh(ix^d) * 10.0d0**log_eint_mid
285 eint_total = max(eint_total, &
286 nh(ix^d) * 10.0d0**eos%T%var2_min)
287 w(ix^d,e_) = eint_total + &
288 half*w(ix^d,mom(1))**2*w(ix^d,rho_)
289 else
290 p_to_eint = p2eint_from_nh_p(nh_in(ix^d), p_in(ix^d))
291 w(ix^d,e_) = w(ix^d,p_)*p_to_eint + &
292 half*w(ix^d,mom(1))**2*w(ix^d,rho_)
293 end if
294 else
295 w(ix^d,e_) = w(ix^d,p_)*p_to_eint + &
296 half*w(ix^d,mom(1))**2*w(ix^d,rho_)
297 end if
298 {end do\}
299 end subroutine ffhd_p_to_e
300
301 !> LTE conserved -> primitive. On entry rho/mom/E; on exit rho/v/p.
302 !> Pressure is energy-consistent from actual eint (stored Ne_/Te_ may be
303 !> stale after AMR prolong/coarsen on the nonlinear EoS).
304 subroutine ffhd_to_primitive_lte(ixI^L, ixO^L, w, x)
306 integer, intent(in) :: ixi^l, ixo^l
307 double precision, intent(inout) :: w(ixi^s, nw)
308 double precision, intent(in) :: x(ixi^s, 1:ndim)
309
310 double precision :: inv_rho
311 double precision :: nh(ixi^s), log_nh(ixi^s)
312 double precision :: eint_val, eint_in
313 integer :: ix^d
314
315 if (fix_small_values) then
316 call ffhd_handle_small_values(.false., w, x, ixi^l, ixo^l, &
317 'ffhd_to_primitive_LTE')
318 end if
319
320 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
321 if (eos%ionE) log_nh(ixo^s) = dlog10(nh(ixo^s))
322
323 {do ix^db=ixomin^db,ixomax^db\}
324 inv_rho = 1.d0/w(ix^d,rho_)
325 w(ix^d,mom(1)) = w(ix^d,mom(1))*inv_rho
326 if (ffhd_energy) then
327 if (eos%ionE) then
328 eint_val = w(ix^d,e_) - half*w(ix^d,rho_)*w(ix^d,mom(1))**2
329 if (eos%method /= 'analytic') then
330 eint_val = max(eint_val, nh(ix^d)*10.0d0**eos%T%var2_min)
331 end if
332 eint_val = max(eint_val, smalldouble)
333 if (eint_val * inv_rho > eos%eint_rho_FI_threshold) then
334 w(ix^d,p_) = eos%gamma_minus_1 &
335 * (eint_val - eos%eion_per_nH * nh(ix^d))
336 else
337 eint_in = dlog10(eint_val) - log_nh(ix^d)
338 w(ix^d,p_) = nh(ix^d) &
339 * p_nh_from_eint(log_nh(ix^d), eint_in)
340 end if
341 else
342 w(ix^d,p_) = eos%gamma_minus_1 &
343 * (w(ix^d,e_) - half*w(ix^d,rho_)*w(ix^d,mom(1))**2)
344 end if
345 end if
346 {end do\}
347 end subroutine ffhd_to_primitive_lte
348
349 !> LTE thermal pressure from the stored aux state: p = nH(1+He+ne/nH)*Te.
350 !> Mirrors the LTE branch of hd_get_pthermal (small-value guards from
351 !> ffhd_get_pthermal_origin).
352 subroutine ffhd_get_pthermal_lte(w, x, ixI^L, ixO^L, pth)
355 integer, intent(in) :: ixi^l, ixo^l
356 double precision, intent(in) :: w(ixi^s, 1:nw)
357 double precision, intent(in) :: x(ixi^s, 1:ndim)
358 double precision, intent(out):: pth(ixi^s)
359 integer :: iw, ix^d
360 double precision :: nh(ixi^s)
361
362 if (ffhd_energy) then
363 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
364 pth(ixo^s) = nh(ixo^s) * (1.0d0 + eos%He_abundance &
365 + (w(ixo^s,iw_ne) / nh(ixo^s))) * w(ixo^s,iw_te)
366 else
367 pth(ixo^s) = ffhd_adiab * w(ixo^s, rho_)**eos%gamma
368 end if
369
370 if (fix_small_values) then
371 {do ix^db= ixo^lim^db\}
372 if(pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
373 {end do^D&\}
374 else if (check_small_values) then
375 {do ix^db= ixo^lim^db\}
376 if(pth(ix^d)<small_pressure) then
377 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
378 " encountered when call ffhd_get_pthermal_LTE"
379 write(*,*) "Iteration: ", it, " Time: ", global_time
380 write(*,*) "Location: ", x(ix^d,:)
381 write(*,*) "Cell number: ", ix^d
382 do iw=1,nw
383 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
384 end do
385 if(trace_small_values) write(*,*) dsqrt(pth(ix^d)-bigdouble)
386 write(*,*) "Saving status at the previous time step"
387 crash=.true.
388 end if
389 {end do^D&\}
390 end if
391 end subroutine ffhd_get_pthermal_lte
392
393 !> cs2 = Gamma_1(LTE) * p/rho.
394 subroutine ffhd_get_csound2_lte(w, x, ixI^L, ixO^L, cs2)
396 integer, intent(in) :: ixi^l, ixo^l
397 double precision, intent(in) :: w(ixi^s, nw)
398 double precision, intent(in) :: x(ixi^s, 1:ndim)
399 double precision, intent(out) :: cs2(ixi^s)
400 integer :: ix^d
401
402 call ffhd_get_gamma1_lte(w, x, ixi^l, ixo^l, cs2)
403 {do ix^db=ixomin^db,ixomax^db\}
404 cs2(ix^d) = cs2(ix^d) * w(ix^d, p_) / w(ix^d, rho_)
405 {end do\}
406 end subroutine ffhd_get_csound2_lte
407
408 !> Effective Gamma_1 for LTE+IonE (dispatch on gamma1_method / eos%method).
409 subroutine ffhd_get_gamma1_lte(w, x, ixI^L, ixO^L, gamma1)
411 integer, intent(in) :: ixi^l, ixo^l
412 double precision, intent(in) :: w(ixi^s, nw)
413 double precision, intent(in) :: x(ixi^s, 1:ndim)
414 double precision, intent(out) :: gamma1(ixi^s)
415 double precision :: nh_val, p_over_rho
416 integer :: ix^d
417
418 if (eos%gamma1_method == 'constant') then
419 gamma1(ixo^s) = eos%gamma
420 return
421 end if
422
423 {do ix^db=ixomin^db,ixomax^db\}
424 p_over_rho = w(ix^d, p_) / w(ix^d, rho_)
425 if (p_over_rho > eos%p_rho_FI_threshold) then
426 gamma1(ix^d) = eos%gamma
427 else
428 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
429 if (eos%method == 'analytic') then
430 if (iw_te > 0 .and. w(ix^d,iw_te) > 0.0d0) then
431 gamma1(ix^d) = saha_gamma1_from_nh_t(nh_val, w(ix^d,iw_te))
432 else
433 gamma1(ix^d) = eos%gamma
434 end if
435 else
436 gamma1(ix^d) = gamma1_from_nh_p(dlog10(nh_val), &
437 dlog10(w(ix^d, p_) / nh_val))
438 end if
439 end if
440 {end do\}
441 end subroutine ffhd_get_gamma1_lte
442
443 !> Conserved (rho, rho*v, E) -> prolong form (rho, v, T); T in the e_ slot.
444 !> Interpolating in (rho, v, T) avoids Jensen's inequality across the
445 !> ionisation plateau. Mirrors hd_to_prolong_LTE.
446 subroutine ffhd_to_prolong_lte(ixI^L, ixO^L, w, x)
447 integer, intent(in) :: ixi^l, ixo^l
448 double precision, intent(inout) :: w(ixi^s, nw)
449 double precision, intent(in) :: x(ixi^s, 1:ndim)
450
451 double precision :: inv_rho, eint_val, nh_val, log_nh, t_loc, y_loc
452 integer :: ix^d
453
454 {do ix^db=ixomin^db,ixomax^db\}
455 inv_rho = 1.d0 / w(ix^d, rho_)
456 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
457 log_nh = dlog10(nh_val)
458
459 w(ix^d,mom(1)) = w(ix^d,mom(1))*inv_rho
460
461 eint_val = w(ix^d, e_) - half*w(ix^d, rho_)*w(ix^d,mom(1))**2
462 if (eos%method /= 'analytic') then
463 eint_val = max(eint_val, nh_val * 10.0d0**eos%T%var2_min)
464 end if
465 eint_val = max(eint_val, smalldouble)
466
467 if (eint_val * inv_rho > eos%eint_rho_FI_threshold) then
468 w(ix^d, e_) = eos%gamma_minus_1 &
469 * (eint_val - eos%eion_per_nH * nh_val) &
470 / (nh_val * eos%n_per_nH_FI)
471 else if (eos%method == 'analytic') then
472 call saha_t_from_nh_eint(nh_val, eint_val / nh_val, t_loc, y_loc)
473 w(ix^d, e_) = t_loc
474 else
475 w(ix^d, e_) = t_from_nh_eint(log_nh, &
476 dlog10(eint_val) - log_nh)
477 end if
478 {end do\}
479 end subroutine ffhd_to_prolong_lte
480
481 !> Prolong form (rho, v, T) -> conserved (rho, rho*v, E); T read from e_.
482 !> Mirrors hd_from_prolong_LTE.
483 subroutine ffhd_from_prolong_lte(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 :: t_val, eint_val, t_fi, nh_val, log_nh, log_t_min
489 integer :: ix^d
490
491 t_fi = (eos%eint_rho_FI_threshold &
492 * eos%nH2rhoFactor - eos%eion_per_nH) &
493 * eos%gamma_minus_1 / eos%n_per_nH_FI
494
495 if (eos%method == 'entropy') then
496 log_t_min = eos%eintT%var2_min
497 else
498 log_t_min = eos%eint_from_T%var2_min
499 end if
500
501 {do ix^db=ixomin^db,ixomax^db\}
502 t_val = w(ix^d, e_)
503 nh_val = w(ix^d, rho_) / eos%nH2rhoFactor
504 log_nh = dlog10(nh_val)
505
506 if (t_val > t_fi) then
507 eint_val = nh_val &
508 * (eos%n_per_nH_FI * t_val * eos%inv_gamma_minus_1 &
509 + eos%eion_per_nH)
510 else if (eos%method == 'analytic') then
511 eint_val = saha_eint_from_nh_t(nh_val, t_val) * nh_val
512 else
513 eint_val = eint_nh_from_t(log_nh, &
514 dlog10(max(t_val, 10.0d0**log_t_min))) * nh_val
515 end if
516
517 w(ix^d, e_) = eint_val + half*w(ix^d, rho_)*w(ix^d,mom(1))**2
518 w(ix^d,mom(1)) = w(ix^d,rho_)*w(ix^d,mom(1))
519 {end do\}
520 end subroutine ffhd_from_prolong_lte
521
522 !=========================================================================
523 !> PI energy-mode (eos_type='PI', ionE=.true.) thermodynamics for FFHD.
524 !> eint carries the ionisation-energy term, so p=(gamma-1)*eint no longer
525 !> holds; the eint<->p relation is delegated to the portable scalar backend
526 !> (mod_eos_PI). Single momentum, total-energy only. Mirrors the
527 !> hd PI-energy family.
528 !=========================================================================
529
530 !> Primitive pressure -> total energy via backend (mom(1) is velocity here).
531 subroutine ffhd_p_to_e_pi(ixI^L, ixO^L, w, x)
533 integer, intent(in) :: ixi^l, ixo^l
534 double precision, intent(inout) :: w(ixi^s, nw)
535 double precision, intent(in) :: x(ixi^s, 1:ndim)
536 double precision :: eint
537 integer :: ix^d
538
539 {do ix^db=ixomin^db,ixomax^db\}
540 if (ffhd_energy) then
541 call eint_from_rho_p_pi(w(ix^d,rho_), w(ix^d,p_), eint)
542 w(ix^d,e_) = eint + half*w(ix^d,mom(1))**2*w(ix^d,rho_)
543 end if
544 {end do\}
545 end subroutine ffhd_p_to_e_pi
546
547 !> Primitive -> conserved (PI energy).
548 subroutine ffhd_to_conserved_pi(ixI^L, ixO^L, w, x)
550 integer, intent(in) :: ixi^l, ixo^l
551 double precision, intent(inout) :: w(ixi^s, nw)
552 double precision, intent(in) :: x(ixi^s, 1:ndim)
553
554 call ffhd_p_to_e_pi(ixi^l, ixo^l, w, x)
555 w(ixo^s,mom(1)) = w(ixo^s,rho_)*w(ixo^s,mom(1))
556 end subroutine ffhd_to_conserved_pi
557
558 !> Conserved -> primitive (PI energy): KE removed -> eint, backend -> p.
559 subroutine ffhd_to_primitive_pi(ixI^L, ixO^L, w, x)
561 integer, intent(in) :: ixi^l, ixo^l
562 double precision, intent(inout) :: w(ixi^s, nw)
563 double precision, intent(in) :: x(ixi^s, 1:ndim)
564 double precision :: inv_rho, eint_val, t, rfac
565 integer :: ix^d
566
567 if (fix_small_values) then
568 call ffhd_handle_small_values(.false., w, x, ixi^l, ixo^l, &
569 'ffhd_to_primitive_PI')
570 end if
571
572 {do ix^db=ixomin^db,ixomax^db\}
573 inv_rho = 1.d0/w(ix^d,rho_)
574 w(ix^d,mom(1)) = w(ix^d,mom(1))*inv_rho
575 if (ffhd_energy) then
576 eint_val = w(ix^d,e_) - half*w(ix^d,rho_)*w(ix^d,mom(1))**2
577 eint_val = max(eint_val, smalldouble)
578 call state_from_eint_pi(w(ix^d,rho_), eint_val, &
579 t, w(ix^d,p_), rfac)
580 end if
581 {end do\}
582 end subroutine ffhd_to_primitive_pi
583
584 !> PI-energy thermal pressure: eint (= e-KE) -> p via the backend.
585 subroutine ffhd_get_pthermal_pi(w, x, ixI^L, ixO^L, pth)
587 integer, intent(in) :: ixi^l, ixo^l
588 double precision, intent(in) :: w(ixi^s, 1:nw), x(ixi^s, 1:ndim)
589 double precision, intent(out):: pth(ixi^s)
590 double precision :: ei(ixi^s), tpi, rpi
591 integer :: ix^d
592
593 ei(ixo^s) = ffhd_get_ei(w, ixi^l, ixo^l)
594 {do ix^db=ixomin^db,ixomax^db\}
595 call state_from_eint_pi(w(ix^d,rho_), ei(ix^d), tpi, pth(ix^d), rpi)
596 {end do\}
597 end subroutine ffhd_get_pthermal_pi
598
599 !> Adiabatic sound speed^2 from primitive (rho, p) via the backend.
600
601 !> Effective Gamma_1 = cs2 * rho / p (PI energy).
602
603 !> PI-energy Te_ refresh: eint (= e-KE) -> T via the backend.
604
605 !> Prominence (T,p table) R-factor from (rho, pth) -- no-energy only, so
606 !> pth=(gamma-1)*eint and R is independent of it. Mirrors hd_Rfactor_prominence.
607
608 !> Prominence (T,p) Te_ update from (rho, pth).
609
610end module mod_ffhd_eos
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').
subroutine, public saha_state_from_nh_p(nh_code, p_code, t_out, y_out, eint_nh_out)
Given (nH, p) in CODE UNITS, find T and y by solving p = nH*(1+y(T))*T_code. Uses bisection on T....
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...
subroutine, public eint_from_p_bisect(log_nh_val, log_p_val, log_eint_nh_out)
Given log10(nH) and log10(p), find log10(eint/nH) by table-guessed bisection on the forward pressure ...
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
FFHD <-> EoS seam: binds the eos% authority into force-free hydrodynamics.
subroutine, public ffhd_link_eos()
Link the appropriate EoS conversion/closure routines per eos_type. Called from ffhd_activate after ff...
Frozen-field hydrodynamics module.
integer, public, protected e_
Index of the energy density (-1 if not present)
subroutine, public ffhd_to_primitive_origin(ixil, ixol, w, x)
procedure(sub_get_pthermal), pointer, public ffhd_get_rfactor
procedure(sub_get_pthermal), pointer, public ffhd_get_temperature
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
integer, public, protected rho_
Whether plasma is partially ionized.
procedure(sub_get_pthermal), pointer, public ffhd_get_pthermal
procedure(sub_convert), pointer, public ffhd_to_conserved
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
subroutine, public ffhd_get_temperature_from_etot(w, x, ixil, ixol, res)
subroutine, public ffhd_get_csound2(w, x, ixil, ixol, csound2)
logical, public, protected ffhd_energy
Whether an energy equation is used.
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
double precision function, dimension(ixo^s), public ffhd_get_ei(w, ixil, ixol)
Internal energy eint = E_total - E_kinetic (single field-aligned momentum). Wired to phys_get_ei; the...
type(te_fluid), allocatable, public te_fl_ffhd
type of fluid for thermal emission synthesis
subroutine, public ffhd_get_pthermal_origin(w, x, ixil, ixol, pth)
procedure(sub_convert), pointer, public ffhd_to_primitive
subroutine, public ffhd_get_temperature_from_te(w, x, ixil, ixol, res)
subroutine, public ffhd_to_conserved_origin(ixil, ixol, w, x)
subroutine, public ffhd_ei_to_e(ixil, ixol, w, x)
subroutine, public rfactor_from_constant_ionization(w, x, ixil, ixol, rfactor)
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
subroutine, public ffhd_e_to_ei(ixil, ixol, w, x)
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
logical fix_small_values
fix small values with average or replace methods
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_e_to_ei), pointer phys_e_to_ei
Definition mod_physics.t:66
procedure(sub_e_to_ei), pointer phys_ei_to_e
Definition mod_physics.t:67
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