MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_ffhd_phys.t
Go to the documentation of this file.
1!> Frozen-field hydrodynamics module
3
4#include "amrvac.h"
5
6 use mod_global_parameters, only: std_len, const_c
10 use mod_physics
11 use mod_eos
12 use mod_comm_lib, only: mpistop
13
14 implicit none
15 private
16
17 !> Whether an energy equation is used
18 logical, public, protected :: ffhd_energy = .true.
19
20 !> Whether thermal conduction is used
21 logical, public, protected :: ffhd_thermal_conduction = .false.
22 !> Whether hyperbolic type thermal conduction is used
23 logical, public, protected :: ffhd_hyperbolic_tc = .false.
24 !> Whether saturation is considered for hyperbolic TC
25 logical, public, protected :: ffhd_hyperbolic_tc_sat = .false.
26 !> Whether the perpendicular hyperbolic-TC channel is enabled
27 logical, public, protected :: ffhd_hyperbolic_tc_use_perp = .false.
28 !> type of fluid for thermal conduction
29 type(tc_fluid), public, allocatable :: tc_fl
30 !> type of fluid for thermal emission synthesis
31 type(te_fluid), public, allocatable :: te_fl_ffhd
32
33 !> Whether radiative cooling is added
34 logical, public, protected :: ffhd_radiative_cooling = .false.
35 !> type of fluid for radiative cooling
36 type(rc_fluid), public, allocatable :: rc_fl
37
38 !> Whether gravity is added
39 logical, public, protected :: ffhd_gravity = .false.
40
41 !> Whether TRAC method is used
42 logical, public, protected :: ffhd_trac = .false.
43
44 !> Which TRAC method is used
45 integer, public, protected :: ffhd_trac_type=1
46
47 !> Height of the mask used in the TRAC method
48 double precision, public, protected :: ffhd_trac_mask = 0.d0
49
50 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
51 integer, public, protected :: ffhd_trac_finegrid=4
52
53 !> Whether plasma is partially ionized
54
55 !> Index of the density (in the w array)
56 integer, public, protected :: rho_
57
58 !> Indices of the momentum density
59 integer, allocatable, public, protected :: mom(:)
60
61 !> Index of the energy density (-1 if not present)
62 integer, public, protected :: e_
63
64 !> Index of the gas pressure (-1 if not present) should equal e_
65 integer, public, protected :: p_
66
67 !> Indices of temperature and electron number density (LTE stored aux state)
68 integer, public, protected :: te_
69 integer, public, protected :: ne_
70
71 !> Index of the cutoff temperature for the TRAC method
72 integer, public, protected :: tcoff_
73 integer, public, protected :: tweight_
74 integer, public, protected :: q_
75
76 !> The adiabatic index (now owned by eos%; use eos%gamma)
77
78 !> The adiabatic constant
79 double precision, public :: ffhd_adiab = 1.0d0
80
81 !> The thermal conductivity kappa in hyperbolic thermal conduction
82 double precision, public :: hyperbolic_tc_kappa
83
84 !> Helium abundance over Hydrogen (now owned by eos%; use eos%He_abundance)
85 !> Ionization fraction of H
86 !> H_ion_fr = H+/(H+ + H)
87 double precision, public, protected :: h_ion_fr=1d0
88 !> Ionization fraction of He
89 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
90 double precision, public, protected :: he_ion_fr=1d0
91 !> Ratio of number He2+ / number He+ + He2+
92 !> He_ion_fr2 = He2+/(He2+ + He+)
93 double precision, public, protected :: he_ion_fr2=1d0
94 ! used for eq of state when it is not defined by units,
95 ! the units do not contain terms related to ionization fraction
96 ! and it is p = RR * rho * T
97 double precision, public, protected :: rr=1d0
98 ! remove the below flag and assume default value = .false.
99
100
101 !define the function interface for the kinetic energy
102 abstract interface
103
104 function fun_kin_en(w, ixI^L, ixO^L, inv_rho) result(ke)
105 use mod_global_parameters, only: nw, ndim,block
106 integer, intent(in) :: ixi^l, ixo^l
107 double precision, intent(in) :: w(ixi^s, nw)
108 double precision :: ke(ixo^s)
109 double precision, intent(in), optional :: inv_rho(ixo^s)
110 end function fun_kin_en
111
112 end interface
113
114 procedure(sub_convert), pointer :: ffhd_to_primitive => null()
115 procedure(sub_convert), pointer :: ffhd_to_conserved => null()
116 procedure(sub_small_values), pointer, public :: ffhd_handle_small_values => null()
117 procedure(sub_get_pthermal), pointer :: ffhd_get_pthermal => null()
118 procedure(sub_get_pthermal), pointer :: ffhd_get_rfactor => null()
119 procedure(sub_get_pthermal), pointer :: ffhd_get_temperature => null()
120 procedure(sub_get_v), pointer :: ffhd_get_v => null()
121 procedure(fun_kin_en), pointer :: ffhd_kin_en => null()
122 ! Public methods
123 public :: ffhd_phys_init
124 public :: ffhd_kin_en
125 public :: ffhd_get_ei
126 public :: ffhd_get_pthermal
127 public :: ffhd_get_rfactor
128 public :: ffhd_get_temperature
129 public :: ffhd_get_v
130 public :: ffhd_get_rho
131 public :: ffhd_get_v_idim
132 public :: ffhd_to_conserved
133 public :: ffhd_to_primitive
134 public :: ffhd_get_csound2
135 public :: ffhd_e_to_ei
136 public :: ffhd_ei_to_e
137 ! concrete routines referenced by the mod_ffhd_eos seam
145
146contains
147
148 subroutine ffhd_read_params(files)
150 character(len=*), intent(in) :: files(:)
151 integer :: n
152
153 ! gamma and eos%He_abundance migrated to &eos_list (eos%gamma / eos%He_abundance)
154 namelist /ffhd_list/ ffhd_energy, ffhd_adiab, &
158
159 do n = 1, size(files)
160 open(unitpar, file=trim(files(n)), status="old")
161 read(unitpar, ffhd_list, end=111)
162111 close(unitpar)
163 end do
164 end subroutine ffhd_read_params
165
166 !> Write this module's parameters to a snapsoht
167 subroutine ffhd_write_info(fh)
169 integer, intent(in) :: fh
170 integer, parameter :: n_par = 1
171 double precision :: values(n_par)
172 character(len=name_len) :: names(n_par)
173 integer, dimension(MPI_STATUS_SIZE) :: st
174 integer :: er
175
176 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
177
178 names(1) = "gamma"
179 values(1) = eos%gamma
180 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
181 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
182 end subroutine ffhd_write_info
183
184 subroutine ffhd_phys_init()
188 use mod_gravity, only: gravity_init
193 integer :: itr, idir
194
195 call ffhd_read_params(par_files)
196
197 if(.not. ffhd_energy) then
200 if(mype==0) write(*,*) 'WARNING: set ffhd_thermal_conduction=F when ffhd_energy=F'
201 end if
202 if(ffhd_hyperbolic_tc) then
203 ffhd_hyperbolic_tc=.false.
204 if(mype==0) write(*,*) 'WARNING: set ffhd_hyperbolic_tc=F when ffhd_energy=F'
205 end if
208 if(mype==0) write(*,*) 'WARNING: set ffhd_radiative_cooling=F when ffhd_energy=F'
209 end if
210 if(ffhd_trac) then
211 ffhd_trac=.false.
212 if(mype==0) write(*,*) 'WARNING: set ffhd_trac=F when ffhd_energy=F'
213 end if
214 ! PI/LTE carry a thermodynamic state and so need the energy equation; only
215 ! FI is meaningful without it (also guarded in ffhd_link_eos).
216 if (eos%eos_type /= 'FI') &
217 call mpistop("eos_type "//trim(eos%eos_type)//" requires ffhd_energy=T")
218 end if
219
220 if(ffhd_hyperbolic_tc) then
222 if(mype==0) write(*,*) 'WARNING: turn off parabolic TC when using hyperbolic TC'
223 end if
224
225 physics_type = "ffhd"
226 phys_energy=ffhd_energy
227 phys_internal_e=.false.
230 ! eos_type='PI' is the single partial-ionisation selector (no legacy flag).
231
232 phys_gamma = eos%gamma
233 phys_total_energy=ffhd_energy
235
236 {^ifoned
237 if(ffhd_trac .and. ffhd_trac_type .gt. 2) then
239 if(mype==0) write(*,*) 'WARNING: reset ffhd_trac_type=1 for 1D simulation'
240 end if
241 }
242 if(ffhd_trac .and. ffhd_trac_type .le. 4) then
243 ffhd_trac_mask=bigdouble
244 if(mype==0) write(*,*) 'WARNING: set ffhd_trac_mask==bigdouble for global TRAC method'
245 end if
247
248 allocate(start_indices(number_species),stop_indices(number_species))
249 start_indices(1)=1
250 ! Determine flux variables
251 rho_ = var_set_rho()
252
253 allocate(mom(1))
254 mom(:) = var_set_momentum(1)
255
256 ! Set index of energy variable
257 if(ffhd_energy) then
258 e_ = var_set_energy() ! energy density
259 p_ = e_ ! gas pressure
260 else
261 e_ = -1
262 p_ = -1
263 end if
264
265 if(ffhd_hyperbolic_tc) then
266 q_ = var_set_fluxvar('q', 'q', need_bc=.false.)
267 need_global_cmax=.true.
268 else
269 q_=-1
270 end if
271
272 !> LTE stores Ne_/Te_ as advection-free extra vars (repopulated each step by
273 !> eos%update_eos); PI keeps Te_ as an auxiliary var for the ionisation
274 !> degree. Mirrors mhd: register here (before stop_indices) so FI leaves
275 !> nwaux=0 and the var layout byte-identical.
276 if (eos%eos_type == 'LTE') then
277 ne_ = var_set_ne()
278 te_ = var_set_te()
279 else if (eos%eos_type == 'PI') then ! PI stores Te via var_set_te (sets iw_te) so the generic mod_eos_PI getters address it like LTE
280 ne_ = -1
281 te_ = var_set_te()
282 else
283 ne_ = -1
284 te_ = -1
285 end if
286
287 ! set number of variables which need update ghostcells
288 ! set number of variables which need update ghostcells.
289 ! The EoS-derived slots Ne/Te are derived state that must stay consistent with (rho,e)
290 ! wherever the conserved state is valid, so they have to travel with it. var_set_ne /
291 ! var_set_te bump nw but neither nwflux nor nwaux, so the historic nwflux+nwaux silently
292 ! excluded them: they were never communicated, only derived, and every ghost cell held
293 ! zero until something derived it. Extend the window to whichever of them exist (they are
294 ! registered contiguously just above); FI leaves both at -1 and the window is unchanged.
295 ! bc_phys is unaffected -- it iterates nwflux+nwaux independently.
296 nwgc=nwflux+nwaux
297 if (iw_ne > 0) nwgc = max(nwgc, iw_ne)
298 if (iw_te > 0) nwgc = max(nwgc, iw_te)
299
300 ! set the index of the last flux variable for species 1
301 stop_indices(1)=nwflux
302
303 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
304 tweight_ = -1
305 if(ffhd_trac) then
306 tcoff_ = var_set_wextra()
307 iw_tcoff=tcoff_
308 if(ffhd_trac_type .ge. 3) then
309 tweight_ = var_set_wextra()
310 iw_tweight=tweight_
311 end if
312 else
313 tcoff_ = -1
314 end if
315
316 nvector = 0 ! No. vector vars
317
318 ! Check whether custom flux types have been defined
319 if(.not. allocated(flux_type)) then
320 allocate(flux_type(ndir, nwflux))
321 flux_type = flux_default
322 else if(any(shape(flux_type) /= [ndir, nwflux])) then
323 call mpistop("phys_check error: flux_type has wrong shape")
324 end if
325
326 phys_get_dt => ffhd_get_dt
327 phys_get_cmax => ffhd_get_cmax_origin
328 phys_get_tcutoff => ffhd_get_tcutoff
329 phys_get_cbounds => ffhd_get_cbounds
330 phys_to_primitive => ffhd_to_primitive_origin
332 phys_to_conserved => ffhd_to_conserved_origin
334 phys_get_flux => ffhd_get_flux
335 phys_get_v => ffhd_get_v_origin
336 ffhd_get_v => ffhd_get_v_origin
337 phys_get_rho => ffhd_get_rho
338 ffhd_kin_en => ffhd_kin_en_origin
339 phys_add_source_geom => ffhd_add_source_geom
340 phys_add_source => ffhd_add_source
341 phys_check_params => ffhd_check_params
342 phys_write_info => ffhd_write_info
343 phys_handle_small_values => ffhd_handle_small_values_origin
344 ffhd_handle_small_values => ffhd_handle_small_values_origin
345 phys_check_w => ffhd_check_w_origin
346
347 if(.not.ffhd_energy) then
348 phys_get_pthermal => ffhd_get_pthermal_iso
349 ffhd_get_pthermal => ffhd_get_pthermal_iso
350 else
351 phys_get_pthermal => ffhd_get_pthermal_origin
353 end if
354
355 ! Rfactor / temperature getter dispatch now lives in ffhd_link_eos (per eos_type)
356
357 ! derive units from basic units
358 call ffhd_physical_units()
359
360 if(ffhd_hyperbolic_tc) then
361 if(si_unit)then
362 ! parallel conduction Spitzer
364 else
365 ! in cgs
367 endif
368 end if
369 if(.not. ffhd_energy .and. ffhd_thermal_conduction) then
370 call mpistop("thermal conduction needs ffhd_energy=T")
371 end if
372 if(.not. ffhd_energy .and. ffhd_hyperbolic_tc) then
373 call mpistop("hyperbolic thermal conduction needs ffhd_energy=T")
374 end if
375 if(.not. ffhd_energy .and. ffhd_radiative_cooling) then
376 call mpistop("radiative cooling needs ffhd_energy=T")
377 end if
378
379 ! initialize thermal conduction module
381 call sts_init()
382 call tc_init_params(eos%gamma)
383
384 allocate(tc_fl)
385 call tc_get_hd_params(tc_fl,tc_params_read_ffhd)
386 call add_sts_method(ffhd_get_tc_dt_ffhd,ffhd_sts_set_source_tc_ffhd,e_,1,e_,1,.false.)
388 call set_error_handling_to_head(ffhd_tc_handle_small_e)
389 tc_fl%e_ = e_
390 tc_fl%Tcoff_ = tcoff_
391 ! get_temperature_*/get_rho/get_ne_nH/get_var_Rfactor/scalars wired in ffhd_bind_eos_to_source
392 end if
393
394 ! Initialize radiative cooling module
396 call radiative_cooling_init_params(eos%gamma,eos%He_abundance)
397 allocate(rc_fl)
398 call radiative_cooling_init(rc_fl,rc_params_read)
399 rc_fl%e_ = e_
400 rc_fl%Tcoff_ = tcoff_
401 rc_fl%subtract_equi = .false.
402 ! get_rho/get_pthermal/get_var_Rfactor/get_Te/get_ne_nH + EoS scalars/kernels
403 ! wired in ffhd_bind_eos_to_source
404 end if
405
406{^ifthreed
407 allocate(te_fl_ffhd)
408 phys_te_images => ffhd_te_images
409 ! te_fl_ffhd%get_rho/get_pthermal/get_var_Rfactor/get_ne_nH wired in ffhd_bind_eos_to_source
410}
411
412 ! Initialize gravity module
413 if(ffhd_gravity) then
414 call gravity_init()
415 end if
416
417 ! The PI ionisation backend (both ionE modes) is initialised centrally in
418 ! eos_finalise_PI (mod_eos_PI) -- mirrors hd/mhd, which no longer call
419 ! ionization_degree_init from the phys module (one source of truth; calling
420 ! it here too triggers "ionization_degree_init called more than once").
421 end subroutine ffhd_phys_init
422
423{^ifthreed
424 subroutine ffhd_te_images
427
428 select case(convert_type)
429 case('EIvtiCCmpi','EIvtuCCmpi')
431 case('ESvtiCCmpi','ESvtuCCmpi')
433 case('SIvtiCCmpi','SIvtuCCmpi')
435 case('WIvtiCCmpi','WIvtuCCmpi')
437 case default
438 call mpistop("Error in synthesize emission: Unknown convert_type")
439 end select
440 end subroutine ffhd_te_images
441}
442
443 subroutine ffhd_sts_set_source_tc_ffhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
447 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
448 double precision, intent(in) :: x(ixi^s,1:ndim)
449 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
450 double precision, intent(in) :: my_dt
451 logical, intent(in) :: fix_conserve_at_step
452 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
453 end subroutine ffhd_sts_set_source_tc_ffhd
454
455 function ffhd_get_tc_dt_ffhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
456 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
457 !where tc_k_para_i=tc_k_para*B_i**2/B**2
458 !and T=p/rho
461
462 integer, intent(in) :: ixi^l, ixo^l
463 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
464 double precision, intent(in) :: w(ixi^s,1:nw)
465 double precision :: dtnew
466
467 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
468 end function ffhd_get_tc_dt_ffhd
469
470 subroutine ffhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
472
473 integer, intent(in) :: ixi^l,ixo^l
474 double precision, intent(inout) :: w(ixi^s,1:nw)
475 double precision, intent(in) :: x(ixi^s,1:ndim)
476 integer, intent(in) :: step
477 character(len=140) :: error_msg
478
479 write(error_msg,"(a,i3)") "Thermal conduction step ", step
480 call ffhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
481 end subroutine ffhd_tc_handle_small_e
482
483 subroutine tc_params_read_ffhd(fl)
485 type(tc_fluid), intent(inout) :: fl
486 integer :: n
487 ! list parameters
488 logical :: tc_saturate=.false.
489 double precision :: tc_k_para=0d0
490 character(len=std_len) :: tc_slope_limiter="MC"
491
492 namelist /tc_list/ tc_saturate, tc_slope_limiter, tc_k_para
493
494 do n = 1, size(par_files)
495 open(unitpar, file=trim(par_files(n)), status="old")
496 read(unitpar, tc_list, end=111)
497111 close(unitpar)
498 end do
499
500 fl%tc_saturate = tc_saturate
501 fl%tc_k_para = tc_k_para
502 select case(tc_slope_limiter)
503 case ('no','none')
504 fl%tc_slope_limiter = 0
505 case ('MC')
506 ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
507 fl%tc_slope_limiter = 1
508 case('minmod')
509 ! minmod limiter
510 fl%tc_slope_limiter = 2
511 case ('superbee')
512 ! Roes superbee limiter (eq.3.51i)
513 fl%tc_slope_limiter = 3
514 case ('koren')
515 ! Barry Koren Right variant
516 fl%tc_slope_limiter = 4
517 case default
518 call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
519 end select
520 end subroutine tc_params_read_ffhd
521
522 subroutine rc_params_read(fl)
524 use mod_constants, only: bigdouble
525 type(rc_fluid), intent(inout) :: fl
526 integer :: n
527 integer :: ncool = 4000
528
529 !> Name of cooling curve
530 character(len=std_len) :: coolcurve='JCcorona'
531
532 !> Fixed temperature not lower than tlow
533 logical :: tfix=.false.
534
535 !> Lower limit of temperature
536 double precision :: tlow=bigdouble
537
538 !> Add cooling source in a split way (.true.) or un-split way (.false.)
539 logical :: rc_split=.false.
540 logical :: rad_damp=.false.
541 double precision :: rad_damp_height=0.5d0
542 double precision :: rad_damp_scale=0.15d0
543
544 namelist /rc_list/ coolcurve, ncool, tlow, tfix, rc_split, rad_damp, rad_damp_height, rad_damp_scale
545
546 do n = 1, size(par_files)
547 open(unitpar, file=trim(par_files(n)), status="old")
548 read(unitpar, rc_list, end=111)
549111 close(unitpar)
550 end do
551
552 fl%ncool=ncool
553 fl%coolcurve=coolcurve
554 fl%tlow=tlow
555 fl%Tfix=tfix
556 fl%rc_split=rc_split
557 fl%rad_damp=rad_damp
558 fl%rad_damp_height=rad_damp_height
559 fl%rad_damp_scale=rad_damp_scale
560 end subroutine rc_params_read
561
562 subroutine ffhd_check_params
566 use mod_geometry, only: coordinate
567
568
569 if (.not. ffhd_energy) then
570 if (eos%gamma <= 0.0d0) call mpistop ("Error: eos%gamma <= 0")
571 if (ffhd_adiab < 0.0d0) call mpistop ("Error: ffhd_adiab < 0")
573 else
574 if (eos%gamma <= 0.0d0 .or. eos%gamma == 1.0d0) &
575 call mpistop ("Error: eos%gamma <= 0 or eos%gamma == 1")
576 small_e = small_pressure * eos%inv_gamma_minus_1
577 end if
578
579 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
580 call mpistop("usr_set_equi_vars has to be implemented in the user file")
581 end if
582
583
584 if(mype==0)then
585 write(*,*)'====FFHD run with settings===================='
586 write(*,*)'Using mod_ffhd_phys with settings:'
587 write(*,*)'SI_unit=',si_unit
588 write(*,*)'Dimensionality :',ndim
589 write(*,*)'vector components:',ndir
590 write(*,*)'coordinate set to type,slab:',coordinate,slab
591 write(*,*)'number of variables nw=',nw
592 write(*,*)' start index iwstart=',iwstart
593 write(*,*)'number of vector variables=',nvector
594 write(*,*)'number of stagger variables nws=',nws
595 write(*,*)'number of variables with BCs=',nwgc
596 write(*,*)'number of vars with fluxes=',nwflux
597 write(*,*)'number of vars with flux + BC=',nwfluxbc
598 write(*,*)'number of auxiliary variables=',nwaux
599 write(*,*)'number of extra vars without flux=',nwextra
600 write(*,*)'number of extra vars for wextra=',nw_extra
601 write(*,*)'number of auxiliary I/O variables=',nwauxio
602 write(*,*)' ffhd_energy=',ffhd_energy
603 write(*,*)' ffhd_gravity=',ffhd_gravity
604 write(*,*)' ffhd_radiative_cooling=',ffhd_radiative_cooling
605 write(*,*)' ffhd_hyperbolic_tc=',ffhd_hyperbolic_tc
606 write(*,*)' ffhd_trac=',ffhd_trac
607 write(*,*)'number of ghostcells=',nghostcells
608 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
609 write(*,*)'==========================================='
610 endif
611 end subroutine ffhd_check_params
612
613 subroutine ffhd_physical_units()
615 double precision :: mp,kb
616 double precision :: a,b
617
618 if(si_unit) then
619 mp=mp_si
620 kb=kb_si
621 else
622 mp=mp_cgs
623 kb=kb_cgs
624 end if
625
626 ! Normalisation dispatch keyed solely on eos%eos_type (FI is the default, so
627 ! legacy parfiles that set neither eos_type nor any flag land in the FI/PI
628 ! absorbed-(a,b), RR=1 branch -- the historical eq_state_units=.true. result).
629 if (eos%eos_type == 'LTE') then
630 !> Remove the assumed FI normalisation from the units; handle in EoS.
631 a=1d0
632 b=1d0
633 eos%nH2rhoFactor = 1d0+4d0*eos%He_abundance
634 rr=(2d0+3d0*eos%He_abundance)/(1d0+4d0*eos%He_abundance)
635 else
636 !> FI / PI: absorbed-(a,b), RR=1. The (1+4He) factor is absorbed into
637 !> unit_density, so nH2rhoFactor stays at the eos_init default of 1 (else
638 !> get_ne_nH would double-divide rho and under-cool by (1+4He)^2).
639 a=1d0+4d0*eos%He_abundance
640 if(eos%eos_type=='PI') then
641 b=1d0+h_ion_fr+eos%He_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0)
642 else
643 b=2d0+3d0*eos%He_abundance
644 end if
645 rr=1d0
646 end if
647 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
648 if(unit_density/=1.d0) then
650 else if(unit_numberdensity/=1.d0) then
652 end if
653 if(unit_temperature/=1.d0) then
656 if(unit_length/=1.d0) then
658 else if(unit_time/=1.d0) then
660 end if
661 else if(unit_pressure/=1.d0) then
664 if(unit_length/=1.d0) then
666 else if(unit_time/=1.d0) then
668 end if
669 else if(unit_velocity/=1.d0) then
672 if(unit_length/=1.d0) then
674 else if(unit_time/=1.d0) then
676 end if
677 else if(unit_time/=1.d0) then
681 end if
682 else if(unit_temperature/=1.d0) then
683 ! units of temperature and velocity are dependent
684 if(unit_pressure/=1.d0) then
688 if(unit_length/=1.d0) then
690 else if(unit_time/=1.d0) then
692 end if
693 end if
694 else if(unit_pressure/=1.d0) then
695 if(unit_velocity/=1.d0) then
699 if(unit_length/=1.d0) then
701 else if(unit_time/=1.d0) then
703 end if
704 else if(unit_time/=0.d0) then
709 end if
710 end if
712 end subroutine ffhd_physical_units
713
714 subroutine ffhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
716 logical, intent(in) :: primitive
717 integer, intent(in) :: ixi^l, ixo^l
718 double precision, intent(in) :: w(ixi^s,nw)
719 double precision :: tmp(ixi^s)
720 logical, intent(inout) :: flag(ixi^s,1:nw)
721
722 flag=.false.
723 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
724
725 if(ffhd_energy) then
726 if(primitive) then
727 where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
728 else
729 tmp(ixo^s)=w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l)
730 where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
731 end if
732 end if
733 end subroutine ffhd_check_w_origin
734
735 subroutine ffhd_to_conserved_origin(ixI^L,ixO^L,w,x)
737 integer, intent(in) :: ixi^l, ixo^l
738 double precision, intent(inout) :: w(ixi^s, nw)
739 double precision, intent(in) :: x(ixi^s, 1:ndim)
740
741 if(ffhd_energy) then
742 w(ixo^s,e_)=w(ixo^s,p_)*eos%inv_gamma_minus_1+half*w(ixo^s,mom(1))**2*w(ixo^s,rho_)
743 end if
744 w(ixo^s,mom(1))=w(ixo^s,rho_)*w(ixo^s,mom(1))
745 end subroutine ffhd_to_conserved_origin
746
747 subroutine ffhd_to_primitive_origin(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 if(fix_small_values) then
754 call ffhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'ffhd_to_primitive_origin')
755 end if
756
757 w(ixo^s,mom(1)) = w(ixo^s,mom(1))/w(ixo^s,rho_)
758 if(ffhd_energy) then
759 w(ixo^s,p_)=eos%gamma_minus_1*(w(ixo^s,e_)-half*w(ixo^s,rho_)*w(ixo^s,mom(1))**2)
760 end if
761 end subroutine ffhd_to_primitive_origin
762
763 subroutine ffhd_ei_to_e(ixI^L,ixO^L,w,x)
765 integer, intent(in) :: ixi^l, ixo^l
766 double precision, intent(inout) :: w(ixi^s, nw)
767 double precision, intent(in) :: x(ixi^s, 1:ndim)
768
769 w(ixo^s,e_)=w(ixo^s,e_)+ffhd_kin_en(w,ixi^l,ixo^l)
770 end subroutine ffhd_ei_to_e
771
772 subroutine ffhd_e_to_ei(ixI^L,ixO^L,w,x)
774 integer, intent(in) :: ixi^l, ixo^l
775 double precision, intent(inout) :: w(ixi^s, nw)
776 double precision, intent(in) :: x(ixi^s, 1:ndim)
777
778 ! Restrict to ixO^L (mirrors hd/mhd): update_eos_LTE calls phys_e_to_ei
779 ! over the mesh interior while ixI^S still spans unfilled corner ghosts
780 ! (rho=0 -> SIGFPE in ffhd_kin_en). FI is unaffected (update_eos_FI no-op;
781 ! the TC STS heads pass the range they need).
782 w(ixo^s,e_)=w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l)
783 if(fix_small_values) then
784 call ffhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'ffhd_e_to_ei')
785 end if
786 end subroutine ffhd_e_to_ei
787
788 !> Internal energy eint = E_total - E_kinetic (single field-aligned momentum).
789 !> Wired to phys_get_ei; the LTE+ionE radiative cooling uses it to recover the
790 !> gas internal energy from the conserved state.
791 function ffhd_get_ei(w, ixI^L, ixO^L) result(ei)
793 integer, intent(in) :: ixi^l, ixo^l
794 double precision, intent(in) :: w(ixi^s, nw)
795 double precision :: ei(ixo^s)
796
797 ei(ixo^s) = w(ixo^s,e_) - ffhd_kin_en(w,ixi^l,ixo^l)
798 end function ffhd_get_ei
799
800 subroutine ffhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
803 logical, intent(in) :: primitive
804 integer, intent(in) :: ixi^l,ixo^l
805 double precision, intent(inout) :: w(ixi^s,1:nw)
806 double precision, intent(in) :: x(ixi^s,1:ndim)
807 character(len=*), intent(in) :: subname
808
809 logical :: flag(ixi^s,1:nw)
810 double precision :: tmp2(ixi^s)
811
812 call phys_check_w(primitive, ixi^l, ixi^l, w, flag)
813
814 if(any(flag)) then
815 select case (small_values_method)
816 case ("replace")
817 where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
818 if(small_values_fix_iw(mom(1))) then
819 where(flag(ixo^s,rho_)) w(ixo^s, mom(1)) = 0.0d0
820 end if
821 if(ffhd_energy) then
822 if(primitive) then
823 where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
824 else
825 where(flag(ixo^s,e_))
826 w(ixo^s,e_) = small_e+ffhd_kin_en(w,ixi^l,ixo^l)
827 end where
828 end if
829 end if
830 case ("average")
831 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
832 if(ffhd_energy) then
833 if(primitive) then
834 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
835 else
836 w(ixi^s,e_)=w(ixi^s,e_)-ffhd_kin_en(w,ixi^l,ixi^l)
837 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
838 w(ixi^s,e_)=w(ixi^s,e_)+ffhd_kin_en(w,ixi^l,ixi^l)
839 end if
840 end if
841 case default
842 if(.not.primitive) then
843 if(ffhd_energy) then
844 w(ixo^s,p_)=eos%gamma_minus_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
845 end if
846 w(ixo^s,mom(1))=w(ixo^s,mom(1))/w(ixo^s,rho_)
847 end if
848 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
849 end select
850 end if
851 end subroutine ffhd_handle_small_values_origin
852
853 subroutine ffhd_get_v_origin(w,x,ixI^L,ixO^L,v)
855 integer, intent(in) :: ixi^l, ixo^l
856 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
857 double precision, intent(out) :: v(ixi^s,ndir)
858 double precision :: rho(ixi^s)
859 integer :: idir
860
861 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
862 rho(ixo^s)=1.d0/rho(ixo^s)
863 do idir=1,ndir
864 v(ixo^s,ndir) = w(ixo^s,mom(1))*block%B0(ixo^s,idir,0)*rho(ixo^s)
865 end do
866 end subroutine ffhd_get_v_origin
867
868 subroutine ffhd_get_v_idim(w,x,ixI^L,ixO^L,idim,v)
870 integer, intent(in) :: ixi^l, ixo^l, idim
871 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
872 double precision, intent(out) :: v(ixi^s)
873 double precision :: rho(ixi^s)
874
875 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
876 v(ixo^s) = (w(ixo^s, mom(1))*block%B0(ixo^s,idim,0)) / rho(ixo^s)
877 end subroutine ffhd_get_v_idim
878
879 subroutine ffhd_get_cmax_origin(wprim,x,ixI^L,ixO^L,idim,cmax)
881 integer, intent(in) :: ixi^l, ixo^l, idim
882 ! w in primitive form
883 double precision, intent(in) :: wprim(ixi^s, nw), x(ixi^s,1:ndim)
884 double precision, intent(inout) :: cmax(ixi^s)
885
886 if(ffhd_energy) then
887 if (eos%ionE) then
888 ! LTE/PI energy: Gamma_1(p,rho)*p/rho from the EoS (wprim is primitive)
889 call eos%get_csound2(wprim,x,ixi^l,ixo^l,cmax)
890 cmax(ixo^s)=dsqrt(cmax(ixo^s))
891 else
892 cmax(ixo^s)=dsqrt(eos%gamma*wprim(ixo^s,p_)/wprim(ixo^s,rho_))
893 end if
894 else
895 cmax(ixo^s)=dsqrt(eos%gamma*ffhd_adiab*wprim(ixo^s,rho_)**eos%gamma_minus_1)
896 end if
897 cmax(ixo^s)=dabs(wprim(ixo^s,mom(1))*block%B0(ixo^s,idim,0))+cmax(ixo^s)
898
899 end subroutine ffhd_get_cmax_origin
900
901 subroutine ffhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
903 use mod_geometry
904 integer, intent(in) :: ixi^l,ixo^l
905 double precision, intent(in) :: x(ixi^s,1:ndim)
906 double precision, intent(inout) :: w(ixi^s,1:nw)
907 double precision, intent(out) :: tco_local,tmax_local
908 double precision, parameter :: trac_delta=0.25d0
909 double precision :: te(ixi^s),lts(ixi^s)
910 double precision, dimension(ixI^S,1:ndim) :: gradt
911 double precision :: bdir(ndim)
912 double precision :: ltrc,ltrp,altr
913 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
914 integer :: jxp^l,hxp^l,ixp^l,ixq^l
915 logical :: lrlt(ixi^s)
916
917 call ffhd_get_temperature(w,x,ixi^l,ixi^l,te)
918 tco_local=zero
919 tmax_local=maxval(te(ixo^s))
920
921 {^ifoned
922 select case(ffhd_trac_type)
923 case(0)
924 !> test case, fixed cutoff temperature
925 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
926 case(1)
927 hxo^l=ixo^l-1;
928 jxo^l=ixo^l+1;
929 lts(ixo^s)=0.5d0*dabs(te(jxo^s)-te(hxo^s))/te(ixo^s)
930 lrlt=.false.
931 where(lts(ixo^s) > trac_delta)
932 lrlt(ixo^s)=.true.
933 end where
934 if(any(lrlt(ixo^s))) then
935 tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
936 end if
937 case(2)
938 !> iijima et al. 2021, LTRAC method
939 ltrc=1.5d0
940 ltrp=4.d0
941 ixp^l=ixo^l^ladd1;
942 hxo^l=ixo^l-1;
943 jxo^l=ixo^l+1;
944 hxp^l=ixp^l-1;
945 jxp^l=ixp^l+1;
946 lts(ixp^s)=0.5d0*dabs(te(jxp^s)-te(hxp^s))/te(ixp^s)
947 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
948 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
949 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
950 case default
951 call mpistop("ffhd_trac_type not allowed for 1D simulation")
952 end select
953 }
954 {^nooned
955 select case(ffhd_trac_type)
956 case(0)
957 !> test case, fixed cutoff temperature
958 if(slab_uniform) then
959 !> assume cgs units
960 block%wextra(ixi^s,tcoff_)=max(min(3.d5/unit_temperature,6.d5/unit_temperature-3.d-4/unit_temperature*unit_length*x(ixi^s,ndim)),zero)
961 else
962 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
963 end if
964 case(1,4,6)
965 do idims=1,ndim
966 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
967 end do
968 if(ffhd_trac_type .gt. 1) then
969 ! B direction at cell center
970 bdir=zero
971 {do ixa^d=0,1\}
972 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
973 bdir(1:ndim)=bdir(1:ndim)+block%B0(ixb^d,1:ndim,0)
974 {end do\}
975 if(sum(bdir(:)**2) .gt. zero) then
976 bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
977 end if
978 block%special_values(3:ndim+2)=bdir(1:ndim)
979 end if
980 {do ix^db=ixomin^db,ixomax^db\}
981 {^iftwod
982 ! temperature length scale inversed
983 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
984 abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
985 }
986 {^ifthreed
987 ! temperature length scale inversed
988 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
989 abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
990 }
991 if(lts(ix^d)>trac_delta) then
992 block%special_values(1)=max(block%special_values(1),te(ix^d))
993 end if
994 {end do\}
995 block%special_values(2)=tmax_local
996 case(2)
997 !> iijima et al. 2021, LTRAC method
998 ltrc=1.5d0
999 ltrp=4.d0
1000 ixp^l=ixo^l^ladd2;
1001 do idims=1,ndim
1002 ixq^l=ixp^l;
1003 hxp^l=ixp^l;
1004 jxp^l=ixp^l;
1005 select case(idims)
1006 {case(^d)
1007 ixqmin^d=ixqmin^d+1
1008 ixqmax^d=ixqmax^d-1
1009 hxpmax^d=ixpmin^d
1010 jxpmin^d=ixpmax^d
1011 \}
1012 end select
1013 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
1014 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
1015 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
1016 end do
1017 {do ix^db=ixpmin^db,ixpmax^db\}
1018 ! temperature length scale inversed
1019 lts(ix^d)=abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
1020 ! fraction of cells size to temperature length scale
1021 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
1022 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
1023 {end do\}
1024
1025 ! need one ghost layer for thermal conductivity
1026 ixp^l=ixo^l^ladd1;
1027 {do ix^db=ixpmin^db,ixpmax^db\}
1028 {^iftwod
1029 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*block%B0(ix^d,1,0)**2+&
1030 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*block%B0(ix^d,2,0)**2)
1031 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
1032 }
1033 {^ifthreed
1034 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*block%B0(ix^d,1,0)**2+&
1035 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*block%B0(ix^d,2,0)**2+&
1036 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*block%B0(ix^d,3,0)**2)
1037 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
1038 }
1039 {end do\}
1040 case(3,5)
1041 !> do nothing here
1042 case default
1043 call mpistop("unknown ffhd_trac_type")
1044 end select
1045 }
1046 end subroutine ffhd_get_tcutoff
1047
1048 subroutine ffhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
1050 integer, intent(in) :: ixi^l, ixo^l, idim
1051 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
1052 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1053 double precision, intent(in) :: x(ixi^s,1:ndim)
1054 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
1055 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
1056 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
1057 double precision :: wmean(ixi^s,nw), wmeanp(ixi^s,nw)
1058 double precision, dimension(ixI^S) :: umean, dmean, csoundl, csoundr, tmp1,tmp2,tmp3
1059
1060 select case (boundspeed)
1061 case (1)
1062 ! This implements formula (10.52) from "Riemann Solvers and Numerical
1063 ! Methods for Fluid Dynamics" by Toro.
1064 tmp1(ixo^s)=dsqrt(wlp(ixo^s,rho_))
1065 tmp2(ixo^s)=dsqrt(wrp(ixo^s,rho_))
1066 tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
1067 umean(ixo^s)=(wlp(ixo^s,mom(1))*tmp1(ixo^s)&
1068 +wrp(ixo^s,mom(1))*tmp2(ixo^s))*tmp3(ixo^s)
1069 umean(ixo^s)=umean(ixo^s)*block%B0(ixo^s,idim,idim)
1070 call ffhd_csound2_cbounds(wlc,wlp,x,ixi^l,ixo^l,csoundl)
1071 call ffhd_csound2_cbounds(wrc,wrp,x,ixi^l,ixo^l,csoundr)
1072 dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)+tmp2(ixo^s)*csoundr(ixo^s)) * &
1073 tmp3(ixo^s) + 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2 * &
1074 ((wrp(ixo^s,mom(1))-wlp(ixo^s,mom(1)))*block%B0(ixo^s,idim,idim))**2
1075 dmean(ixo^s)=dsqrt(dmean(ixo^s))
1076 if(present(cmin)) then
1077 cmin(ixo^s,1)=umean(ixo^s)-dmean(ixo^s)
1078 cmax(ixo^s,1)=umean(ixo^s)+dmean(ixo^s)
1079 else
1080 cmax(ixo^s,1)=dabs(umean(ixo^s))+dmean(ixo^s)
1081 end if
1082 case (2)
1083 wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
1084 tmp1(ixo^s)=wmean(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)/wmean(ixo^s,rho_)
1085 if (eos%ionE) then
1086 wmeanp(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
1087 call eos%get_csound2(wmeanp,x,ixi^l,ixo^l,csoundr)
1088 else
1089 call ffhd_get_csound2(wmean,x,ixi^l,ixo^l,csoundr)
1090 end if
1091 csoundr(ixo^s) = dsqrt(csoundr(ixo^s))
1092 if(present(cmin)) then
1093 cmax(ixo^s,1)=max(tmp1(ixo^s)+csoundr(ixo^s),zero)
1094 cmin(ixo^s,1)=min(tmp1(ixo^s)-csoundr(ixo^s),zero)
1095 else
1096 cmax(ixo^s,1)=dabs(tmp1(ixo^s))+csoundr(ixo^s)
1097 end if
1098 case (3)
1099 ! Miyoshi 2005 JCP 208, 315 equation (67)
1100 call ffhd_csound2_cbounds(wlc,wlp,x,ixi^l,ixo^l,csoundl)
1101 call ffhd_csound2_cbounds(wrc,wrp,x,ixi^l,ixo^l,csoundr)
1102 csoundl(ixo^s)=max(dsqrt(csoundl(ixo^s)),dsqrt(csoundr(ixo^s)))
1103 if(present(cmin)) then
1104 cmin(ixo^s,1)=min(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1105 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))-csoundl(ixo^s)
1106 cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1107 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1108 else
1109 cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1110 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1111 end if
1112 end select
1113 end subroutine ffhd_get_cbounds
1114
1115 !> Sound speed^2 at a Riemann interface. FI uses the conserved-state pthermal
1116 !> path (bit-identical to the legacy ffhd_get_csound2(wC) call); LTE uses the
1117 !> primitive Gamma_1*p/rho via eos% because the stored Te_/Ne_ are NOT
1118 !> reconstructed onto interface states (they are advection-free extra vars).
1119 subroutine ffhd_csound2_cbounds(wC,wp,x,ixI^L,ixO^L,cs2)
1121 integer, intent(in) :: ixi^l, ixo^l
1122 double precision, intent(in) :: wc(ixi^s,nw), wp(ixi^s,nw), x(ixi^s,1:ndim)
1123 double precision, intent(out):: cs2(ixi^s)
1124
1125 if (eos%ionE) then
1126 call eos%get_csound2(wp,x,ixi^l,ixo^l,cs2)
1127 else
1128 call ffhd_get_csound2(wc,x,ixi^l,ixo^l,cs2)
1129 end if
1130 end subroutine ffhd_csound2_cbounds
1131
1132 subroutine ffhd_get_pthermal_iso(w,x,ixI^L,ixO^L,pth)
1134
1135 integer, intent(in) :: ixi^l, ixo^l
1136 double precision, intent(in) :: w(ixi^s,nw)
1137 double precision, intent(in) :: x(ixi^s,1:ndim)
1138 double precision, intent(out):: pth(ixi^s)
1139
1140 call ffhd_get_rho(w,x,ixi^l,ixo^l,pth)
1141 pth(ixo^s)=ffhd_adiab*pth(ixo^s)**eos%gamma
1142 end subroutine ffhd_get_pthermal_iso
1143
1144 subroutine ffhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
1147 integer, intent(in) :: ixi^l, ixo^l
1148 double precision, intent(in) :: w(ixi^s,nw)
1149 double precision, intent(in) :: x(ixi^s,1:ndim)
1150 double precision, intent(out):: pth(ixi^s)
1151 integer :: iw, ix^d
1152
1153 pth(ixo^s)=eos%gamma_minus_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
1154 if (fix_small_values) then
1155 {do ix^db= ixo^lim^db\}
1156 if(pth(ix^d)<small_pressure) then
1157 pth(ix^d)=small_pressure
1158 end if
1159 {end do^D&\}
1160 elseif(check_small_values) then
1161 {do ix^db= ixo^lim^db\}
1162 if(pth(ix^d)<small_pressure) then
1163 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1164 " encountered when call ffhd_get_pthermal"
1165 write(*,*) "Iteration: ", it, " Time: ", global_time
1166 write(*,*) "Location: ", x(ix^d,:)
1167 write(*,*) "Cell number: ", ix^d
1168 do iw=1,nw
1169 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1170 end do
1171 ! use erroneous arithmetic operation to crash the run
1172 if(trace_small_values) write(*,*) dsqrt(pth(ix^d)-bigdouble)
1173 write(*,*) "Saving status at the previous time step"
1174 crash=.true.
1175 end if
1176 {end do^D&\}
1177 end if
1178 end subroutine ffhd_get_pthermal_origin
1179
1180 subroutine ffhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
1182 integer, intent(in) :: ixi^l, ixo^l
1183 double precision, intent(in) :: w(ixi^s, 1:nw)
1184 double precision, intent(in) :: x(ixi^s, 1:ndim)
1185 double precision, intent(out):: res(ixi^s)
1186
1187 res(ixo^s) = w(ixo^s, te_)
1188 end subroutine ffhd_get_temperature_from_te
1189
1190 subroutine ffhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
1192 integer, intent(in) :: ixi^l, ixo^l
1193 double precision, intent(in) :: w(ixi^s, 1:nw)
1194 double precision, intent(in) :: x(ixi^s, 1:ndim)
1195 double precision, intent(out):: res(ixi^s)
1196 double precision :: r(ixi^s)
1197
1198 call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1199 res(ixo^s) = eos%gamma_minus_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
1200 end subroutine ffhd_get_temperature_from_eint
1201
1202 subroutine ffhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
1204 integer, intent(in) :: ixi^l, ixo^l
1205 double precision, intent(in) :: w(ixi^s, 1:nw)
1206 double precision, intent(in) :: x(ixi^s, 1:ndim)
1207 double precision, intent(out):: res(ixi^s)
1208
1209 double precision :: r(ixi^s)
1210
1211 call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1212 call ffhd_get_pthermal(w,x,ixi^l,ixo^l,res)
1213 res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
1214 end subroutine ffhd_get_temperature_from_etot
1215
1216 subroutine ffhd_get_csound2(w,x,ixI^L,ixO^L,csound2)
1218 integer, intent(in) :: ixi^l, ixo^l
1219 double precision, intent(in) :: w(ixi^s,nw)
1220 double precision, intent(in) :: x(ixi^s,1:ndim)
1221 double precision, intent(out) :: csound2(ixi^s)
1222 double precision :: rho(ixi^s)
1223
1224 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1225 if(ffhd_energy) then
1226 call ffhd_get_pthermal(w,x,ixi^l,ixo^l,csound2)
1227 csound2(ixo^s)=eos%gamma*csound2(ixo^s)/rho(ixo^s)
1228 else
1229 csound2(ixo^s)=eos%gamma*ffhd_adiab*rho(ixo^s)**eos%gamma_minus_1
1230 end if
1231 end subroutine ffhd_get_csound2
1232
1233 subroutine ffhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
1235 use mod_geometry
1236 integer, intent(in) :: ixi^l, ixo^l, idim
1237 ! conservative w
1238 double precision, intent(in) :: wc(ixi^s,nw)
1239 ! primitive w
1240 double precision, intent(in) :: w(ixi^s,nw)
1241 double precision, intent(in) :: x(ixi^s,1:ndim)
1242 double precision,intent(out) :: f(ixi^s,nwflux)
1243 double precision :: ptotal(ixo^s)
1244
1245 f(ixo^s,rho_)=w(ixo^s,mom(1))*w(ixo^s,rho_)*block%B0(ixo^s,idim,idim)
1246
1247 if(ffhd_energy) then
1248 ptotal(ixo^s)=w(ixo^s,p_)
1249 else
1250 ptotal(ixo^s)=ffhd_adiab*w(ixo^s,rho_)**eos%gamma
1251 end if
1252
1253 ! Get flux of momentum
1254 f(ixo^s,mom(1))=(wc(ixo^s,mom(1))*w(ixo^s,mom(1))+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1255
1256 ! Get flux of energy
1257 if(ffhd_energy) then
1258 f(ixo^s,e_)=w(ixo^s,mom(1))*(wc(ixo^s,e_)+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1259 if(ffhd_hyperbolic_tc) then
1260 f(ixo^s,e_)=f(ixo^s,e_)+w(ixo^s,q_)*block%B0(ixo^s,idim,idim)
1261 f(ixo^s,q_)=zero
1262 end if
1263 end if
1264 end subroutine ffhd_get_flux
1265
1266 subroutine ffhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
1270 integer, intent(in) :: ixi^l, ixo^l
1271 double precision, intent(in) :: qdt,dtfactor
1272 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
1273 double precision, intent(inout) :: w(ixi^s,1:nw)
1274 logical, intent(in) :: qsourcesplit
1275 logical, intent(inout) :: active
1276
1277 if (.not. qsourcesplit) then
1278 active = .true.
1279 call add_punitb(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1280 if(ffhd_hyperbolic_tc) then
1281 call add_hyperbolic_tc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1282 end if
1283 end if
1284
1285 if(ffhd_radiative_cooling) then
1286 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1287 w,x,qsourcesplit,active, rc_fl)
1288 end if
1289
1290 if(ffhd_gravity) then
1291 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1292 w,x,ffhd_energy,qsourcesplit,active)
1293 end if
1294
1295 ! update temperature from new pressure, density, and old ionization degree
1296 if(eos%eos_type == 'PI') then
1297 if(.not.qsourcesplit) then
1298 active = .true.
1299 call eos%update_eos(ixi^l,ixo^l,w,x)
1300 end if
1301 end if
1302 end subroutine ffhd_add_source
1303
1304 subroutine add_punitb(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1306 use mod_geometry
1307 integer, intent(in) :: ixi^l,ixo^l
1308 double precision, intent(in) :: qdt
1309 double precision, intent(in) :: wct(ixi^s,1:nw),x(ixi^s,1:ndim)
1310 double precision, intent(in) :: wctprim(ixi^s,1:nw)
1311 double precision, intent(inout) :: w(ixi^s,1:nw)
1312
1313 integer :: idims,hxo^l
1314 double precision :: divb(ixi^s)
1315 double precision :: rhovpar(ixi^s),gradrhov(ixi^s)
1316
1317 divb=zero
1318 if(slab_uniform) then
1319 do idims=1,ndim
1320 hxo^l=ixo^l-kr(idims,^d);
1321 divb(ixo^s)=divb(ixo^s)+(block%B0(ixo^s,idims,idims)-block%B0(hxo^s,idims,idims))/dxlevel(idims)
1322 end do
1323 else
1324 call divvector(block%B0(ixi^s,1:ndir,0),ixi^l,ixo^l,divb)
1325 end if
1326 w(ixo^s,mom(1))=w(ixo^s,mom(1))+qdt*wctprim(ixo^s,p_)*divb(ixo^s)
1327 end subroutine add_punitb
1328
1329 subroutine ffhd_get_rho(w,x,ixI^L,ixO^L,rho)
1331 integer, intent(in) :: ixi^l, ixo^l
1332 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
1333 double precision, intent(out) :: rho(ixi^s)
1334
1335 rho(ixo^s) = w(ixo^s,rho_)
1336 end subroutine ffhd_get_rho
1337
1338 subroutine ffhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
1341 integer, intent(in) :: ixi^l,ixo^l, ie
1342 double precision, intent(inout) :: w(ixi^s,1:nw)
1343 double precision, intent(in) :: x(ixi^s,1:ndim)
1344 character(len=*), intent(in) :: subname
1345 integer :: idir
1346 logical :: flag(ixi^s,1:nw)
1347 double precision :: rho(ixi^s)
1348
1349 flag=.false.
1350 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
1351 if(any(flag(ixo^s,ie))) then
1352 select case (small_values_method)
1353 case ("replace")
1354 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
1355 case ("average")
1356 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
1357 case default
1358 w(ixo^s,e_)=w(ixo^s,e_)*eos%gamma_minus_1
1359 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1360 w(ixo^s,mom(1)) = w(ixo^s,mom(1))/rho(ixo^s)
1361 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
1362 end select
1363 end if
1364 end subroutine ffhd_handle_small_ei
1365
1366
1367 subroutine ffhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
1369 use mod_usr_methods
1370 use mod_gravity, only: gravity_get_dt
1371 integer, intent(in) :: ixi^l, ixo^l
1372 double precision, intent(inout) :: dtnew
1373 double precision, intent(in) :: dx^d
1374 double precision, intent(in) :: wprim(ixi^s,1:nw)
1375 double precision, intent(in) :: x(ixi^s,1:ndim)
1376
1377 dtnew = bigdouble
1378
1379 if(ffhd_gravity) then
1380 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
1381 end if
1382 end subroutine ffhd_get_dt
1383
1384 subroutine ffhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
1386 integer, intent(in) :: ixi^l, ixo^l
1387 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
1388 double precision, intent(inout) :: wct(ixi^s,1:nw), wprim(ixi^s,1:nw),w(ixi^s,1:nw)
1389
1390 ! no geometric source terms needed for ffhd, no divergences of tensors
1391 end subroutine ffhd_add_source_geom
1392
1393 function ffhd_kin_en_origin(w, ixI^L, ixO^L, inv_rho) result(ke)
1394 use mod_global_parameters, only: nw, ndim,block
1395 integer, intent(in) :: ixi^l, ixo^l
1396 double precision, intent(in) :: w(ixi^s, nw)
1397 double precision :: ke(ixo^s)
1398 double precision, intent(in), optional :: inv_rho(ixo^s)
1399
1400 if(present(inv_rho)) then
1401 ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2*inv_rho(ixo^s)
1402 else
1403 ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2/w(ixo^s,rho_)
1404 end if
1405 end function ffhd_kin_en_origin
1406
1407
1408 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
1410 integer, intent(in) :: ixi^l, ixo^l
1411 double precision, intent(in) :: w(ixi^s,1:nw)
1412 double precision, intent(in) :: x(ixi^s,1:ndim)
1413 double precision, intent(out):: rfactor(ixi^s)
1414
1415 rfactor(ixo^s)=rr
1417
1418 subroutine add_hyperbolic_tc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1420
1421 integer, intent(in) :: ixi^l,ixo^l
1422 double precision, intent(in) :: qdt
1423 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
1424 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
1425 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
1426
1427 double precision, dimension(ixI^S) :: te, r
1428 double precision :: sigma_t5,sigma_t7,sigmat5_bgradt,f_sat,tau
1429 integer :: ix^d
1430
1431 ! EoS-aware temperature: T = p/(R*rho). For FI R=RR (=1 under eq_state_units)
1432 ! recovers p/rho; for LTE R=Rfactor_from_LTE varies, so LTE+HTC is physically
1433 ! consistent. Computed over ixI^L (the +-2 stencil reaches ghost layers;
1434 ! their R uses the update_eos_4_bc-refreshed aux state, as in mhd).
1435 call ffhd_get_rfactor(wct,x,ixi^l,ixi^l,r)
1436 te(ixi^s)=wctprim(ixi^s,p_)/(r(ixi^s)*wct(ixi^s,rho_))
1437 ! temperature on face T_(i+1/2)=(7(T_i+T_(i+1))-(T_(i-1)+T_(i+2)))/12
1438 ! T_(i+1/2)-T_(i-1/2)=(8(T_(i+1)-T_(i-1))-T_(i+2)+T_(i-2))/12
1439 {^iftwod
1440 do ix2=ixomin2,ixomax2
1441 do ix1=ixomin1,ixomax1
1442 if(ffhd_trac) then
1443 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
1444 sigma_t5=hyperbolic_tc_kappa*sqrt(block%wextra(ix^d,tcoff_)**5)
1445 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
1446 else
1447 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1448 sigma_t7=sigma_t5*te(ix^d)
1449 end if
1450 else
1451 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1452 sigma_t7=sigma_t5*te(ix^d)
1453 end if
1454 sigmat5_bgradt=sigma_t5*(&
1455 block%B0(ix^d,1,0)*((8.d0*(te(ix1+1,ix2)-te(ix1-1,ix2))-te(ix1+2,ix2)+te(ix1-2,ix2))/12.d0)/block%ds(ix^d,1)&
1456 +block%B0(ix^d,2,0)*((8.d0*(te(ix1,ix2+1)-te(ix1,ix2-1))-te(ix1,ix2+2)+te(ix1,ix2-2))/12.d0)/block%ds(ix^d,2))
1457 if(ffhd_hyperbolic_tc_sat) then
1458 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
1459 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*wct(ix^d,rho_)*(wctprim(ix^d,p_)/wct(ix^d,rho_))**1.5d0))
1460 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1461 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
1462 else
1463 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
1464 max(4.d0*dt, sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1465 end if
1466 end do
1467 end do
1468 }
1469 {^ifthreed
1470 do ix3=ixomin3,ixomax3
1471 do ix2=ixomin2,ixomax2
1472 do ix1=ixomin1,ixomax1
1473 if(ffhd_trac) then
1474 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
1475 sigma_t5=hyperbolic_tc_kappa*sqrt(block%wextra(ix^d,tcoff_)**5)
1476 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
1477 else
1478 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1479 sigma_t7=sigma_t5*te(ix^d)
1480 end if
1481 else
1482 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1483 sigma_t7=sigma_t5*te(ix^d)
1484 end if
1485 sigmat5_bgradt=sigma_t5*(&
1486 block%B0(ix^d,1,0)*((8.d0*(te(ix1+1,ix2,ix3)-te(ix1-1,ix2,ix3))-te(ix1+2,ix2,ix3)+te(ix1-2,ix2,ix3))/12.d0)/block%ds(ix^d,1)&
1487 +block%B0(ix^d,2,0)*((8.d0*(te(ix1,ix2+1,ix3)-te(ix1,ix2-1,ix3))-te(ix1,ix2+2,ix3)+te(ix1,ix2-2,ix3))/12.d0)/block%ds(ix^d,2)&
1488 +block%B0(ix^d,3,0)*((8.d0*(te(ix1,ix2,ix3+1)-te(ix1,ix2,ix3-1))-te(ix1,ix2,ix3+2)+te(ix1,ix2,ix3-2))/12.d0)/block%ds(ix^d,3))
1489 if(ffhd_hyperbolic_tc_sat) then
1490 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
1491 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*wct(ix^d,rho_)*(wctprim(ix^d,p_)/wct(ix^d,rho_))**1.5d0))
1492 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1493 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
1494 else
1495 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
1496 max(4.d0*dt, sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1497 end if
1498 end do
1499 end do
1500 end do
1501 }
1502 end subroutine add_hyperbolic_tc_source
1503
1504end module mod_ffhd_phys
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter bigdouble
A very large real number.
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition mod_convert.t:59
PI (partial-ionisation) ionisation-degree backend for the eos% family.
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
Frozen-field hydrodynamics module.
integer, public, protected te_
Indices of temperature and electron number density (LTE stored aux state)
integer, public, protected ffhd_trac_type
Which TRAC method is used.
integer, public, protected e_
Index of the energy density (-1 if not present)
subroutine, public ffhd_to_primitive_origin(ixil, ixol, w, x)
double precision, public hyperbolic_tc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
procedure(sub_get_pthermal), pointer, public ffhd_get_rfactor
double precision, public ffhd_adiab
The adiabatic index (now owned by eos%; use eosgamma)
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.
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
procedure(sub_get_pthermal), pointer, public ffhd_get_pthermal
subroutine, public ffhd_get_rho(w, x, ixil, ixol, rho)
integer, public, protected ne_
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)
logical, public, protected ffhd_hyperbolic_tc_use_perp
Whether the perpendicular hyperbolic-TC channel is enabled.
double precision, public, protected h_ion_fr
Helium abundance over Hydrogen (now owned by eos%; use eosHe_abundance) Ionization fraction of H H_io...
procedure(fun_kin_en), pointer, public ffhd_kin_en
subroutine, public ffhd_phys_init()
procedure(sub_get_v), pointer, public ffhd_get_v
subroutine, public ffhd_get_csound2(w, x, ixil, ixol, csound2)
logical, public, protected ffhd_energy
Whether an energy equation is used.
double precision, public, protected rr
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
logical, public, protected ffhd_hyperbolic_tc
Whether hyperbolic type thermal conduction is used.
logical, public, protected ffhd_radiative_cooling
Whether radiative cooling is added.
subroutine, public ffhd_get_v_idim(w, x, ixil, ixol, idim, v)
subroutine, public ffhd_get_pthermal_origin(w, x, ixil, ixol, pth)
integer, public, protected q_
procedure(sub_convert), pointer, public ffhd_to_primitive
logical, public, protected ffhd_hyperbolic_tc_sat
Whether saturation is considered for hyperbolic TC.
subroutine, public ffhd_get_temperature_from_te(w, x, ixil, ixol, res)
integer, public, protected tweight_
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
logical, public, protected ffhd_trac
Whether TRAC method is used.
subroutine, public ffhd_to_conserved_origin(ixil, ixol, w, x)
logical, public, protected ffhd_thermal_conduction
Whether thermal conduction is used.
subroutine, public ffhd_ei_to_e(ixil, ixol, w, x)
logical, public, protected ffhd_gravity
Whether gravity is added.
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_.
double precision, public, protected ffhd_trac_mask
Height of the mask used in the TRAC method.
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
subroutine, public ffhd_get_temperature_from_eint(w, x, ixil, ixol, res)
integer, public, protected ffhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
procedure(sub_small_values), pointer, public ffhd_handle_small_values
subroutine, public ffhd_e_to_ei(ixil, ixol, w, x)
Module for flux conservation near refinement boundaries.
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
integer coordinate
Definition mod_geometry.t:7
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
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.
double precision unit_time
Physical scaling factor for time.
double precision unit_density
Physical scaling factor for density.
integer, parameter unitpar
file handle for IO
double precision unit_mass
Physical scaling factor for mass.
integer, dimension(3, 3) kr
Kronecker delta tensor.
double precision unit_numberdensity
Physical scaling factor for number density.
character(len=std_len) convert_type
Which format to use when converting.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision dt
global time step
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision courantpar
The Courant (CFL) number used for the simulation.
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
integer nwauxio
Number of auxiliary variables that are only included in output.
double precision unit_velocity
Physical scaling factor for velocity.
logical b0field
split magnetic field as background B0 field
double precision unit_temperature
Physical scaling factor for temperature.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
logical phys_trac
Use TRAC for MHD or 1D HD.
logical need_global_cmax
need global maximal wave speed
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
integer, parameter unitconvert
integer number_equi_vars
number of equilibrium set variables, besides the mag field
Module for including gravity in (magneto)hydrodynamics simulations.
Definition mod_gravity.t:2
subroutine gravity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Definition mod_gravity.t:81
subroutine gravity_init()
Initialize the module.
Definition mod_gravity.t:26
subroutine gravity_add_source(qdt, ixil, ixol, wct, wctprim, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
Definition mod_gravity.t:43
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
Module for handling problematic values in simulations, such as negative pressures.
subroutine, public small_values_average(ixil, ixol, w, x, w_flag, windex)
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
subroutine, public small_values_error(wprim, x, ixil, ixol, w_flag, subname)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method which can be used for multiple source terms in the governing equatio...
subroutine, public add_sts_method(sts_getdt, sts_set_sources, startvar, nflux, startwbc, nwbc, evolve_b)
subroutine which added programatically a term to be calculated using STS Params: sts_getdt function c...
subroutine, public set_conversion_methods_to_head(sts_before_first_cycle, sts_after_last_cycle)
Set the hooks called before the first cycle and after the last cycle in the STS update This method sh...
subroutine, public set_error_handling_to_head(sts_error_handling)
Set the hook of error handling in the STS update. This method is called before updating the BC....
subroutine, public sts_init()
Initialize sts module.
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
subroutine, public tc_get_hd_params(fl, read_hd_params)
Init TC coefficients: HD case.
double precision function, public get_tc_dt_mhd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor
procedure(set_equi_vars), pointer usr_set_equi_vars