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 nwgc=nwflux+nwaux
289
290 ! set the index of the last flux variable for species 1
291 stop_indices(1)=nwflux
292
293 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
294 tweight_ = -1
295 if(ffhd_trac) then
296 tcoff_ = var_set_wextra()
297 iw_tcoff=tcoff_
298 if(ffhd_trac_type .ge. 3) then
299 tweight_ = var_set_wextra()
300 iw_tweight=tweight_
301 end if
302 else
303 tcoff_ = -1
304 end if
305
306 nvector = 0 ! No. vector vars
307
308 ! Check whether custom flux types have been defined
309 if(.not. allocated(flux_type)) then
310 allocate(flux_type(ndir, nwflux))
311 flux_type = flux_default
312 else if(any(shape(flux_type) /= [ndir, nwflux])) then
313 call mpistop("phys_check error: flux_type has wrong shape")
314 end if
315
316 phys_get_dt => ffhd_get_dt
317 phys_get_cmax => ffhd_get_cmax_origin
318 phys_get_tcutoff => ffhd_get_tcutoff
319 phys_get_cbounds => ffhd_get_cbounds
320 phys_to_primitive => ffhd_to_primitive_origin
322 phys_to_conserved => ffhd_to_conserved_origin
324 phys_get_flux => ffhd_get_flux
325 phys_get_v => ffhd_get_v_origin
326 ffhd_get_v => ffhd_get_v_origin
327 phys_get_rho => ffhd_get_rho
328 ffhd_kin_en => ffhd_kin_en_origin
329 phys_add_source_geom => ffhd_add_source_geom
330 phys_add_source => ffhd_add_source
331 phys_check_params => ffhd_check_params
332 phys_write_info => ffhd_write_info
333 phys_handle_small_values => ffhd_handle_small_values_origin
334 ffhd_handle_small_values => ffhd_handle_small_values_origin
335 phys_check_w => ffhd_check_w_origin
336
337 if(.not.ffhd_energy) then
338 phys_get_pthermal => ffhd_get_pthermal_iso
339 ffhd_get_pthermal => ffhd_get_pthermal_iso
340 else
341 phys_get_pthermal => ffhd_get_pthermal_origin
343 end if
344
345 ! Rfactor / temperature getter dispatch now lives in ffhd_link_eos (per eos_type)
346
347 ! derive units from basic units
348 call ffhd_physical_units()
349
350 if(ffhd_hyperbolic_tc) then
351 if(si_unit)then
352 ! parallel conduction Spitzer
354 else
355 ! in cgs
357 endif
358 end if
359 if(.not. ffhd_energy .and. ffhd_thermal_conduction) then
360 call mpistop("thermal conduction needs ffhd_energy=T")
361 end if
362 if(.not. ffhd_energy .and. ffhd_hyperbolic_tc) then
363 call mpistop("hyperbolic thermal conduction needs ffhd_energy=T")
364 end if
365 if(.not. ffhd_energy .and. ffhd_radiative_cooling) then
366 call mpistop("radiative cooling needs ffhd_energy=T")
367 end if
368
369 ! initialize thermal conduction module
371 call sts_init()
372 call tc_init_params(eos%gamma)
373
374 allocate(tc_fl)
375 call tc_get_hd_params(tc_fl,tc_params_read_ffhd)
376 call add_sts_method(ffhd_get_tc_dt_ffhd,ffhd_sts_set_source_tc_ffhd,e_,1,e_,1,.false.)
378 call set_error_handling_to_head(ffhd_tc_handle_small_e)
379 tc_fl%e_ = e_
380 tc_fl%Tcoff_ = tcoff_
381 ! get_temperature_*/get_rho/get_ne_nH/get_var_Rfactor/scalars wired in ffhd_bind_eos_to_source
382 end if
383
384 ! Initialize radiative cooling module
386 call radiative_cooling_init_params(eos%gamma,eos%He_abundance)
387 allocate(rc_fl)
388 call radiative_cooling_init(rc_fl,rc_params_read)
389 rc_fl%e_ = e_
390 rc_fl%Tcoff_ = tcoff_
391 rc_fl%subtract_equi = .false.
392 ! get_rho/get_pthermal/get_var_Rfactor/get_Te/get_ne_nH + EoS scalars/kernels
393 ! wired in ffhd_bind_eos_to_source
394 end if
395
396{^ifthreed
397 allocate(te_fl_ffhd)
398 phys_te_images => ffhd_te_images
399 ! te_fl_ffhd%get_rho/get_pthermal/get_var_Rfactor/get_ne_nH wired in ffhd_bind_eos_to_source
400}
401
402 ! Initialize gravity module
403 if(ffhd_gravity) then
404 call gravity_init()
405 end if
406
407 ! The PI ionisation backend (both ionE modes) is initialised centrally in
408 ! eos_finalise_PI (mod_eos_PI) -- mirrors hd/mhd, which no longer call
409 ! ionization_degree_init from the phys module (one source of truth; calling
410 ! it here too triggers "ionization_degree_init called more than once").
411 end subroutine ffhd_phys_init
412
413{^ifthreed
414 subroutine ffhd_te_images
417
418 select case(convert_type)
419 case('EIvtiCCmpi','EIvtuCCmpi')
421 case('ESvtiCCmpi','ESvtuCCmpi')
423 case('SIvtiCCmpi','SIvtuCCmpi')
425 case('WIvtiCCmpi','WIvtuCCmpi')
427 case default
428 call mpistop("Error in synthesize emission: Unknown convert_type")
429 end select
430 end subroutine ffhd_te_images
431}
432
433 subroutine ffhd_sts_set_source_tc_ffhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
437 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
438 double precision, intent(in) :: x(ixi^s,1:ndim)
439 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
440 double precision, intent(in) :: my_dt
441 logical, intent(in) :: fix_conserve_at_step
442 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
443 end subroutine ffhd_sts_set_source_tc_ffhd
444
445 function ffhd_get_tc_dt_ffhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
446 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
447 !where tc_k_para_i=tc_k_para*B_i**2/B**2
448 !and T=p/rho
451
452 integer, intent(in) :: ixi^l, ixo^l
453 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
454 double precision, intent(in) :: w(ixi^s,1:nw)
455 double precision :: dtnew
456
457 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
458 end function ffhd_get_tc_dt_ffhd
459
460 subroutine ffhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
462
463 integer, intent(in) :: ixi^l,ixo^l
464 double precision, intent(inout) :: w(ixi^s,1:nw)
465 double precision, intent(in) :: x(ixi^s,1:ndim)
466 integer, intent(in) :: step
467 character(len=140) :: error_msg
468
469 write(error_msg,"(a,i3)") "Thermal conduction step ", step
470 call ffhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
471 end subroutine ffhd_tc_handle_small_e
472
473 subroutine tc_params_read_ffhd(fl)
475 type(tc_fluid), intent(inout) :: fl
476 integer :: n
477 ! list parameters
478 logical :: tc_saturate=.false.
479 double precision :: tc_k_para=0d0
480 character(len=std_len) :: tc_slope_limiter="MC"
481
482 namelist /tc_list/ tc_saturate, tc_slope_limiter, tc_k_para
483
484 do n = 1, size(par_files)
485 open(unitpar, file=trim(par_files(n)), status="old")
486 read(unitpar, tc_list, end=111)
487111 close(unitpar)
488 end do
489
490 fl%tc_saturate = tc_saturate
491 fl%tc_k_para = tc_k_para
492 select case(tc_slope_limiter)
493 case ('no','none')
494 fl%tc_slope_limiter = 0
495 case ('MC')
496 ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
497 fl%tc_slope_limiter = 1
498 case('minmod')
499 ! minmod limiter
500 fl%tc_slope_limiter = 2
501 case ('superbee')
502 ! Roes superbee limiter (eq.3.51i)
503 fl%tc_slope_limiter = 3
504 case ('koren')
505 ! Barry Koren Right variant
506 fl%tc_slope_limiter = 4
507 case default
508 call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
509 end select
510 end subroutine tc_params_read_ffhd
511
512 subroutine rc_params_read(fl)
514 use mod_constants, only: bigdouble
515 type(rc_fluid), intent(inout) :: fl
516 integer :: n
517 integer :: ncool = 4000
518
519 !> Name of cooling curve
520 character(len=std_len) :: coolcurve='JCcorona'
521
522 !> Fixed temperature not lower than tlow
523 logical :: tfix=.false.
524
525 !> Lower limit of temperature
526 double precision :: tlow=bigdouble
527
528 !> Add cooling source in a split way (.true.) or un-split way (.false.)
529 logical :: rc_split=.false.
530 logical :: rad_damp=.false.
531 double precision :: rad_damp_height=0.5d0
532 double precision :: rad_damp_scale=0.15d0
533
534 namelist /rc_list/ coolcurve, ncool, tlow, tfix, rc_split, rad_damp, rad_damp_height, rad_damp_scale
535
536 do n = 1, size(par_files)
537 open(unitpar, file=trim(par_files(n)), status="old")
538 read(unitpar, rc_list, end=111)
539111 close(unitpar)
540 end do
541
542 fl%ncool=ncool
543 fl%coolcurve=coolcurve
544 fl%tlow=tlow
545 fl%Tfix=tfix
546 fl%rc_split=rc_split
547 fl%rad_damp=rad_damp
548 fl%rad_damp_height=rad_damp_height
549 fl%rad_damp_scale=rad_damp_scale
550 end subroutine rc_params_read
551
552 subroutine ffhd_check_params
556 use mod_geometry, only: coordinate
557
558
559 if (.not. ffhd_energy) then
560 if (eos%gamma <= 0.0d0) call mpistop ("Error: eos%gamma <= 0")
561 if (ffhd_adiab < 0.0d0) call mpistop ("Error: ffhd_adiab < 0")
563 else
564 if (eos%gamma <= 0.0d0 .or. eos%gamma == 1.0d0) &
565 call mpistop ("Error: eos%gamma <= 0 or eos%gamma == 1")
566 small_e = small_pressure * eos%inv_gamma_minus_1
567 end if
568
569 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
570 call mpistop("usr_set_equi_vars has to be implemented in the user file")
571 end if
572
573
574 if(mype==0)then
575 write(*,*)'====FFHD run with settings===================='
576 write(*,*)'Using mod_ffhd_phys with settings:'
577 write(*,*)'SI_unit=',si_unit
578 write(*,*)'Dimensionality :',ndim
579 write(*,*)'vector components:',ndir
580 write(*,*)'coordinate set to type,slab:',coordinate,slab
581 write(*,*)'number of variables nw=',nw
582 write(*,*)' start index iwstart=',iwstart
583 write(*,*)'number of vector variables=',nvector
584 write(*,*)'number of stagger variables nws=',nws
585 write(*,*)'number of variables with BCs=',nwgc
586 write(*,*)'number of vars with fluxes=',nwflux
587 write(*,*)'number of vars with flux + BC=',nwfluxbc
588 write(*,*)'number of auxiliary variables=',nwaux
589 write(*,*)'number of extra vars without flux=',nwextra
590 write(*,*)'number of extra vars for wextra=',nw_extra
591 write(*,*)'number of auxiliary I/O variables=',nwauxio
592 write(*,*)' ffhd_energy=',ffhd_energy
593 write(*,*)' ffhd_gravity=',ffhd_gravity
594 write(*,*)' ffhd_radiative_cooling=',ffhd_radiative_cooling
595 write(*,*)' ffhd_hyperbolic_tc=',ffhd_hyperbolic_tc
596 write(*,*)' ffhd_trac=',ffhd_trac
597 write(*,*)'number of ghostcells=',nghostcells
598 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
599 write(*,*)'==========================================='
600 endif
601 end subroutine ffhd_check_params
602
603 subroutine ffhd_physical_units()
605 double precision :: mp,kb
606 double precision :: a,b
607
608 if(si_unit) then
609 mp=mp_si
610 kb=kb_si
611 else
612 mp=mp_cgs
613 kb=kb_cgs
614 end if
615
616 ! Normalisation dispatch keyed solely on eos%eos_type (FI is the default, so
617 ! legacy parfiles that set neither eos_type nor any flag land in the FI/PI
618 ! absorbed-(a,b), RR=1 branch -- the historical eq_state_units=.true. result).
619 if (eos%eos_type == 'LTE') then
620 !> Remove the assumed FI normalisation from the units; handle in EoS.
621 a=1d0
622 b=1d0
623 eos%nH2rhoFactor = 1d0+4d0*eos%He_abundance
624 rr=(2d0+3d0*eos%He_abundance)/(1d0+4d0*eos%He_abundance)
625 else
626 !> FI / PI: absorbed-(a,b), RR=1. The (1+4He) factor is absorbed into
627 !> unit_density, so nH2rhoFactor stays at the eos_init default of 1 (else
628 !> get_ne_nH would double-divide rho and under-cool by (1+4He)^2).
629 a=1d0+4d0*eos%He_abundance
630 if(eos%eos_type=='PI') then
631 b=1d0+h_ion_fr+eos%He_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0)
632 else
633 b=2d0+3d0*eos%He_abundance
634 end if
635 rr=1d0
636 end if
637 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
638 if(unit_density/=1.d0) then
640 else if(unit_numberdensity/=1.d0) then
642 end if
643 if(unit_temperature/=1.d0) then
646 if(unit_length/=1.d0) then
648 else if(unit_time/=1.d0) then
650 end if
651 else if(unit_pressure/=1.d0) then
654 if(unit_length/=1.d0) then
656 else if(unit_time/=1.d0) then
658 end if
659 else if(unit_velocity/=1.d0) then
662 if(unit_length/=1.d0) then
664 else if(unit_time/=1.d0) then
666 end if
667 else if(unit_time/=1.d0) then
671 end if
672 else if(unit_temperature/=1.d0) then
673 ! units of temperature and velocity are dependent
674 if(unit_pressure/=1.d0) then
678 if(unit_length/=1.d0) then
680 else if(unit_time/=1.d0) then
682 end if
683 end if
684 else if(unit_pressure/=1.d0) then
685 if(unit_velocity/=1.d0) then
689 if(unit_length/=1.d0) then
691 else if(unit_time/=1.d0) then
693 end if
694 else if(unit_time/=0.d0) then
699 end if
700 end if
702 end subroutine ffhd_physical_units
703
704 subroutine ffhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
706 logical, intent(in) :: primitive
707 integer, intent(in) :: ixi^l, ixo^l
708 double precision, intent(in) :: w(ixi^s,nw)
709 double precision :: tmp(ixi^s)
710 logical, intent(inout) :: flag(ixi^s,1:nw)
711
712 flag=.false.
713 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
714
715 if(ffhd_energy) then
716 if(primitive) then
717 where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
718 else
719 tmp(ixo^s)=w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l)
720 where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
721 end if
722 end if
723 end subroutine ffhd_check_w_origin
724
725 subroutine ffhd_to_conserved_origin(ixI^L,ixO^L,w,x)
727 integer, intent(in) :: ixi^l, ixo^l
728 double precision, intent(inout) :: w(ixi^s, nw)
729 double precision, intent(in) :: x(ixi^s, 1:ndim)
730
731 if(ffhd_energy) then
732 w(ixo^s,e_)=w(ixo^s,p_)*eos%inv_gamma_minus_1+half*w(ixo^s,mom(1))**2*w(ixo^s,rho_)
733 end if
734 w(ixo^s,mom(1))=w(ixo^s,rho_)*w(ixo^s,mom(1))
735 end subroutine ffhd_to_conserved_origin
736
737 subroutine ffhd_to_primitive_origin(ixI^L,ixO^L,w,x)
739 integer, intent(in) :: ixi^l, ixo^l
740 double precision, intent(inout) :: w(ixi^s, nw)
741 double precision, intent(in) :: x(ixi^s, 1:ndim)
742
743 if(fix_small_values) then
744 call ffhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'ffhd_to_primitive_origin')
745 end if
746
747 w(ixo^s,mom(1)) = w(ixo^s,mom(1))/w(ixo^s,rho_)
748 if(ffhd_energy) then
749 w(ixo^s,p_)=eos%gamma_minus_1*(w(ixo^s,e_)-half*w(ixo^s,rho_)*w(ixo^s,mom(1))**2)
750 end if
751 end subroutine ffhd_to_primitive_origin
752
753 subroutine ffhd_ei_to_e(ixI^L,ixO^L,w,x)
755 integer, intent(in) :: ixi^l, ixo^l
756 double precision, intent(inout) :: w(ixi^s, nw)
757 double precision, intent(in) :: x(ixi^s, 1:ndim)
758
759 w(ixo^s,e_)=w(ixo^s,e_)+ffhd_kin_en(w,ixi^l,ixo^l)
760 end subroutine ffhd_ei_to_e
761
762 subroutine ffhd_e_to_ei(ixI^L,ixO^L,w,x)
764 integer, intent(in) :: ixi^l, ixo^l
765 double precision, intent(inout) :: w(ixi^s, nw)
766 double precision, intent(in) :: x(ixi^s, 1:ndim)
767
768 ! Restrict to ixO^L (mirrors hd/mhd): update_eos_LTE calls phys_e_to_ei
769 ! over the mesh interior while ixI^S still spans unfilled corner ghosts
770 ! (rho=0 -> SIGFPE in ffhd_kin_en). FI is unaffected (update_eos_FI no-op;
771 ! the TC STS heads pass the range they need).
772 w(ixo^s,e_)=w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l)
773 if(fix_small_values) then
774 call ffhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'ffhd_e_to_ei')
775 end if
776 end subroutine ffhd_e_to_ei
777
778 !> Internal energy eint = E_total - E_kinetic (single field-aligned momentum).
779 !> Wired to phys_get_ei; the LTE+ionE radiative cooling uses it to recover the
780 !> gas internal energy from the conserved state.
781 function ffhd_get_ei(w, ixI^L, ixO^L) result(ei)
783 integer, intent(in) :: ixi^l, ixo^l
784 double precision, intent(in) :: w(ixi^s, nw)
785 double precision :: ei(ixo^s)
786
787 ei(ixo^s) = w(ixo^s,e_) - ffhd_kin_en(w,ixi^l,ixo^l)
788 end function ffhd_get_ei
789
790 subroutine ffhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
793 logical, intent(in) :: primitive
794 integer, intent(in) :: ixi^l,ixo^l
795 double precision, intent(inout) :: w(ixi^s,1:nw)
796 double precision, intent(in) :: x(ixi^s,1:ndim)
797 character(len=*), intent(in) :: subname
798
799 logical :: flag(ixi^s,1:nw)
800 double precision :: tmp2(ixi^s)
801
802 call phys_check_w(primitive, ixi^l, ixi^l, w, flag)
803
804 if(any(flag)) then
805 select case (small_values_method)
806 case ("replace")
807 where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
808 if(small_values_fix_iw(mom(1))) then
809 where(flag(ixo^s,rho_)) w(ixo^s, mom(1)) = 0.0d0
810 end if
811 if(ffhd_energy) then
812 if(primitive) then
813 where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
814 else
815 where(flag(ixo^s,e_))
816 w(ixo^s,e_) = small_e+ffhd_kin_en(w,ixi^l,ixo^l)
817 end where
818 end if
819 end if
820 case ("average")
821 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
822 if(ffhd_energy) then
823 if(primitive) then
824 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
825 else
826 w(ixi^s,e_)=w(ixi^s,e_)-ffhd_kin_en(w,ixi^l,ixi^l)
827 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
828 w(ixi^s,e_)=w(ixi^s,e_)+ffhd_kin_en(w,ixi^l,ixi^l)
829 end if
830 end if
831 case default
832 if(.not.primitive) then
833 if(ffhd_energy) then
834 w(ixo^s,p_)=eos%gamma_minus_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
835 end if
836 w(ixo^s,mom(1))=w(ixo^s,mom(1))/w(ixo^s,rho_)
837 end if
838 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
839 end select
840 end if
841 end subroutine ffhd_handle_small_values_origin
842
843 subroutine ffhd_get_v_origin(w,x,ixI^L,ixO^L,v)
845 integer, intent(in) :: ixi^l, ixo^l
846 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
847 double precision, intent(out) :: v(ixi^s,ndir)
848 double precision :: rho(ixi^s)
849 integer :: idir
850
851 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
852 rho(ixo^s)=1.d0/rho(ixo^s)
853 do idir=1,ndir
854 v(ixo^s,ndir) = w(ixo^s,mom(1))*block%B0(ixo^s,idir,0)*rho(ixo^s)
855 end do
856 end subroutine ffhd_get_v_origin
857
858 subroutine ffhd_get_v_idim(w,x,ixI^L,ixO^L,idim,v)
860 integer, intent(in) :: ixi^l, ixo^l, idim
861 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
862 double precision, intent(out) :: v(ixi^s)
863 double precision :: rho(ixi^s)
864
865 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
866 v(ixo^s) = (w(ixo^s, mom(1))*block%B0(ixo^s,idim,0)) / rho(ixo^s)
867 end subroutine ffhd_get_v_idim
868
869 subroutine ffhd_get_cmax_origin(wprim,x,ixI^L,ixO^L,idim,cmax)
871 integer, intent(in) :: ixi^l, ixo^l, idim
872 ! w in primitive form
873 double precision, intent(in) :: wprim(ixi^s, nw), x(ixi^s,1:ndim)
874 double precision, intent(inout) :: cmax(ixi^s)
875
876 if(ffhd_energy) then
877 if (eos%ionE) then
878 ! LTE/PI energy: Gamma_1(p,rho)*p/rho from the EoS (wprim is primitive)
879 call eos%get_csound2(wprim,x,ixi^l,ixo^l,cmax)
880 cmax(ixo^s)=dsqrt(cmax(ixo^s))
881 else
882 cmax(ixo^s)=dsqrt(eos%gamma*wprim(ixo^s,p_)/wprim(ixo^s,rho_))
883 end if
884 else
885 cmax(ixo^s)=dsqrt(eos%gamma*ffhd_adiab*wprim(ixo^s,rho_)**eos%gamma_minus_1)
886 end if
887 cmax(ixo^s)=dabs(wprim(ixo^s,mom(1))*block%B0(ixo^s,idim,0))+cmax(ixo^s)
888
889 end subroutine ffhd_get_cmax_origin
890
891 subroutine ffhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
893 use mod_geometry
894 integer, intent(in) :: ixi^l,ixo^l
895 double precision, intent(in) :: x(ixi^s,1:ndim)
896 double precision, intent(inout) :: w(ixi^s,1:nw)
897 double precision, intent(out) :: tco_local,tmax_local
898 double precision, parameter :: trac_delta=0.25d0
899 double precision :: te(ixi^s),lts(ixi^s)
900 double precision, dimension(ixI^S,1:ndim) :: gradt
901 double precision :: bdir(ndim)
902 double precision :: ltrc,ltrp,altr
903 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
904 integer :: jxp^l,hxp^l,ixp^l,ixq^l
905 logical :: lrlt(ixi^s)
906
907 call ffhd_get_temperature(w,x,ixi^l,ixi^l,te)
908 tco_local=zero
909 tmax_local=maxval(te(ixo^s))
910
911 {^ifoned
912 select case(ffhd_trac_type)
913 case(0)
914 !> test case, fixed cutoff temperature
915 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
916 case(1)
917 hxo^l=ixo^l-1;
918 jxo^l=ixo^l+1;
919 lts(ixo^s)=0.5d0*dabs(te(jxo^s)-te(hxo^s))/te(ixo^s)
920 lrlt=.false.
921 where(lts(ixo^s) > trac_delta)
922 lrlt(ixo^s)=.true.
923 end where
924 if(any(lrlt(ixo^s))) then
925 tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
926 end if
927 case(2)
928 !> iijima et al. 2021, LTRAC method
929 ltrc=1.5d0
930 ltrp=4.d0
931 ixp^l=ixo^l^ladd1;
932 hxo^l=ixo^l-1;
933 jxo^l=ixo^l+1;
934 hxp^l=ixp^l-1;
935 jxp^l=ixp^l+1;
936 lts(ixp^s)=0.5d0*dabs(te(jxp^s)-te(hxp^s))/te(ixp^s)
937 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
938 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
939 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
940 case default
941 call mpistop("ffhd_trac_type not allowed for 1D simulation")
942 end select
943 }
944 {^nooned
945 select case(ffhd_trac_type)
946 case(0)
947 !> test case, fixed cutoff temperature
948 if(slab_uniform) then
949 !> assume cgs units
950 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)
951 else
952 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
953 end if
954 case(1,4,6)
955 do idims=1,ndim
956 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
957 end do
958 if(ffhd_trac_type .gt. 1) then
959 ! B direction at cell center
960 bdir=zero
961 {do ixa^d=0,1\}
962 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
963 bdir(1:ndim)=bdir(1:ndim)+block%B0(ixb^d,1:ndim,0)
964 {end do\}
965 if(sum(bdir(:)**2) .gt. zero) then
966 bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
967 end if
968 block%special_values(3:ndim+2)=bdir(1:ndim)
969 end if
970 {do ix^db=ixomin^db,ixomax^db\}
971 {^iftwod
972 ! temperature length scale inversed
973 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
974 abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
975 }
976 {^ifthreed
977 ! temperature length scale inversed
978 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
979 abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
980 }
981 if(lts(ix^d)>trac_delta) then
982 block%special_values(1)=max(block%special_values(1),te(ix^d))
983 end if
984 {end do\}
985 block%special_values(2)=tmax_local
986 case(2)
987 !> iijima et al. 2021, LTRAC method
988 ltrc=1.5d0
989 ltrp=4.d0
990 ixp^l=ixo^l^ladd2;
991 do idims=1,ndim
992 ixq^l=ixp^l;
993 hxp^l=ixp^l;
994 jxp^l=ixp^l;
995 select case(idims)
996 {case(^d)
997 ixqmin^d=ixqmin^d+1
998 ixqmax^d=ixqmax^d-1
999 hxpmax^d=ixpmin^d
1000 jxpmin^d=ixpmax^d
1001 \}
1002 end select
1003 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
1004 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
1005 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
1006 end do
1007 {do ix^db=ixpmin^db,ixpmax^db\}
1008 ! temperature length scale inversed
1009 lts(ix^d)=abs(^d&gradt({ix^d},^d)*block%B0({ix^d},^d,0)+)/te(ix^d)
1010 ! fraction of cells size to temperature length scale
1011 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
1012 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
1013 {end do\}
1014
1015 ! need one ghost layer for thermal conductivity
1016 ixp^l=ixo^l^ladd1;
1017 {do ix^db=ixpmin^db,ixpmax^db\}
1018 {^iftwod
1019 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*block%B0(ix^d,1,0)**2+&
1020 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*block%B0(ix^d,2,0)**2)
1021 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
1022 }
1023 {^ifthreed
1024 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*block%B0(ix^d,1,0)**2+&
1025 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*block%B0(ix^d,2,0)**2+&
1026 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*block%B0(ix^d,3,0)**2)
1027 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
1028 }
1029 {end do\}
1030 case(3,5)
1031 !> do nothing here
1032 case default
1033 call mpistop("unknown ffhd_trac_type")
1034 end select
1035 }
1036 end subroutine ffhd_get_tcutoff
1037
1038 subroutine ffhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
1040 integer, intent(in) :: ixi^l, ixo^l, idim
1041 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
1042 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1043 double precision, intent(in) :: x(ixi^s,1:ndim)
1044 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
1045 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
1046 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
1047 double precision :: wmean(ixi^s,nw), wmeanp(ixi^s,nw)
1048 double precision, dimension(ixI^S) :: umean, dmean, csoundl, csoundr, tmp1,tmp2,tmp3
1049
1050 select case (boundspeed)
1051 case (1)
1052 ! This implements formula (10.52) from "Riemann Solvers and Numerical
1053 ! Methods for Fluid Dynamics" by Toro.
1054 tmp1(ixo^s)=dsqrt(wlp(ixo^s,rho_))
1055 tmp2(ixo^s)=dsqrt(wrp(ixo^s,rho_))
1056 tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
1057 umean(ixo^s)=(wlp(ixo^s,mom(1))*tmp1(ixo^s)&
1058 +wrp(ixo^s,mom(1))*tmp2(ixo^s))*tmp3(ixo^s)
1059 umean(ixo^s)=umean(ixo^s)*block%B0(ixo^s,idim,idim)
1060 call ffhd_csound2_cbounds(wlc,wlp,x,ixi^l,ixo^l,csoundl)
1061 call ffhd_csound2_cbounds(wrc,wrp,x,ixi^l,ixo^l,csoundr)
1062 dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)+tmp2(ixo^s)*csoundr(ixo^s)) * &
1063 tmp3(ixo^s) + 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2 * &
1064 ((wrp(ixo^s,mom(1))-wlp(ixo^s,mom(1)))*block%B0(ixo^s,idim,idim))**2
1065 dmean(ixo^s)=dsqrt(dmean(ixo^s))
1066 if(present(cmin)) then
1067 cmin(ixo^s,1)=umean(ixo^s)-dmean(ixo^s)
1068 cmax(ixo^s,1)=umean(ixo^s)+dmean(ixo^s)
1069 else
1070 cmax(ixo^s,1)=dabs(umean(ixo^s))+dmean(ixo^s)
1071 end if
1072 case (2)
1073 wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
1074 tmp1(ixo^s)=wmean(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)/wmean(ixo^s,rho_)
1075 if (eos%ionE) then
1076 wmeanp(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
1077 call eos%get_csound2(wmeanp,x,ixi^l,ixo^l,csoundr)
1078 else
1079 call ffhd_get_csound2(wmean,x,ixi^l,ixo^l,csoundr)
1080 end if
1081 csoundr(ixo^s) = dsqrt(csoundr(ixo^s))
1082 if(present(cmin)) then
1083 cmax(ixo^s,1)=max(tmp1(ixo^s)+csoundr(ixo^s),zero)
1084 cmin(ixo^s,1)=min(tmp1(ixo^s)-csoundr(ixo^s),zero)
1085 else
1086 cmax(ixo^s,1)=dabs(tmp1(ixo^s))+csoundr(ixo^s)
1087 end if
1088 case (3)
1089 ! Miyoshi 2005 JCP 208, 315 equation (67)
1090 call ffhd_csound2_cbounds(wlc,wlp,x,ixi^l,ixo^l,csoundl)
1091 call ffhd_csound2_cbounds(wrc,wrp,x,ixi^l,ixo^l,csoundr)
1092 csoundl(ixo^s)=max(dsqrt(csoundl(ixo^s)),dsqrt(csoundr(ixo^s)))
1093 if(present(cmin)) then
1094 cmin(ixo^s,1)=min(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1095 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))-csoundl(ixo^s)
1096 cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1097 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1098 else
1099 cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1100 wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1101 end if
1102 end select
1103 end subroutine ffhd_get_cbounds
1104
1105 !> Sound speed^2 at a Riemann interface. FI uses the conserved-state pthermal
1106 !> path (bit-identical to the legacy ffhd_get_csound2(wC) call); LTE uses the
1107 !> primitive Gamma_1*p/rho via eos% because the stored Te_/Ne_ are NOT
1108 !> reconstructed onto interface states (they are advection-free extra vars).
1109 subroutine ffhd_csound2_cbounds(wC,wp,x,ixI^L,ixO^L,cs2)
1111 integer, intent(in) :: ixi^l, ixo^l
1112 double precision, intent(in) :: wc(ixi^s,nw), wp(ixi^s,nw), x(ixi^s,1:ndim)
1113 double precision, intent(out):: cs2(ixi^s)
1114
1115 if (eos%ionE) then
1116 call eos%get_csound2(wp,x,ixi^l,ixo^l,cs2)
1117 else
1118 call ffhd_get_csound2(wc,x,ixi^l,ixo^l,cs2)
1119 end if
1120 end subroutine ffhd_csound2_cbounds
1121
1122 subroutine ffhd_get_pthermal_iso(w,x,ixI^L,ixO^L,pth)
1124
1125 integer, intent(in) :: ixi^l, ixo^l
1126 double precision, intent(in) :: w(ixi^s,nw)
1127 double precision, intent(in) :: x(ixi^s,1:ndim)
1128 double precision, intent(out):: pth(ixi^s)
1129
1130 call ffhd_get_rho(w,x,ixi^l,ixo^l,pth)
1131 pth(ixo^s)=ffhd_adiab*pth(ixo^s)**eos%gamma
1132 end subroutine ffhd_get_pthermal_iso
1133
1134 subroutine ffhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
1137 integer, intent(in) :: ixi^l, ixo^l
1138 double precision, intent(in) :: w(ixi^s,nw)
1139 double precision, intent(in) :: x(ixi^s,1:ndim)
1140 double precision, intent(out):: pth(ixi^s)
1141 integer :: iw, ix^d
1142
1143 pth(ixo^s)=eos%gamma_minus_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
1144 if (fix_small_values) then
1145 {do ix^db= ixo^lim^db\}
1146 if(pth(ix^d)<small_pressure) then
1147 pth(ix^d)=small_pressure
1148 end if
1149 {end do^D&\}
1150 elseif(check_small_values) then
1151 {do ix^db= ixo^lim^db\}
1152 if(pth(ix^d)<small_pressure) then
1153 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1154 " encountered when call ffhd_get_pthermal"
1155 write(*,*) "Iteration: ", it, " Time: ", global_time
1156 write(*,*) "Location: ", x(ix^d,:)
1157 write(*,*) "Cell number: ", ix^d
1158 do iw=1,nw
1159 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1160 end do
1161 ! use erroneous arithmetic operation to crash the run
1162 if(trace_small_values) write(*,*) dsqrt(pth(ix^d)-bigdouble)
1163 write(*,*) "Saving status at the previous time step"
1164 crash=.true.
1165 end if
1166 {end do^D&\}
1167 end if
1168 end subroutine ffhd_get_pthermal_origin
1169
1170 subroutine ffhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
1172 integer, intent(in) :: ixi^l, ixo^l
1173 double precision, intent(in) :: w(ixi^s, 1:nw)
1174 double precision, intent(in) :: x(ixi^s, 1:ndim)
1175 double precision, intent(out):: res(ixi^s)
1176
1177 res(ixo^s) = w(ixo^s, te_)
1178 end subroutine ffhd_get_temperature_from_te
1179
1180 subroutine ffhd_get_temperature_from_eint(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 double precision :: r(ixi^s)
1187
1188 call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1189 res(ixo^s) = eos%gamma_minus_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
1190 end subroutine ffhd_get_temperature_from_eint
1191
1192 subroutine ffhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
1194 integer, intent(in) :: ixi^l, ixo^l
1195 double precision, intent(in) :: w(ixi^s, 1:nw)
1196 double precision, intent(in) :: x(ixi^s, 1:ndim)
1197 double precision, intent(out):: res(ixi^s)
1198
1199 double precision :: r(ixi^s)
1200
1201 call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1202 call ffhd_get_pthermal(w,x,ixi^l,ixo^l,res)
1203 res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
1204 end subroutine ffhd_get_temperature_from_etot
1205
1206 subroutine ffhd_get_csound2(w,x,ixI^L,ixO^L,csound2)
1208 integer, intent(in) :: ixi^l, ixo^l
1209 double precision, intent(in) :: w(ixi^s,nw)
1210 double precision, intent(in) :: x(ixi^s,1:ndim)
1211 double precision, intent(out) :: csound2(ixi^s)
1212 double precision :: rho(ixi^s)
1213
1214 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1215 if(ffhd_energy) then
1216 call ffhd_get_pthermal(w,x,ixi^l,ixo^l,csound2)
1217 csound2(ixo^s)=eos%gamma*csound2(ixo^s)/rho(ixo^s)
1218 else
1219 csound2(ixo^s)=eos%gamma*ffhd_adiab*rho(ixo^s)**eos%gamma_minus_1
1220 end if
1221 end subroutine ffhd_get_csound2
1222
1223 subroutine ffhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
1225 use mod_geometry
1226 integer, intent(in) :: ixi^l, ixo^l, idim
1227 ! conservative w
1228 double precision, intent(in) :: wc(ixi^s,nw)
1229 ! primitive w
1230 double precision, intent(in) :: w(ixi^s,nw)
1231 double precision, intent(in) :: x(ixi^s,1:ndim)
1232 double precision,intent(out) :: f(ixi^s,nwflux)
1233 double precision :: ptotal(ixo^s)
1234
1235 f(ixo^s,rho_)=w(ixo^s,mom(1))*w(ixo^s,rho_)*block%B0(ixo^s,idim,idim)
1236
1237 if(ffhd_energy) then
1238 ptotal(ixo^s)=w(ixo^s,p_)
1239 else
1240 ptotal(ixo^s)=ffhd_adiab*w(ixo^s,rho_)**eos%gamma
1241 end if
1242
1243 ! Get flux of momentum
1244 f(ixo^s,mom(1))=(wc(ixo^s,mom(1))*w(ixo^s,mom(1))+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1245
1246 ! Get flux of energy
1247 if(ffhd_energy) then
1248 f(ixo^s,e_)=w(ixo^s,mom(1))*(wc(ixo^s,e_)+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1249 if(ffhd_hyperbolic_tc) then
1250 f(ixo^s,e_)=f(ixo^s,e_)+w(ixo^s,q_)*block%B0(ixo^s,idim,idim)
1251 f(ixo^s,q_)=zero
1252 end if
1253 end if
1254 end subroutine ffhd_get_flux
1255
1256 subroutine ffhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
1260 integer, intent(in) :: ixi^l, ixo^l
1261 double precision, intent(in) :: qdt,dtfactor
1262 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
1263 double precision, intent(inout) :: w(ixi^s,1:nw)
1264 logical, intent(in) :: qsourcesplit
1265 logical, intent(inout) :: active
1266
1267 if (.not. qsourcesplit) then
1268 active = .true.
1269 call add_punitb(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1270 if(ffhd_hyperbolic_tc) then
1271 call add_hyperbolic_tc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1272 end if
1273 end if
1274
1275 if(ffhd_radiative_cooling) then
1276 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1277 w,x,qsourcesplit,active, rc_fl)
1278 end if
1279
1280 if(ffhd_gravity) then
1281 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1282 w,x,ffhd_energy,qsourcesplit,active)
1283 end if
1284
1285 ! update temperature from new pressure, density, and old ionization degree
1286 if(eos%eos_type == 'PI') then
1287 if(.not.qsourcesplit) then
1288 active = .true.
1289 call eos%update_eos(ixi^l,ixo^l,w,x)
1290 end if
1291 end if
1292 end subroutine ffhd_add_source
1293
1294 subroutine add_punitb(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1296 use mod_geometry
1297 integer, intent(in) :: ixi^l,ixo^l
1298 double precision, intent(in) :: qdt
1299 double precision, intent(in) :: wct(ixi^s,1:nw),x(ixi^s,1:ndim)
1300 double precision, intent(in) :: wctprim(ixi^s,1:nw)
1301 double precision, intent(inout) :: w(ixi^s,1:nw)
1302
1303 integer :: idims,hxo^l
1304 double precision :: divb(ixi^s)
1305 double precision :: rhovpar(ixi^s),gradrhov(ixi^s)
1306
1307 divb=zero
1308 if(slab_uniform) then
1309 do idims=1,ndim
1310 hxo^l=ixo^l-kr(idims,^d);
1311 divb(ixo^s)=divb(ixo^s)+(block%B0(ixo^s,idims,idims)-block%B0(hxo^s,idims,idims))/dxlevel(idims)
1312 end do
1313 else
1314 call divvector(block%B0(ixi^s,1:ndir,0),ixi^l,ixo^l,divb)
1315 end if
1316 w(ixo^s,mom(1))=w(ixo^s,mom(1))+qdt*wctprim(ixo^s,p_)*divb(ixo^s)
1317 end subroutine add_punitb
1318
1319 subroutine ffhd_get_rho(w,x,ixI^L,ixO^L,rho)
1321 integer, intent(in) :: ixi^l, ixo^l
1322 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
1323 double precision, intent(out) :: rho(ixi^s)
1324
1325 rho(ixo^s) = w(ixo^s,rho_)
1326 end subroutine ffhd_get_rho
1327
1328 subroutine ffhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
1331 integer, intent(in) :: ixi^l,ixo^l, ie
1332 double precision, intent(inout) :: w(ixi^s,1:nw)
1333 double precision, intent(in) :: x(ixi^s,1:ndim)
1334 character(len=*), intent(in) :: subname
1335 integer :: idir
1336 logical :: flag(ixi^s,1:nw)
1337 double precision :: rho(ixi^s)
1338
1339 flag=.false.
1340 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
1341 if(any(flag(ixo^s,ie))) then
1342 select case (small_values_method)
1343 case ("replace")
1344 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
1345 case ("average")
1346 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
1347 case default
1348 w(ixo^s,e_)=w(ixo^s,e_)*eos%gamma_minus_1
1349 call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1350 w(ixo^s,mom(1)) = w(ixo^s,mom(1))/rho(ixo^s)
1351 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
1352 end select
1353 end if
1354 end subroutine ffhd_handle_small_ei
1355
1356
1357 subroutine ffhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
1359 use mod_usr_methods
1360 use mod_gravity, only: gravity_get_dt
1361 integer, intent(in) :: ixi^l, ixo^l
1362 double precision, intent(inout) :: dtnew
1363 double precision, intent(in) :: dx^d
1364 double precision, intent(in) :: wprim(ixi^s,1:nw)
1365 double precision, intent(in) :: x(ixi^s,1:ndim)
1366
1367 dtnew = bigdouble
1368
1369 if(ffhd_gravity) then
1370 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
1371 end if
1372 end subroutine ffhd_get_dt
1373
1374 subroutine ffhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
1376 integer, intent(in) :: ixi^l, ixo^l
1377 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
1378 double precision, intent(inout) :: wct(ixi^s,1:nw), wprim(ixi^s,1:nw),w(ixi^s,1:nw)
1379
1380 ! no geometric source terms needed for ffhd, no divergences of tensors
1381 end subroutine ffhd_add_source_geom
1382
1383 function ffhd_kin_en_origin(w, ixI^L, ixO^L, inv_rho) result(ke)
1384 use mod_global_parameters, only: nw, ndim,block
1385 integer, intent(in) :: ixi^l, ixo^l
1386 double precision, intent(in) :: w(ixi^s, nw)
1387 double precision :: ke(ixo^s)
1388 double precision, intent(in), optional :: inv_rho(ixo^s)
1389
1390 if(present(inv_rho)) then
1391 ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2*inv_rho(ixo^s)
1392 else
1393 ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2/w(ixo^s,rho_)
1394 end if
1395 end function ffhd_kin_en_origin
1396
1397
1398 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
1400 integer, intent(in) :: ixi^l, ixo^l
1401 double precision, intent(in) :: w(ixi^s,1:nw)
1402 double precision, intent(in) :: x(ixi^s,1:ndim)
1403 double precision, intent(out):: rfactor(ixi^s)
1404
1405 rfactor(ixo^s)=rr
1407
1408 subroutine add_hyperbolic_tc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1410
1411 integer, intent(in) :: ixi^l,ixo^l
1412 double precision, intent(in) :: qdt
1413 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
1414 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
1415 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
1416
1417 double precision, dimension(ixI^S) :: te, r
1418 double precision :: sigma_t5,sigma_t7,sigmat5_bgradt,f_sat,tau
1419 integer :: ix^d
1420
1421 ! EoS-aware temperature: T = p/(R*rho). For FI R=RR (=1 under eq_state_units)
1422 ! recovers p/rho; for LTE R=Rfactor_from_LTE varies, so LTE+HTC is physically
1423 ! consistent. Computed over ixI^L (the +-2 stencil reaches ghost layers;
1424 ! their R uses the update_eos_4_bc-refreshed aux state, as in mhd).
1425 call ffhd_get_rfactor(wct,x,ixi^l,ixi^l,r)
1426 te(ixi^s)=wctprim(ixi^s,p_)/(r(ixi^s)*wct(ixi^s,rho_))
1427 ! temperature on face T_(i+1/2)=(7(T_i+T_(i+1))-(T_(i-1)+T_(i+2)))/12
1428 ! T_(i+1/2)-T_(i-1/2)=(8(T_(i+1)-T_(i-1))-T_(i+2)+T_(i-2))/12
1429 {^iftwod
1430 do ix2=ixomin2,ixomax2
1431 do ix1=ixomin1,ixomax1
1432 if(ffhd_trac) then
1433 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
1434 sigma_t5=hyperbolic_tc_kappa*sqrt(block%wextra(ix^d,tcoff_)**5)
1435 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
1436 else
1437 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1438 sigma_t7=sigma_t5*te(ix^d)
1439 end if
1440 else
1441 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1442 sigma_t7=sigma_t5*te(ix^d)
1443 end if
1444 sigmat5_bgradt=sigma_t5*(&
1445 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)&
1446 +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))
1447 if(ffhd_hyperbolic_tc_sat) then
1448 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
1449 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*wct(ix^d,rho_)*(wctprim(ix^d,p_)/wct(ix^d,rho_))**1.5d0))
1450 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1451 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
1452 else
1453 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
1454 max(4.d0*dt, sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1455 end if
1456 end do
1457 end do
1458 }
1459 {^ifthreed
1460 do ix3=ixomin3,ixomax3
1461 do ix2=ixomin2,ixomax2
1462 do ix1=ixomin1,ixomax1
1463 if(ffhd_trac) then
1464 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
1465 sigma_t5=hyperbolic_tc_kappa*sqrt(block%wextra(ix^d,tcoff_)**5)
1466 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
1467 else
1468 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1469 sigma_t7=sigma_t5*te(ix^d)
1470 end if
1471 else
1472 sigma_t5=hyperbolic_tc_kappa*sqrt(te(ix^d)**5)
1473 sigma_t7=sigma_t5*te(ix^d)
1474 end if
1475 sigmat5_bgradt=sigma_t5*(&
1476 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)&
1477 +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)&
1478 +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))
1479 if(ffhd_hyperbolic_tc_sat) then
1480 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
1481 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*wct(ix^d,rho_)*(wctprim(ix^d,p_)/wct(ix^d,rho_))**1.5d0))
1482 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1483 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
1484 else
1485 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
1486 max(4.d0*dt, sigma_t7*courantpar**2/(wctprim(ix^d,p_)*eos%inv_gamma_minus_1*cmax_global**2))
1487 end if
1488 end do
1489 end do
1490 end do
1491 }
1492 end subroutine add_hyperbolic_tc_source
1493
1494end 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