MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
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_comm_lib, only: mpistop
12 
13  implicit none
14  private
15 
16  !> Whether an energy equation is used
17  logical, public, protected :: ffhd_energy = .true.
18 
19  !> Whether thermal conduction is used
20  logical, public, protected :: ffhd_thermal_conduction = .false.
21  !> Whether hyperbolic type thermal conduction is used
22  logical, public, protected :: ffhd_hyperbolic_thermal_conduction = .false.
23  !> type of fluid for thermal conduction
24  type(tc_fluid), public, allocatable :: tc_fl
25  !> type of fluid for thermal emission synthesis
26  type(te_fluid), public, allocatable :: te_fl_ffhd
27 
28  !> Whether radiative cooling is added
29  logical, public, protected :: ffhd_radiative_cooling = .false.
30  !> type of fluid for radiative cooling
31  type(rc_fluid), public, allocatable :: rc_fl
32 
33  !> Whether viscosity is added
34  logical, public, protected :: ffhd_viscosity = .false.
35 
36  !> Whether gravity is added
37  logical, public, protected :: ffhd_gravity = .false.
38 
39  !> Whether TRAC method is used
40  logical, public, protected :: ffhd_trac = .false.
41 
42  !> Which TRAC method is used
43  integer, public, protected :: ffhd_trac_type=1
44 
45  !> Height of the mask used in the TRAC method
46  double precision, public, protected :: ffhd_trac_mask = 0.d0
47 
48  !> Distance between two adjacent traced magnetic field lines (in finest cell size)
49  integer, public, protected :: ffhd_trac_finegrid=4
50 
51  !> Whether plasma is partially ionized
52  logical, public, protected :: ffhd_partial_ionization = .false.
53 
54  !> Index of the density (in the w array)
55  integer, public, protected :: rho_
56 
57  !> Indices of the momentum density
58  integer, allocatable, public, protected :: mom(:)
59 
60  !> Index of the energy density (-1 if not present)
61  integer, public, protected :: e_
62 
63  !> Index of the gas pressure (-1 if not present) should equal e_
64  integer, public, protected :: p_
65 
66  !> Indices of temperature
67  integer, public, protected :: te_
68 
69  !> Index of the cutoff temperature for the TRAC method
70  integer, public, protected :: tcoff_
71  integer, public, protected :: tweight_
72  integer, public, protected :: q_
73 
74  !> The adiabatic index
75  double precision, public :: ffhd_gamma = 5.d0/3.0d0
76 
77  !> The adiabatic constant
78  double precision, public :: ffhd_adiab = 1.0d0
79 
80  !> The small_est allowed energy
81  double precision, protected :: small_e
82 
83  !> The thermal conductivity kappa in hyperbolic thermal conduction
84  double precision, public :: hypertc_kappa
85 
86  !> Helium abundance over Hydrogen
87  double precision, public, protected :: he_abundance=0.1d0
88  !> Ionization fraction of H
89  !> H_ion_fr = H+/(H+ + H)
90  double precision, public, protected :: h_ion_fr=1d0
91  !> Ionization fraction of He
92  !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
93  double precision, public, protected :: he_ion_fr=1d0
94  !> Ratio of number He2+ / number He+ + He2+
95  !> He_ion_fr2 = He2+/(He2+ + He+)
96  double precision, public, protected :: he_ion_fr2=1d0
97  ! used for eq of state when it is not defined by units,
98  ! the units do not contain terms related to ionization fraction
99  ! and it is p = RR * rho * T
100  double precision, public, protected :: rr=1d0
101  ! remove the below flag and assume default value = .false.
102  ! when eq state properly implemented everywhere
103  ! and not anymore through units
104  logical, public, protected :: eq_state_units = .true.
105 
106  !> gamma minus one and its inverse
107  double precision :: gamma_1, inv_gamma_1
108 
109  !define the subroutine interface for the ambipolar mask
110  abstract interface
111 
112  function fun_kin_en(w, ixI^L, ixO^L, inv_rho) result(ke)
113  use mod_global_parameters, only: nw, ndim,block
114  integer, intent(in) :: ixi^l, ixo^l
115  double precision, intent(in) :: w(ixi^s, nw)
116  double precision :: ke(ixo^s)
117  double precision, intent(in), optional :: inv_rho(ixo^s)
118  end function fun_kin_en
119 
120  end interface
121 
122  procedure(sub_convert), pointer :: ffhd_to_primitive => null()
123  procedure(sub_convert), pointer :: ffhd_to_conserved => null()
124  procedure(sub_small_values), pointer :: ffhd_handle_small_values => null()
125  procedure(sub_get_pthermal), pointer :: ffhd_get_pthermal => null()
126  procedure(sub_get_pthermal), pointer :: ffhd_get_rfactor => null()
127  procedure(sub_get_pthermal), pointer :: ffhd_get_temperature => null()
128  procedure(sub_get_v), pointer :: ffhd_get_v => null()
129  procedure(fun_kin_en), pointer :: ffhd_kin_en => null()
130  ! Public methods
131  public :: ffhd_phys_init
132  public :: ffhd_kin_en
133  public :: ffhd_get_pthermal
134  public :: ffhd_get_temperature
135  public :: ffhd_get_v
136  public :: ffhd_get_rho
137  public :: ffhd_get_v_idim
138  public :: ffhd_to_conserved
139  public :: ffhd_to_primitive
140  public :: ffhd_get_csound2
141  public :: ffhd_e_to_ei
142  public :: ffhd_ei_to_e
143 
144 contains
145 
146  subroutine ffhd_read_params(files)
148  use mod_particles, only: particles_eta, particles_etah
149  character(len=*), intent(in) :: files(:)
150  integer :: n
151 
152  namelist /ffhd_list/ ffhd_energy, ffhd_gamma, ffhd_adiab,&
156 
157  do n = 1, size(files)
158  open(unitpar, file=trim(files(n)), status="old")
159  read(unitpar, ffhd_list, end=111)
160 111 close(unitpar)
161  end do
162  end subroutine ffhd_read_params
163 
164  !> Write this module's parameters to a snapsoht
165  subroutine ffhd_write_info(fh)
167  integer, intent(in) :: fh
168  integer, parameter :: n_par = 1
169  double precision :: values(n_par)
170  character(len=name_len) :: names(n_par)
171  integer, dimension(MPI_STATUS_SIZE) :: st
172  integer :: er
173 
174  call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
175 
176  names(1) = "gamma"
177  values(1) = ffhd_gamma
178  call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
179  call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
180  end subroutine ffhd_write_info
181 
182  subroutine ffhd_phys_init()
186  use mod_viscosity, only: viscosity_init
187  use mod_gravity, only: gravity_init
191  use mod_usr_methods, only: usr_rfactor
192  integer :: itr, idir
193 
194  call ffhd_read_params(par_files)
195 
196  if(.not. ffhd_energy) then
197  if(ffhd_thermal_conduction) then
199  if(mype==0) write(*,*) 'WARNING: set ffhd_thermal_conduction=F when ffhd_energy=F'
200  end if
201  if(ffhd_thermal_conduction) then
203  if(mype==0) write(*,*) 'WARNING: set ffhd_hyperbolic_thermal_conduction=F when ffhd_energy=F'
204  end if
205  if(ffhd_radiative_cooling) then
206  ffhd_radiative_cooling=.false.
207  if(mype==0) write(*,*) 'WARNING: set ffhd_radiative_cooling=F when ffhd_energy=F'
208  end if
209  if(ffhd_trac) then
210  ffhd_trac=.false.
211  if(mype==0) write(*,*) 'WARNING: set ffhd_trac=F when ffhd_energy=F'
212  end if
213  if(ffhd_partial_ionization) then
215  if(mype==0) write(*,*) 'WARNING: set ffhd_partial_ionization=F when ffhd_energy=F'
216  end if
217  end if
218  if(.not.eq_state_units) then
219  if(ffhd_partial_ionization) then
221  if(mype==0) write(*,*) 'WARNING: set ffhd_partial_ionization=F when eq_state_units=F'
222  end if
223  end if
224 
227  if(mype==0) write(*,*) 'WARNING: turn off parabolic TC when using hyperbolic TC'
228  end if
229 
230  physics_type = "ffhd"
231  phys_energy=ffhd_energy
232  phys_internal_e=.false.
235  phys_partial_ionization=ffhd_partial_ionization
236 
237  phys_gamma = ffhd_gamma
238  phys_total_energy=ffhd_energy
240 
241  {^ifoned
242  if(ffhd_trac .and. ffhd_trac_type .gt. 2) then
244  if(mype==0) write(*,*) 'WARNING: reset ffhd_trac_type=1 for 1D simulation'
245  end if
246  }
247  if(ffhd_trac .and. ffhd_trac_type .le. 4) then
248  ffhd_trac_mask=bigdouble
249  if(mype==0) write(*,*) 'WARNING: set ffhd_trac_mask==bigdouble for global TRAC method'
250  end if
252 
253  allocate(start_indices(number_species),stop_indices(number_species))
254  ! set the index of the first flux variable for species 1
255  start_indices(1)=1
256  ! Determine flux variables
257  rho_ = var_set_rho()
258 
259  allocate(mom(1))
260  mom(:) = var_set_momentum(1)
261 
262  ! Set index of energy variable
263  if(ffhd_energy) then
264  e_ = var_set_energy() ! energy density
265  p_ = e_ ! gas pressure
266  else
267  e_ = -1
268  p_ = -1
269  end if
270 
272  q_ = var_set_q()
273  need_global_cs2max=.true.
274  else
275  q_=-1
276  end if
277 
278  ! set number of variables which need update ghostcells
279  nwgc=nwflux
280 
281  ! set the index of the last flux variable for species 1
282  stop_indices(1)=nwflux
283 
284  ! Number of variables need reconstruction in w
285  nw_recon=nwflux
286 
287  ! set temperature as an auxiliary variable to get ionization degree
288  if(ffhd_partial_ionization) then
289  te_ = var_set_auxvar('Te','Te')
290  else
291  te_ = -1
292  end if
293 
294  ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
295  tweight_ = -1
296  if(ffhd_trac) then
297  tcoff_ = var_set_wextra()
298  iw_tcoff=tcoff_
299  if(ffhd_trac_type .ge. 3) then
300  tweight_ = var_set_wextra()
301  iw_tweight=tweight_
302  end if
303  else
304  tcoff_ = -1
305  end if
306 
307  nvector = 0 ! No. vector vars
308 
309  ! Check whether custom flux types have been defined
310  if(.not. allocated(flux_type)) then
311  allocate(flux_type(ndir, nwflux))
312  flux_type = flux_default
313  else if(any(shape(flux_type) /= [ndir, nwflux])) then
314  call mpistop("phys_check error: flux_type has wrong shape")
315  end if
316 
317  phys_get_dt => ffhd_get_dt
318  phys_get_cmax => ffhd_get_cmax_origin
319  phys_get_a2max => ffhd_get_a2max
320  phys_get_cs2max => ffhd_get_cs2max
321  phys_get_tcutoff => ffhd_get_tcutoff
322  phys_get_cbounds => ffhd_get_cbounds
323  phys_to_primitive => ffhd_to_primitive_origin
325  phys_to_conserved => ffhd_to_conserved_origin
327  phys_get_flux => ffhd_get_flux
328  phys_get_v => ffhd_get_v_origin
330  phys_get_rho => ffhd_get_rho
332  !> need to check source geom here
333  !phys_add_source_geom => ffhd_add_source_geom
334  phys_add_source => ffhd_add_source
335  phys_check_params => ffhd_check_params
336  phys_write_info => ffhd_write_info
337  phys_handle_small_values => ffhd_handle_small_values_origin
338  ffhd_handle_small_values => ffhd_handle_small_values_origin
339  phys_check_w => ffhd_check_w_origin
340 
341  if(.not.ffhd_energy) then
342  phys_get_pthermal => ffhd_get_pthermal_iso
344  else
345  phys_get_pthermal => ffhd_get_pthermal_origin
347  end if
348 
349  ! choose Rfactor in ideal gas law
350  if(ffhd_partial_ionization) then
351  ffhd_get_rfactor=>rfactor_from_temperature_ionization
352  phys_update_temperature => ffhd_update_temperature
353  else if(associated(usr_rfactor)) then
354  ffhd_get_rfactor=>usr_rfactor
355  else
356  ffhd_get_rfactor=>rfactor_from_constant_ionization
357  end if
358 
359  if(ffhd_partial_ionization) then
361  else
363  end if
364 
365  ! derive units from basic units
366  call ffhd_physical_units()
367 
370  end if
371  if(.not. ffhd_energy .and. ffhd_thermal_conduction) then
372  call mpistop("thermal conduction needs ffhd_energy=T")
373  end if
375  call mpistop("hyperbolic thermal conduction needs ffhd_energy=T")
376  end if
377  if(.not. ffhd_energy .and. ffhd_radiative_cooling) then
378  call mpistop("radiative cooling needs ffhd_energy=T")
379  end if
380 
381  ! initialize thermal conduction module
382  if(ffhd_thermal_conduction) then
383  phys_req_diagonal = .true.
384 
385  call sts_init()
387 
388  allocate(tc_fl)
391  tc_fl%get_temperature_from_conserved => ffhd_get_temperature_from_etot
392  tc_fl%get_temperature_from_eint => ffhd_get_temperature_from_eint
395  tc_fl%get_rho => ffhd_get_rho
396  tc_fl%e_ = e_
397  tc_fl%Tcoff_ = tcoff_
398  end if
399 
400  ! Initialize radiative cooling module
401  if(ffhd_radiative_cooling) then
403  allocate(rc_fl)
405  rc_fl%get_rho => ffhd_get_rho
406  rc_fl%get_pthermal => ffhd_get_pthermal
407  rc_fl%get_var_Rfactor => ffhd_get_rfactor
408  rc_fl%e_ = e_
409  rc_fl%Tcoff_ = tcoff_
410  rc_fl%has_equi = .false.
411  end if
412  allocate(te_fl_ffhd)
413  te_fl_ffhd%get_rho=> ffhd_get_rho
414  te_fl_ffhd%get_pthermal=> ffhd_get_pthermal
415  te_fl_ffhd%get_var_Rfactor => ffhd_get_rfactor
416 {^ifthreed
417  phys_te_images => ffhd_te_images
418 }
419  ! Initialize viscosity module
420  if(ffhd_viscosity) call viscosity_init(phys_wider_stencil,phys_req_diagonal)
421 
422  ! Initialize gravity module
423  if(ffhd_gravity) then
424  call gravity_init()
425  end if
426 
427  ! initialize ionization degree table
429  end subroutine ffhd_phys_init
430 
431 {^ifthreed
432  subroutine ffhd_te_images
435 
436  select case(convert_type)
437  case('EIvtiCCmpi','EIvtuCCmpi')
439  case('ESvtiCCmpi','ESvtuCCmpi')
441  case('SIvtiCCmpi','SIvtuCCmpi')
443  case('WIvtiCCmpi','WIvtuCCmpi')
445  case default
446  call mpistop("Error in synthesize emission: Unknown convert_type")
447  end select
448  end subroutine ffhd_te_images
449 }
450 
451  subroutine ffhd_sts_set_source_tc_ffhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
453  use mod_fix_conserve
455  integer, intent(in) :: ixI^L, ixO^L, igrid, nflux
456  double precision, intent(in) :: x(ixI^S,1:ndim)
457  double precision, intent(inout) :: wres(ixI^S,1:nw), w(ixI^S,1:nw)
458  double precision, intent(in) :: my_dt
459  logical, intent(in) :: fix_conserve_at_step
460  call sts_set_source_tc_ffhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
461  end subroutine ffhd_sts_set_source_tc_ffhd
462 
463  function ffhd_get_tc_dt_ffhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
464  !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
465  !where tc_k_para_i=tc_k_para*B_i**2/B**2
466  !and T=p/rho
469 
470  integer, intent(in) :: ixi^l, ixo^l
471  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
472  double precision, intent(in) :: w(ixi^s,1:nw)
473  double precision :: dtnew
474 
475  dtnew=get_tc_dt_ffhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
476  end function ffhd_get_tc_dt_ffhd
477 
478  subroutine ffhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
480 
481  integer, intent(in) :: ixI^L,ixO^L
482  double precision, intent(inout) :: w(ixI^S,1:nw)
483  double precision, intent(in) :: x(ixI^S,1:ndim)
484  integer, intent(in) :: step
485  character(len=140) :: error_msg
486 
487  write(error_msg,"(a,i3)") "Thermal conduction step ", step
488  call ffhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
489  end subroutine ffhd_tc_handle_small_e
490 
491  subroutine tc_params_read_ffhd(fl)
493  type(tc_fluid), intent(inout) :: fl
494  integer :: n
495  ! list parameters
496  logical :: tc_saturate=.false.
497  double precision :: tc_k_para=0d0
498  character(len=std_len) :: tc_slope_limiter="MC"
499 
500  namelist /tc_list/ tc_saturate, tc_slope_limiter, tc_k_para
501 
502  do n = 1, size(par_files)
503  open(unitpar, file=trim(par_files(n)), status="old")
504  read(unitpar, tc_list, end=111)
505 111 close(unitpar)
506  end do
507 
508  fl%tc_saturate = tc_saturate
509  fl%tc_k_para = tc_k_para
510  select case(tc_slope_limiter)
511  case ('no','none')
512  fl%tc_slope_limiter = 0
513  case ('MC')
514  ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
515  fl%tc_slope_limiter = 1
516  case('minmod')
517  ! minmod limiter
518  fl%tc_slope_limiter = 2
519  case ('superbee')
520  ! Roes superbee limiter (eq.3.51i)
521  fl%tc_slope_limiter = 3
522  case ('koren')
523  ! Barry Koren Right variant
524  fl%tc_slope_limiter = 4
525  case default
526  call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
527  end select
528  end subroutine tc_params_read_ffhd
529 
530  subroutine rc_params_read(fl)
532  use mod_constants, only: bigdouble
533  type(rc_fluid), intent(inout) :: fl
534  integer :: n
535  integer :: ncool = 4000
536  double precision :: cfrac=0.1d0
537 
538  !> Name of cooling curve
539  character(len=std_len) :: coolcurve='JCcorona'
540 
541  !> Name of cooling method
542  character(len=std_len) :: coolmethod='exact'
543 
544  !> Fixed temperature not lower than tlow
545  logical :: Tfix=.false.
546 
547  !> Lower limit of temperature
548  double precision :: tlow=bigdouble
549 
550  !> Add cooling source in a split way (.true.) or un-split way (.false.)
551  logical :: rc_split=.false.
552  logical :: rad_cut=.false.
553  double precision :: rad_cut_hgt=0.5d0
554  double precision :: rad_cut_dey=0.15d0
555 
556  namelist /rc_list/ coolcurve, coolmethod, ncool, cfrac, tlow, tfix, rc_split, rad_cut, rad_cut_hgt, rad_cut_dey
557 
558  do n = 1, size(par_files)
559  open(unitpar, file=trim(par_files(n)), status="old")
560  read(unitpar, rc_list, end=111)
561 111 close(unitpar)
562  end do
563 
564  fl%ncool=ncool
565  fl%coolcurve=coolcurve
566  fl%coolmethod=coolmethod
567  fl%tlow=tlow
568  fl%Tfix=tfix
569  fl%rc_split=rc_split
570  fl%cfrac=cfrac
571  fl%rad_cut=rad_cut
572  fl%rad_cut_hgt=rad_cut_hgt
573  fl%rad_cut_dey=rad_cut_dey
574  end subroutine rc_params_read
575 
576  subroutine ffhd_check_params
578  use mod_usr_methods
580 
581  gamma_1=ffhd_gamma-1.d0
582  if (.not. ffhd_energy) then
583  if (ffhd_gamma <= 0.0d0) call mpistop ("Error: ffhd_gamma <= 0")
584  if (ffhd_adiab < 0.0d0) call mpistop ("Error: ffhd_adiab < 0")
586  else
587  if (ffhd_gamma <= 0.0d0 .or. ffhd_gamma == 1.0d0) &
588  call mpistop ("Error: ffhd_gamma <= 0 or ffhd_gamma == 1")
589  inv_gamma_1=1.d0/gamma_1
590  small_e = small_pressure * inv_gamma_1
591  end if
592 
593  if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
594  call mpistop("usr_set_equi_vars has to be implemented in the user file")
595  end if
596  end subroutine ffhd_check_params
597 
598  subroutine ffhd_physical_units()
600  double precision :: mp,kB
601  double precision :: a,b
602 
603  if(si_unit) then
604  mp=mp_si
605  kb=kb_si
606  else
607  mp=mp_cgs
608  kb=kb_cgs
609  end if
610  if(eq_state_units) then
611  a = 1d0 + 4d0 * he_abundance
612  if(ffhd_partial_ionization) then
613  b = 2+.3d0
614  else
615  b = 1d0 + h_ion_fr + he_abundance*(he_ion_fr*(he_ion_fr2 + 1d0)+1d0)
616  end if
617  rr = 1d0
618  else
619  a = 1d0
620  b = 1d0
621  rr = (1d0 + h_ion_fr + he_abundance*(he_ion_fr*(he_ion_fr2 + 1d0)+1d0))/(1d0 + 4d0 * he_abundance)
622  end if
623  if(unit_density/=1.d0) then
625  else
627  end if
628  if(unit_velocity/=1.d0) then
631  else if(unit_pressure/=1.d0) then
634  else
637  end if
638  if(unit_time/=1.d0) then
640  else
642  end if
644  end subroutine ffhd_physical_units
645 
646  subroutine ffhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
648  logical, intent(in) :: primitive
649  integer, intent(in) :: ixI^L, ixO^L
650  double precision, intent(in) :: w(ixI^S,nw)
651  double precision :: tmp(ixI^S)
652  logical, intent(inout) :: flag(ixI^S,1:nw)
653 
654  flag=.false.
655  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
656 
657  if(ffhd_energy) then
658  if(primitive) then
659  where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
660  else
661  tmp(ixo^s)=w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l)
662  where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
663  end if
664  end if
665  end subroutine ffhd_check_w_origin
666 
667  subroutine ffhd_to_conserved_origin(ixI^L,ixO^L,w,x)
669  integer, intent(in) :: ixI^L, ixO^L
670  double precision, intent(inout) :: w(ixI^S, nw)
671  double precision, intent(in) :: x(ixI^S, 1:ndim)
672  double precision :: inv_gamma2(ixO^S)
673  integer :: idir
674 
675  if(ffhd_energy) then
676  w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1+half*w(ixo^s,mom(1))**2*w(ixo^s,rho_)
677  end if
678  w(ixo^s,mom(1))=w(ixo^s,rho_)*w(ixo^s,mom(1))
679  end subroutine ffhd_to_conserved_origin
680 
681  subroutine ffhd_to_primitive_origin(ixI^L,ixO^L,w,x)
683  integer, intent(in) :: ixI^L, ixO^L
684  double precision, intent(inout) :: w(ixI^S, nw)
685  double precision, intent(in) :: x(ixI^S, 1:ndim)
686  double precision :: inv_rho(ixO^S), gamma2(ixO^S)
687 
688  if(fix_small_values) then
689  !> fix small values preventing NaN numbers in the following converting
690  call ffhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'ffhd_to_primitive_origin')
691  end if
692 
693  w(ixo^s,mom(1)) = w(ixo^s,mom(1))/w(ixo^s,rho_)
694  if(ffhd_energy) then
695  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)-half*w(ixo^s,rho_)*w(ixo^s,mom(1))**2)
696  end if
697  end subroutine ffhd_to_primitive_origin
698 
699  subroutine ffhd_ei_to_e(ixI^L,ixO^L,w,x)
701  integer, intent(in) :: ixi^l, ixo^l
702  double precision, intent(inout) :: w(ixi^s, nw)
703  double precision, intent(in) :: x(ixi^s, 1:ndim)
704 
705  w(ixi^s,e_)=w(ixi^s,e_)+ffhd_kin_en(w,ixi^l,ixi^l)
706  end subroutine ffhd_ei_to_e
707 
708  subroutine ffhd_e_to_ei(ixI^L,ixO^L,w,x)
710  integer, intent(in) :: ixi^l, ixo^l
711  double precision, intent(inout) :: w(ixi^s, nw)
712  double precision, intent(in) :: x(ixi^s, 1:ndim)
713 
714  w(ixi^s,e_)=w(ixi^s,e_)-ffhd_kin_en(w,ixi^l,ixi^l)
715  if(fix_small_values) then
716  call ffhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'ffhd_e_to_ei')
717  end if
718  end subroutine ffhd_e_to_ei
719 
720  subroutine ffhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
722  use mod_small_values
723  logical, intent(in) :: primitive
724  integer, intent(in) :: ixI^L,ixO^L
725  double precision, intent(inout) :: w(ixI^S,1:nw)
726  double precision, intent(in) :: x(ixI^S,1:ndim)
727  character(len=*), intent(in) :: subname
728 
729  logical :: flag(ixI^S,1:nw)
730  double precision :: tmp2(ixI^S)
731 
732  call phys_check_w(primitive, ixi^l, ixi^l, w, flag)
733 
734  if(any(flag)) then
735  select case (small_values_method)
736  case ("replace")
737  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
738  if(small_values_fix_iw(mom(1))) then
739  where(flag(ixo^s,rho_)) w(ixo^s, mom(1)) = 0.0d0
740  end if
741  if(ffhd_energy) then
742  if(primitive) then
743  where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
744  else
745  where(flag(ixo^s,e_))
746  w(ixo^s,e_) = small_e+ffhd_kin_en(w,ixi^l,ixo^l)
747  end where
748  end if
749  end if
750  case ("average")
751  call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
752  if(ffhd_energy) then
753  if(primitive) then
754  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
755  else
756  w(ixi^s,e_)=w(ixi^s,e_)-ffhd_kin_en(w,ixi^l,ixi^l)
757  call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
758  w(ixi^s,e_)=w(ixi^s,e_)+ffhd_kin_en(w,ixi^l,ixi^l)
759  end if
760  end if
761  case default
762  if(.not.primitive) then
763  if(ffhd_energy) then
764  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
765  end if
766  w(ixo^s,mom(1))=w(ixo^s,mom(1))/w(ixo^s,rho_)
767  end if
768  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
769  end select
770  end if
771  end subroutine ffhd_handle_small_values_origin
772 
773  subroutine ffhd_get_v_origin(w,x,ixI^L,ixO^L,v)
775  integer, intent(in) :: ixI^L, ixO^L
776  double precision, intent(in) :: w(ixI^S,nw), x(ixI^S,1:ndim)
777  double precision, intent(out) :: v(ixI^S,ndir)
778  double precision :: rho(ixI^S)
779  integer :: idir
780 
781  call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
782  rho(ixo^s)=1.d0/rho(ixo^s)
783  do idir=1,ndir
784  v(ixo^s,ndir) = w(ixo^s,mom(1))*block%B0(ixo^s,idir,0)*rho(ixo^s)
785  end do
786  end subroutine ffhd_get_v_origin
787 
788  subroutine ffhd_get_v_idim(w,x,ixI^L,ixO^L,idim,v)
790  integer, intent(in) :: ixi^l, ixo^l, idim
791  double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
792  double precision, intent(out) :: v(ixi^s)
793  double precision :: rho(ixi^s)
794 
795  call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
796  v(ixo^s) = (w(ixo^s, mom(1))*block%B0(ixo^s,idim,0)) / rho(ixo^s)
797  end subroutine ffhd_get_v_idim
798 
799  subroutine ffhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
801  integer, intent(in) :: ixI^L, ixO^L, idim
802  ! w in primitive form
803  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
804  double precision, intent(inout) :: cmax(ixI^S)
805 
806  if(ffhd_energy) then
807  cmax(ixo^s)=sqrt(ffhd_gamma*w(ixo^s,p_)/w(ixo^s,rho_))*abs(block%B0(ixo^s,idim,idim))
808  else
809  cmax(ixo^s)=sqrt(ffhd_gamma*ffhd_adiab*w(ixo^s,rho_)**gamma_1)*abs(block%B0(ixo^s,idim,idim))
810  end if
811  cmax(ixo^s)=abs(w(ixo^s,mom(1))*block%B0(ixo^s,idim,0))+cmax(ixo^s)
812 
813  end subroutine ffhd_get_cmax_origin
814 
815  subroutine ffhd_get_cs2max(w,x,ixI^L,ixO^L,cs2max)
817  integer, intent(in) :: ixI^L, ixO^L
818  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
819  double precision, intent(inout) :: cs2max
820  double precision :: cs2(ixI^S)
821 
822  call ffhd_get_csound2(w,x,ixi^l,ixo^l,cs2)
823  cs2max=maxval(cs2(ixo^s))
824  end subroutine ffhd_get_cs2max
825 
826  subroutine ffhd_get_a2max(w,x,ixI^L,ixO^L,a2max)
828  integer, intent(in) :: ixI^L, ixO^L
829  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
830  double precision, intent(inout) :: a2max(ndim)
831  double precision :: a2(ixI^S,ndim,nw)
832  integer :: gxO^L,hxO^L,jxO^L,kxO^L,i,j
833 
834  a2=zero
835  do i = 1,ndim
836  !> 4th order
837  hxo^l=ixo^l-kr(i,^d);
838  gxo^l=hxo^l-kr(i,^d);
839  jxo^l=ixo^l+kr(i,^d);
840  kxo^l=jxo^l+kr(i,^d);
841  a2(ixo^s,i,1:nw)=abs(-w(kxo^s,1:nw)+16.d0*w(jxo^s,1:nw)&
842  -30.d0*w(ixo^s,1:nw)+16.d0*w(hxo^s,1:nw)-w(gxo^s,1:nw))
843  a2max(i)=maxval(a2(ixo^s,i,1:nw))/12.d0/dxlevel(i)**2
844  end do
845  end subroutine ffhd_get_a2max
846 
847  subroutine ffhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
849  use mod_geometry
850  integer, intent(in) :: ixI^L,ixO^L
851  double precision, intent(in) :: x(ixI^S,1:ndim)
852  double precision, intent(inout) :: w(ixI^S,1:nw)
853  double precision, intent(out) :: Tco_local,Tmax_local
854  double precision, parameter :: trac_delta=0.25d0
855  double precision :: tmp1(ixI^S),Te(ixI^S),lts(ixI^S)
856  double precision, dimension(ixI^S,1:ndir) :: bunitvec
857  double precision, dimension(ixI^S,1:ndim) :: gradT
858  double precision :: Bdir(ndim)
859  double precision :: ltrc,ltrp,altr(ixI^S)
860  integer :: idims,jxO^L,hxO^L,ixA^D,ixB^D
861  integer :: jxP^L,hxP^L,ixP^L,ixQ^L
862  logical :: lrlt(ixI^S)
863 
864  call ffhd_get_temperature(w,x,ixi^l,ixi^l,te)
865  tco_local=zero
866  tmax_local=maxval(te(ixo^s))
867 
868  {^ifoned
869  select case(ffhd_trac_type)
870  case(0)
871  !> test case, fixed cutoff temperature
872  block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
873  case(1)
874  hxo^l=ixo^l-1;
875  jxo^l=ixo^l+1;
876  lts(ixo^s)=0.5d0*abs(te(jxo^s)-te(hxo^s))/te(ixo^s)
877  lrlt=.false.
878  where(lts(ixo^s) > trac_delta)
879  lrlt(ixo^s)=.true.
880  end where
881  if(any(lrlt(ixo^s))) then
882  tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
883  end if
884  case(2)
885  !> iijima et al. 2021, LTRAC method
886  ltrc=1.5d0
887  ltrp=4.d0
888  ixp^l=ixo^l^ladd1;
889  hxo^l=ixo^l-1;
890  jxo^l=ixo^l+1;
891  hxp^l=ixp^l-1;
892  jxp^l=ixp^l+1;
893  lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
894  lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
895  lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
896  block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
897  case default
898  call mpistop("ffhd_trac_type not allowed for 1D simulation")
899  end select
900  }
901  {^nooned
902  select case(ffhd_trac_type)
903  case(0)
904  !> test case, fixed cutoff temperature
905  if(slab_uniform) then
906  !> assume cgs units
907  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)
908  else
909  block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
910  end if
911  case(1,4,6)
912  do idims=1,ndim
913  call gradient(te,ixi^l,ixo^l,idims,tmp1)
914  gradt(ixo^s,idims)=tmp1(ixo^s)
915  end do
916  bunitvec(ixo^s,:)=block%B0(ixo^s,:,0)
917  if(ffhd_trac_type .gt. 1) then
918  ! B direction at cell center
919  bdir=zero
920  {do ixa^d=0,1\}
921  ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
922  bdir(1:ndim)=bdir(1:ndim)+bunitvec(ixb^d,1:ndim)
923  {end do\}
924  if(sum(bdir(:)**2) .gt. zero) then
925  bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
926  end if
927  block%special_values(3:ndim+2)=bdir(1:ndim)
928  end if
929  tmp1(ixo^s)=dsqrt(sum(bunitvec(ixo^s,:)**2,dim=ndim+1))
930  where(tmp1(ixo^s)/=0.d0)
931  tmp1(ixo^s)=1.d0/tmp1(ixo^s)
932  else where
933  tmp1(ixo^s)=bigdouble
934  end where
935  ! b unit vector: magnetic field direction vector
936  do idims=1,ndim
937  bunitvec(ixo^s,idims)=bunitvec(ixo^s,idims)*tmp1(ixo^s)
938  end do
939  ! temperature length scale inversed
940  lts(ixo^s)=abs(sum(gradt(ixo^s,1:ndim)*bunitvec(ixo^s,1:ndim),dim=ndim+1))/te(ixo^s)
941  ! fraction of cells size to temperature length scale
942  if(slab_uniform) then
943  lts(ixo^s)=minval(dxlevel)*lts(ixo^s)
944  else
945  lts(ixo^s)=minval(block%ds(ixo^s,:),dim=ndim+1)*lts(ixo^s)
946  end if
947  lrlt=.false.
948  where(lts(ixo^s) > trac_delta)
949  lrlt(ixo^s)=.true.
950  end where
951  if(any(lrlt(ixo^s))) then
952  block%special_values(1)=maxval(te(ixo^s), mask=lrlt(ixo^s))
953  else
954  block%special_values(1)=zero
955  end if
956  block%special_values(2)=tmax_local
957  case(2)
958  !> iijima et al. 2021, LTRAC method
959  ltrc=1.5d0
960  ltrp=4.d0
961  ixp^l=ixo^l^ladd2;
962  do idims=1,ndim
963  ixq^l=ixp^l;
964  hxp^l=ixp^l;
965  jxp^l=ixp^l;
966  select case(idims)
967  {case(^d)
968  ixqmin^d=ixqmin^d+1
969  ixqmax^d=ixqmax^d-1
970  hxpmax^d=ixpmin^d
971  jxpmin^d=ixpmax^d
972  \}
973  end select
974  call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
975  call gradientx(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),.false.)
976  call gradientq(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims))
977  end do
978  bunitvec(ixp^s,:)=block%B0(ixp^s,:,0)
979  lts(ixp^s)=abs(sum(gradt(ixp^s,1:ndim)*bunitvec(ixp^s,1:ndim),dim=ndim+1))/te(ixp^s)
980  if(slab_uniform) then
981  lts(ixp^s)=minval(dxlevel)*lts(ixp^s)
982  else
983  lts(ixp^s)=minval(block%ds(ixp^s,:),dim=ndim+1)*lts(ixp^s)
984  end if
985  lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
986 
987  altr=zero
988  ixp^l=ixo^l^ladd1;
989  do idims=1,ndim
990  hxo^l=ixp^l-kr(idims,^d);
991  jxo^l=ixp^l+kr(idims,^d);
992  altr(ixp^s)=altr(ixp^s)+0.25d0*(lts(hxo^s)+two*lts(ixp^s)+lts(jxo^s))*bunitvec(ixp^s,idims)**2
993  end do
994  block%wextra(ixp^s,tcoff_)=te(ixp^s)*altr(ixp^s)**0.4d0
995  case(3,5)
996  !> do nothing here
997  case default
998  call mpistop("unknown ffhd_trac_type")
999  end select
1000  }
1001  end subroutine ffhd_get_tcutoff
1002 
1003  subroutine ffhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
1005  integer, intent(in) :: ixI^L, ixO^L, idim
1006  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
1007  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
1008  double precision, intent(in) :: x(ixI^S,1:ndim)
1009  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
1010  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
1011  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
1012  double precision :: wmean(ixI^S,nw)
1013  double precision, dimension(ixI^S) :: umean, dmean, csoundL, csoundR, tmp1,tmp2,tmp3
1014  integer :: ix^D
1015 
1016  select case (boundspeed)
1017  case (1)
1018  ! This implements formula (10.52) from "Riemann Solvers and Numerical
1019  ! Methods for Fluid Dynamics" by Toro.
1020  tmp1(ixo^s)=sqrt(wlp(ixo^s,rho_))
1021  tmp2(ixo^s)=sqrt(wrp(ixo^s,rho_))
1022  tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
1023  umean(ixo^s)=(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)*tmp1(ixo^s)&
1024  +wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)*tmp2(ixo^s))*tmp3(ixo^s)
1025  call ffhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
1026  call ffhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
1027  dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)+tmp2(ixo^s)*csoundr(ixo^s)) * &
1028  tmp3(ixo^s) + 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2 * &
1029  (wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)-wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))**2
1030  dmean(ixo^s)=dsqrt(dmean(ixo^s))
1031  if(present(cmin)) then
1032  cmin(ixo^s,1)=umean(ixo^s)-dmean(ixo^s)
1033  cmax(ixo^s,1)=umean(ixo^s)+dmean(ixo^s)
1034  else
1035  cmax(ixo^s,1)=abs(umean(ixo^s))+dmean(ixo^s)
1036  end if
1037  case (2)
1038  wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
1039  tmp1(ixo^s)=wmean(ixo^s,mom(1))*block%B0(ixo^s,idim,idim)/wmean(ixo^s,rho_)
1040  call ffhd_get_csound(wmean,x,ixi^l,ixo^l,idim,csoundr)
1041  if(present(cmin)) then
1042  cmax(ixo^s,1)=max(tmp1(ixo^s)+csoundr(ixo^s),zero)
1043  cmin(ixo^s,1)=min(tmp1(ixo^s)-csoundr(ixo^s),zero)
1044  else
1045  cmax(ixo^s,1)=abs(tmp1(ixo^s))+csoundr(ixo^s)
1046  end if
1047  case (3)
1048  ! Miyoshi 2005 JCP 208, 315 equation (67)
1049  call ffhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
1050  call ffhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
1051  csoundl(ixo^s)=max(csoundl(ixo^s),csoundr(ixo^s))
1052  if(present(cmin)) then
1053  cmin(ixo^s,1)=min(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1054  wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))-csoundl(ixo^s)
1055  cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1056  wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1057  else
1058  cmax(ixo^s,1)=max(wlp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim),&
1059  wrp(ixo^s,mom(1))*block%B0(ixo^s,idim,idim))+csoundl(ixo^s)
1060  end if
1061  end select
1062  end subroutine ffhd_get_cbounds
1063 
1064  subroutine ffhd_get_csound(w,x,ixI^L,ixO^L,idim,csound)
1066  integer, intent(in) :: ixI^L, ixO^L, idim
1067  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
1068  double precision, intent(out):: csound(ixI^S)
1069 
1070  call ffhd_get_csound2(w,x,ixi^l,ixo^l,csound)
1071  csound(ixo^s) = dsqrt(csound(ixo^s))*abs(block%B0(ixo^s,idim,idim))
1072  end subroutine ffhd_get_csound
1073 
1074  !> Calculate fast magnetosonic wave speed
1075  subroutine ffhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
1077 
1078  integer, intent(in) :: ixI^L, ixO^L, idim
1079  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
1080  double precision, intent(out):: csound(ixI^S)
1081 
1082  if(ffhd_energy) then
1083  csound(ixo^s)=ffhd_gamma*w(ixo^s,e_)/w(ixo^s,rho_)
1084  else
1085  csound(ixo^s)=ffhd_gamma*ffhd_adiab*w(ixo^s,rho_)**gamma_1
1086  end if
1087  csound(ixo^s) = dsqrt(csound(ixo^s))
1088  end subroutine ffhd_get_csound_prim
1089 
1090  subroutine ffhd_get_pthermal_iso(w,x,ixI^L,ixO^L,pth)
1092 
1093  integer, intent(in) :: ixI^L, ixO^L
1094  double precision, intent(in) :: w(ixI^S,nw)
1095  double precision, intent(in) :: x(ixI^S,1:ndim)
1096  double precision, intent(out):: pth(ixI^S)
1097 
1098  call ffhd_get_rho(w,x,ixi^l,ixo^l,pth)
1099  pth(ixo^s)=ffhd_adiab*pth(ixo^s)**ffhd_gamma
1100  end subroutine ffhd_get_pthermal_iso
1101 
1102  subroutine ffhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
1105  integer, intent(in) :: ixI^L, ixO^L
1106  double precision, intent(in) :: w(ixI^S,nw)
1107  double precision, intent(in) :: x(ixI^S,1:ndim)
1108  double precision, intent(out):: pth(ixI^S)
1109  integer :: iw, ix^D
1110 
1111  pth(ixo^s)=gamma_1*(w(ixo^s,e_)-ffhd_kin_en(w,ixi^l,ixo^l))
1112  if (fix_small_values) then
1113  {do ix^db= ixo^lim^db\}
1114  if(pth(ix^d)<small_pressure) then
1115  pth(ix^d)=small_pressure
1116  end if
1117  {end do^D&\}
1118  elseif(check_small_values) then
1119  {do ix^db= ixo^lim^db\}
1120  if(pth(ix^d)<small_pressure) then
1121  write(*,*) "Error: small value of gas pressure",pth(ix^d),&
1122  " encountered when call ffhd_get_pthermal"
1123  write(*,*) "Iteration: ", it, " Time: ", global_time
1124  write(*,*) "Location: ", x(ix^d,:)
1125  write(*,*) "Cell number: ", ix^d
1126  do iw=1,nw
1127  write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
1128  end do
1129  ! use erroneous arithmetic operation to crash the run
1130  if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
1131  write(*,*) "Saving status at the previous time step"
1132  crash=.true.
1133  end if
1134  {end do^D&\}
1135  end if
1136  end subroutine ffhd_get_pthermal_origin
1137 
1138  subroutine ffhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
1140  integer, intent(in) :: ixI^L, ixO^L
1141  double precision, intent(in) :: w(ixI^S, 1:nw)
1142  double precision, intent(in) :: x(ixI^S, 1:ndim)
1143  double precision, intent(out):: res(ixI^S)
1144 
1145  res(ixo^s) = w(ixo^s, te_)
1146  end subroutine ffhd_get_temperature_from_te
1147 
1148  subroutine ffhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
1150  integer, intent(in) :: ixI^L, ixO^L
1151  double precision, intent(in) :: w(ixI^S, 1:nw)
1152  double precision, intent(in) :: x(ixI^S, 1:ndim)
1153  double precision, intent(out):: res(ixI^S)
1154  double precision :: R(ixI^S)
1155 
1156  call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1157  res(ixo^s) = gamma_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
1158  end subroutine ffhd_get_temperature_from_eint
1159 
1160  subroutine ffhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
1162  integer, intent(in) :: ixI^L, ixO^L
1163  double precision, intent(in) :: w(ixI^S, 1:nw)
1164  double precision, intent(in) :: x(ixI^S, 1:ndim)
1165  double precision, intent(out):: res(ixI^S)
1166 
1167  double precision :: R(ixI^S)
1168 
1169  call ffhd_get_rfactor(w,x,ixi^l,ixo^l,r)
1170  call ffhd_get_pthermal(w,x,ixi^l,ixo^l,res)
1171  res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
1172  end subroutine ffhd_get_temperature_from_etot
1173 
1174  subroutine ffhd_get_csound2(w,x,ixI^L,ixO^L,csound2)
1176  integer, intent(in) :: ixi^l, ixo^l
1177  double precision, intent(in) :: w(ixi^s,nw)
1178  double precision, intent(in) :: x(ixi^s,1:ndim)
1179  double precision, intent(out) :: csound2(ixi^s)
1180  double precision :: rho(ixi^s)
1181 
1182  call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1183  if(ffhd_energy) then
1184  call ffhd_get_pthermal(w,x,ixi^l,ixo^l,csound2)
1185  csound2(ixo^s)=ffhd_gamma*csound2(ixo^s)/rho(ixo^s)
1186  else
1187  csound2(ixo^s)=ffhd_gamma*ffhd_adiab*rho(ixo^s)**gamma_1
1188  end if
1189  end subroutine ffhd_get_csound2
1190 
1191  subroutine ffhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
1193  use mod_geometry
1194  integer, intent(in) :: ixI^L, ixO^L, idim
1195  ! conservative w
1196  double precision, intent(in) :: wC(ixI^S,nw)
1197  ! primitive w
1198  double precision, intent(in) :: w(ixI^S,nw)
1199  double precision, intent(in) :: x(ixI^S,1:ndim)
1200  double precision,intent(out) :: f(ixI^S,nwflux)
1201  double precision :: ptotal(ixO^S)
1202  double precision :: tmp(ixI^S)
1203  integer :: idirmin, iw, idir, jdir, kdir
1204  double precision, dimension(ixI^S) :: Te,tau,sigT
1205 
1206  f(ixo^s,rho_)=w(ixo^s,mom(1))*w(ixo^s,rho_)*block%B0(ixo^s,idim,idim)
1207 
1208  if(ffhd_energy) then
1209  ptotal(ixo^s)=w(ixo^s,p_)
1210  else
1211  ptotal(ixo^s)=ffhd_adiab*w(ixo^s,rho_)**ffhd_gamma
1212  end if
1213 
1214  ! Get flux of momentum
1215  f(ixo^s,mom(1))=(wc(ixo^s,mom(1))*w(ixo^s,mom(1))+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1216 
1217  ! Get flux of energy
1218  if(ffhd_energy) then
1219  f(ixo^s,e_)=w(ixo^s,mom(1))*(wc(ixo^s,e_)+ptotal(ixo^s))*block%B0(ixo^s,idim,idim)
1221  f(ixo^s,e_)=f(ixo^s,e_)+w(ixo^s,q_)*block%B0(ixo^s,idim,idim)
1222  f(ixo^s,q_)=zero
1223  end if
1224  end if
1225  end subroutine ffhd_get_flux
1226 
1227  subroutine ffhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
1231  use mod_gravity, only: gravity_add_source
1232  integer, intent(in) :: ixI^L, ixO^L
1233  double precision, intent(in) :: qdt,dtfactor
1234  double precision, intent(in) :: wCT(ixI^S,1:nw),wCTprim(ixI^S,1:nw), x(ixI^S,1:ndim)
1235  double precision, intent(inout) :: w(ixI^S,1:nw)
1236  logical, intent(in) :: qsourcesplit
1237  logical, intent(inout) :: active
1238 
1239  if (.not. qsourcesplit) then
1240  active = .true.
1241  call add_punitb(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1243  call add_hypertc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
1244  end if
1245  end if
1246 
1247  if(ffhd_radiative_cooling) then
1248  call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1249  w,x,qsourcesplit,active, rc_fl)
1250  end if
1251 
1252  if(ffhd_viscosity) then
1253  call viscosity_add_source(qdt,ixi^l,ixo^l,wct,&
1254  w,x,ffhd_energy,qsourcesplit,active)
1255  end if
1256 
1257  if(ffhd_gravity) then
1258  call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
1259  w,x,ffhd_energy,.false.,qsourcesplit,active)
1260  end if
1261 
1262  ! update temperature from new pressure, density, and old ionization degree
1263  if(ffhd_partial_ionization) then
1264  if(.not.qsourcesplit) then
1265  active = .true.
1266  call ffhd_update_temperature(ixi^l,ixo^l,wct,w,x)
1267  end if
1268  end if
1269  end subroutine ffhd_add_source
1270 
1271  subroutine add_punitb(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1273  use mod_geometry
1274  integer, intent(in) :: ixI^L,ixO^L
1275  double precision, intent(in) :: qdt
1276  double precision, intent(in) :: wCT(ixI^S,1:nw),x(ixI^S,1:ndim)
1277  double precision, intent(in) :: wCTprim(ixI^S,1:nw)
1278  double precision, intent(inout) :: w(ixI^S,1:nw)
1279 
1280  integer :: idims,hxO^L
1281  double precision :: divb(ixI^S)
1282 
1283  divb=zero
1284  if(slab_uniform) then
1285  do idims=1,ndim
1286  hxo^l=ixo^l-kr(idims,^d);
1287  divb(ixo^s)=divb(ixo^s)+(block%B0(ixo^s,idims,idims)-block%B0(hxo^s,idims,idims))/dxlevel(idims)
1288  end do
1289  else
1290  call divvector(block%B0(ixi^s,1:ndir,0),ixi^l,ixo^l,divb)
1291  end if
1292  w(ixo^s,mom(1))=w(ixo^s,mom(1))+qdt*wctprim(ixo^s,p_)*divb(ixo^s)
1293  end subroutine add_punitb
1294 
1295  subroutine ffhd_get_rho(w,x,ixI^L,ixO^L,rho)
1297  integer, intent(in) :: ixi^l, ixo^l
1298  double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
1299  double precision, intent(out) :: rho(ixi^s)
1300 
1301  rho(ixo^s) = w(ixo^s,rho_)
1302  end subroutine ffhd_get_rho
1303 
1304  subroutine ffhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
1306  use mod_small_values
1307  integer, intent(in) :: ixI^L,ixO^L, ie
1308  double precision, intent(inout) :: w(ixI^S,1:nw)
1309  double precision, intent(in) :: x(ixI^S,1:ndim)
1310  character(len=*), intent(in) :: subname
1311  integer :: idir
1312  logical :: flag(ixI^S,1:nw)
1313  double precision :: rho(ixI^S)
1314 
1315  flag=.false.
1316  where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
1317  if(any(flag(ixo^s,ie))) then
1318  select case (small_values_method)
1319  case ("replace")
1320  where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
1321  case ("average")
1322  call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
1323  case default
1324  w(ixo^s,e_)=w(ixo^s,e_)*gamma_1
1325  call ffhd_get_rho(w,x,ixi^l,ixo^l,rho)
1326  w(ixo^s,mom(1)) = w(ixo^s,mom(1))/rho(ixo^s)
1327  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
1328  end select
1329  end if
1330  end subroutine ffhd_handle_small_ei
1331 
1332  subroutine ffhd_update_temperature(ixI^L,ixO^L,wCT,w,x)
1335  integer, intent(in) :: ixI^L, ixO^L
1336  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
1337  double precision, intent(inout) :: w(ixI^S,1:nw)
1338  double precision :: iz_H(ixO^S),iz_He(ixO^S), pth(ixI^S)
1339 
1340  call ionization_degree_from_temperature(ixi^l,ixo^l,wct(ixi^s,te_),iz_h,iz_he)
1341  call ffhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
1342  w(ixo^s,te_)=(2.d0+3.d0*he_abundance)*pth(ixo^s)/(w(ixo^s,rho_)*(1.d0+iz_h(ixo^s)+&
1343  he_abundance*(iz_he(ixo^s)*(iz_he(ixo^s)+1.d0)+1.d0)))
1344  end subroutine ffhd_update_temperature
1345 
1346  subroutine ffhd_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
1348  use mod_usr_methods
1350  use mod_viscosity, only: viscosity_get_dt
1351  use mod_gravity, only: gravity_get_dt
1352  integer, intent(in) :: ixI^L, ixO^L
1353  double precision, intent(inout) :: dtnew
1354  double precision, intent(in) :: dx^D
1355  double precision, intent(in) :: w(ixI^S,1:nw)
1356  double precision, intent(in) :: x(ixI^S,1:ndim)
1357  integer :: idirmin,idim
1358  double precision :: dxarr(ndim)
1359  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S)
1360 
1361  dtnew = bigdouble
1362 
1363  if(ffhd_radiative_cooling) then
1364  call cooling_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x,rc_fl)
1365  end if
1366 
1367  if(ffhd_viscosity) then
1368  call viscosity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
1369  end if
1370 
1371  if(ffhd_gravity) then
1372  call gravity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
1373  end if
1374  end subroutine ffhd_get_dt
1375 
1376 ! subroutine ffhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
1377 ! use mod_global_parameters
1378 ! use mod_geometry
1379 !
1380 ! integer, intent(in) :: ixI^L, ixO^L
1381 ! double precision, intent(in) :: qdt, dtfactor,x(ixI^S,1:ndim)
1382 ! double precision, intent(inout) :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
1383 !
1384 ! integer :: iw,idir, h1x^L{^NOONED, h2x^L}
1385 ! double precision :: tmp(ixI^S),tmp1(ixI^S),tmp2(ixI^S),invrho(ixO^S),invr(ixO^S)
1386 !
1387 ! integer :: mr_,mphi_ ! Polar var. names
1388 ! integer :: br_,bphi_
1389 !
1390 ! mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
1391 ! br_=mag(1); bphi_=mag(1)-1+phi_
1392 !
1393 ! ! 1/rho
1394 ! invrho(ixO^S)=1.d0/wCT(ixO^S,rho_)
1395 ! ! include dt in invr, invr is always used with qdt
1396 ! if(local_timestep) then
1397 ! invr(ixO^S) = block%dt(ixO^S) * dtfactor/x(ixO^S,1)
1398 ! else
1399 ! invr(ixO^S) = qdt/x(ixO^S,1)
1400 ! end if
1401 !
1402 !
1403 ! select case (coordinate)
1404 ! case (cylindrical)
1405 ! call ffhd_get_p_total(wCT,x,ixI^L,ixO^L,tmp)
1406 ! if(phi_>0) then
1407 ! w(ixO^S,mr_)=w(ixO^S,mr_)+invr(ixO^S)*(tmp(ixO^S)-&
1408 ! wCT(ixO^S,bphi_)**2+wCT(ixO^S,mphi_)**2*invrho(ixO^S))
1409 ! w(ixO^S,mphi_)=w(ixO^S,mphi_)+invr(ixO^S)*(&
1410 ! -wCT(ixO^S,mphi_)*wCT(ixO^S,mr_)*invrho(ixO^S) &
1411 ! +wCT(ixO^S,bphi_)*wCT(ixO^S,br_))
1412 ! if(.not.stagger_grid) then
1413 ! w(ixO^S,bphi_)=w(ixO^S,bphi_)+invr(ixO^S)*&
1414 ! (wCT(ixO^S,bphi_)*wCT(ixO^S,mr_) &
1415 ! -wCT(ixO^S,br_)*wCT(ixO^S,mphi_)) &
1416 ! *invrho(ixO^S)
1417 ! end if
1418 ! else
1419 ! w(ixO^S,mr_)=w(ixO^S,mr_)+invr(ixO^S)*tmp(ixO^S)
1420 ! end if
1421 ! if(ffhd_glm) w(ixO^S,br_)=w(ixO^S,br_)+wCT(ixO^S,psi_)*invr(ixO^S)
1422 ! case (spherical)
1423 ! h1x^L=ixO^L-kr(1,^D); {^NOONED h2x^L=ixO^L-kr(2,^D);}
1424 ! call ffhd_get_p_total(wCT,x,ixI^L,ixO^L,tmp1)
1425 ! ! m1
1426 ! tmp(ixO^S)=tmp1(ixO^S)*x(ixO^S,1) &
1427 ! *(block%surfaceC(ixO^S,1)-block%surfaceC(h1x^S,1))/block%dvolume(ixO^S)
1428 ! do idir=2,ndir
1429 ! tmp(ixO^S)=tmp(ixO^S)+wCT(ixO^S,mom(idir))**2*invrho(ixO^S)-wCT(ixO^S,mag(idir))**2
1430 ! end do
1431 ! w(ixO^S,mom(1))=w(ixO^S,mom(1))+tmp(ixO^S)*invr(ixO^S)
1432 ! ! b1
1433 ! if(ffhd_glm) then
1434 ! w(ixO^S,mag(1))=w(ixO^S,mag(1))+invr(ixO^S)*2.0d0*wCT(ixO^S,psi_)
1435 ! end if
1436 !
1437 ! {^NOONED
1438 ! ! m2
1439 ! ! This will make hydrostatic p=const an exact solution
1440 ! if(local_timestep) then
1441 ! tmp(ixO^S) = block%dt(ixO^S) * tmp1(ixO^S)
1442 ! else
1443 ! tmp(ixO^S) = qdt * tmp1(ixO^S)
1444 ! end if
1445 ! w(ixO^S,mom(2))=w(ixO^S,mom(2))+tmp(ixO^S) &
1446 ! *(block%surfaceC(ixO^S,2)-block%surfaceC(h2x^S,2)) &
1447 ! /block%dvolume(ixO^S)
1448 ! tmp(ixO^S)=-(wCT(ixO^S,mom(1))*wCT(ixO^S,mom(2))*invrho(ixO^S) &
1449 ! -wCT(ixO^S,mag(1))*wCT(ixO^S,mag(2)))
1450 ! if(ndir==3) then
1451 ! tmp(ixO^S)=tmp(ixO^S)+(wCT(ixO^S,mom(3))**2*invrho(ixO^S) &
1452 ! -wCT(ixO^S,mag(3))**2)*dcos(x(ixO^S,2))/dsin(x(ixO^S,2))
1453 ! end if
1454 ! w(ixO^S,mom(2))=w(ixO^S,mom(2))+tmp(ixO^S)*invr(ixO^S)
1455 ! ! b2
1456 ! if(.not.stagger_grid) then
1457 ! tmp(ixO^S)=(wCT(ixO^S,mom(1))*wCT(ixO^S,mag(2)) &
1458 ! -wCT(ixO^S,mom(2))*wCT(ixO^S,mag(1)))*invrho(ixO^S)
1459 ! if(ffhd_glm) then
1460 ! tmp(ixO^S)=tmp(ixO^S) &
1461 ! + dcos(x(ixO^S,2))/dsin(x(ixO^S,2))*wCT(ixO^S,psi_)
1462 ! end if
1463 ! w(ixO^S,mag(2))=w(ixO^S,mag(2))+tmp(ixO^S)*invr(ixO^S)
1464 ! end if
1465 ! }
1466 !
1467 ! if(ndir==3) then
1468 ! ! m3
1469 ! tmp(ixO^S)=-(wCT(ixO^S,mom(3))*wCT(ixO^S,mom(1))*invrho(ixO^S) &
1470 ! -wCT(ixO^S,mag(3))*wCT(ixO^S,mag(1))) {^NOONED &
1471 ! -(wCT(ixO^S,mom(2))*wCT(ixO^S,mom(3))*invrho(ixO^S) &
1472 ! -wCT(ixO^S,mag(2))*wCT(ixO^S,mag(3))) &
1473 ! *dcos(x(ixO^S,2))/dsin(x(ixO^S,2)) }
1474 ! w(ixO^S,mom(3))=w(ixO^S,mom(3))+tmp(ixO^S)*invr(ixO^S)
1475 ! ! b3
1476 ! if(.not.stagger_grid) then
1477 ! tmp(ixO^S)=(wCT(ixO^S,mom(1))*wCT(ixO^S,mag(3)) &
1478 ! -wCT(ixO^S,mom(3))*wCT(ixO^S,mag(1)))*invrho(ixO^S) {^NOONED &
1479 ! -(wCT(ixO^S,mom(3))*wCT(ixO^S,mag(2)) &
1480 ! -wCT(ixO^S,mom(2))*wCT(ixO^S,mag(3)))*dcos(x(ixO^S,2)) &
1481 ! /(wCT(ixO^S,rho_)*dsin(x(ixO^S,2))) }
1482 ! w(ixO^S,mag(3))=w(ixO^S,mag(3))+tmp(ixO^S)*invr(ixO^S)
1483 ! end if
1484 ! end if
1485 ! end select
1486 ! end subroutine ffhd_add_source_geom
1487 
1488  function ffhd_kin_en_origin(w, ixI^L, ixO^L, inv_rho) result(ke)
1489  use mod_global_parameters, only: nw, ndim,block
1490  integer, intent(in) :: ixi^l, ixo^l
1491  double precision, intent(in) :: w(ixi^s, nw)
1492  double precision :: ke(ixo^s)
1493  double precision, intent(in), optional :: inv_rho(ixo^s)
1494 
1495  if(present(inv_rho)) then
1496  ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2*inv_rho(ixo^s)
1497  else
1498  ke(ixo^s)=0.5d0*w(ixo^s,mom(1))**2/w(ixo^s,rho_)
1499  end if
1500  end function ffhd_kin_en_origin
1501 
1502  subroutine rfactor_from_temperature_ionization(w,x,ixI^L,ixO^L,Rfactor)
1505  integer, intent(in) :: ixI^L, ixO^L
1506  double precision, intent(in) :: w(ixI^S,1:nw)
1507  double precision, intent(in) :: x(ixI^S,1:ndim)
1508  double precision, intent(out):: Rfactor(ixI^S)
1509  double precision :: iz_H(ixO^S),iz_He(ixO^S)
1510 
1511  call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,te_),iz_h,iz_he)
1512  rfactor(ixo^s)=(1.d0+iz_h(ixo^s)+0.1d0*(1.d0+iz_he(ixo^s)*(1.d0+iz_he(ixo^s))))/(2.d0+3.d0*he_abundance)
1514 
1515  subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
1517  integer, intent(in) :: ixI^L, ixO^L
1518  double precision, intent(in) :: w(ixI^S,1:nw)
1519  double precision, intent(in) :: x(ixI^S,1:ndim)
1520  double precision, intent(out):: Rfactor(ixI^S)
1521 
1522  rfactor(ixo^s)=rr
1523  end subroutine rfactor_from_constant_ionization
1524 
1525  subroutine get_tau(ixI^L,ixO^L,w,Te,tau,sigT5)
1527  integer, intent(in) :: ixI^L, ixO^L
1528  double precision, dimension(ixI^S,1:nw), intent(in) :: w
1529  double precision, dimension(ixI^S), intent(in) :: Te
1530  double precision, dimension(ixI^S), intent(out) :: tau,sigT5
1531  integer :: ix^D
1532  double precision :: dxmin,taumin
1533  double precision, dimension(ixI^S) :: sigT7,eint
1534 
1535  taumin=4.d0
1536  !> w supposed to be wCTprim here
1537  if(ffhd_trac) then
1538  where(te(ixo^s) .lt. block%wextra(ixo^s,tcoff_))
1539  sigt5(ixo^s)=hypertc_kappa*sqrt(block%wextra(ixo^s,tcoff_)**5)
1540  sigt7(ixo^s)=sigt5(ixo^s)*block%wextra(ixo^s,tcoff_)
1541  else where
1542  sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
1543  sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
1544  end where
1545  else
1546  sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
1547  sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
1548  end if
1549  eint(ixo^s)=w(ixo^s,p_)/(ffhd_gamma-one)
1550  tau(ixo^s)=max(taumin*dt,sigt7(ixo^s)/eint(ixo^s)/cs2max_global)
1551  end subroutine get_tau
1552 
1553  subroutine add_hypertc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
1555  integer, intent(in) :: ixI^L,ixO^L
1556  double precision, intent(in) :: qdt
1557  double precision, dimension(ixI^S,1:ndim), intent(in) :: x
1558  double precision, dimension(ixI^S,1:nw), intent(in) :: wCT,wCTprim
1559  double precision, dimension(ixI^S,1:nw), intent(inout) :: w
1560  integer :: idims
1561  integer :: hxC^L,hxO^L,ixC^L,jxC^L,jxO^L,kxC^L
1562  double precision :: invdx
1563  double precision, dimension(ixI^S) :: Te,tau,sigT,htc_qsrc,Tface
1564  double precision, dimension(ixI^S) :: htc_esrc
1565 
1566  te(ixi^s)=wctprim(ixi^s,p_)/wct(ixi^s,rho_)
1567  call get_tau(ixi^l,ixo^l,wctprim,te,tau,sigt)
1568  htc_qsrc=zero
1569  do idims=1,ndim
1570  invdx=1.d0/dxlevel(idims)
1571  ixc^l=ixo^l;
1572  ixcmin^d=ixomin^d-kr(idims,^d);ixcmax^d=ixomax^d;
1573  jxc^l=ixc^l+kr(idims,^d);
1574  kxc^l=jxc^l+kr(idims,^d);
1575  hxc^l=ixc^l-kr(idims,^d);
1576  hxo^l=ixo^l-kr(idims,^d);
1577  tface(ixc^s)=(7.d0*(te(ixc^s)+te(jxc^s))-(te(hxc^s)+te(kxc^s)))/12.d0
1578  htc_qsrc(ixo^s)=htc_qsrc(ixo^s)+sigt(ixo^s)*block%B0(ixo^s,idims,0)*(tface(ixo^s)-tface(hxo^s))*invdx
1579  end do
1580  htc_qsrc(ixo^s)=(htc_qsrc(ixo^s)+wct(ixo^s,q_))/tau(ixo^s)
1581  w(ixo^s,q_)=w(ixo^s,q_)-qdt*htc_qsrc(ixo^s)
1582  end subroutine add_hypertc_source
1583 end module mod_ffhd_phys
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: mod_comm_lib.t:208
Module for physical and numeric constants.
Definition: mod_constants.t:2
double precision, parameter bigdouble
A very large real number.
Definition: mod_constants.t:11
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition: mod_convert.t:59
Frozen-field hydrodynamics module.
Definition: mod_ffhd_phys.t:2
integer, public, protected te_
Indices of temperature.
Definition: mod_ffhd_phys.t:67
integer, public, protected ffhd_trac_type
Which TRAC method is used.
Definition: mod_ffhd_phys.t:43
subroutine ffhd_get_cs2max(w, x, ixIL, ixOL, cs2max)
double precision, public hypertc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
Definition: mod_ffhd_phys.t:84
integer, public, protected e_
Index of the energy density (-1 if not present)
Definition: mod_ffhd_phys.t:61
subroutine ffhd_handle_small_values_origin(primitive, w, x, ixIL, ixOL, subname)
double precision, public ffhd_gamma
The adiabatic index.
Definition: mod_ffhd_phys.t:75
double precision function ffhd_get_tc_dt_ffhd(w, ixIL, ixOL, dxD, x)
logical, public, protected eq_state_units
subroutine ffhd_update_temperature(ixIL, ixOL, wCT, w, x)
subroutine ffhd_get_temperature_from_eint(w, x, ixIL, ixOL, res)
subroutine ffhd_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
double precision, public ffhd_adiab
The adiabatic constant.
Definition: mod_ffhd_phys.t:78
procedure(sub_get_pthermal), pointer, public ffhd_get_temperature
subroutine ffhd_get_temperature_from_etot(w, x, ixIL, ixOL, res)
subroutine rfactor_from_constant_ionization(w, x, ixIL, ixOL, Rfactor)
logical, public, protected ffhd_hyperbolic_thermal_conduction
Whether hyperbolic type thermal conduction is used.
Definition: mod_ffhd_phys.t:22
subroutine, public ffhd_get_v_idim(w, x, ixIL, ixOL, idim, v)
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
Definition: mod_ffhd_phys.t:31
subroutine ffhd_get_tcutoff(ixIL, ixOL, w, x, Tco_local, Tmax_local)
subroutine tc_params_read_ffhd(fl)
integer, public, protected rho_
Index of the density (in the w array)
Definition: mod_ffhd_phys.t:55
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
Definition: mod_ffhd_phys.t:70
procedure(sub_get_pthermal), pointer, public ffhd_get_pthermal
subroutine ffhd_check_params
logical, public, protected ffhd_partial_ionization
Whether plasma is partially ionized.
Definition: mod_ffhd_phys.t:52
procedure(sub_convert), pointer, public ffhd_to_conserved
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
Definition: mod_ffhd_phys.t:58
subroutine ffhd_te_images
subroutine ffhd_to_conserved_origin(ixIL, ixOL, w, x)
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
Definition: mod_ffhd_phys.t:90
procedure(fun_kin_en), pointer, public ffhd_kin_en
subroutine, public ffhd_phys_init()
subroutine ffhd_add_source(qdt, dtfactor, ixIL, ixOL, wCT, wCTprim, w, x, qsourcesplit, active)
procedure(sub_get_v), pointer, public ffhd_get_v
subroutine ffhd_get_a2max(w, x, ixIL, ixOL, a2max)
subroutine ffhd_write_info(fh)
Write this module's parameters to a snapsoht.
subroutine ffhd_to_primitive_origin(ixIL, ixOL, w, x)
subroutine ffhd_get_cbounds(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
logical, public, protected ffhd_energy
Whether an energy equation is used.
Definition: mod_ffhd_phys.t:17
double precision, public, protected rr
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
Definition: mod_ffhd_phys.t:24
subroutine ffhd_get_flux(wC, w, x, ixIL, ixOL, idim, f)
subroutine ffhd_physical_units()
subroutine, public ffhd_e_to_ei(ixIL, ixOL, w, x)
subroutine add_punitb(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
subroutine ffhd_get_csound(w, x, ixIL, ixOL, idim, csound)
subroutine rfactor_from_temperature_ionization(w, x, ixIL, ixOL, Rfactor)
type(te_fluid), allocatable, public te_fl_ffhd
type of fluid for thermal emission synthesis
Definition: mod_ffhd_phys.t:26
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
Definition: mod_ffhd_phys.t:87
subroutine ffhd_get_v_origin(w, x, ixIL, ixOL, v)
logical, public, protected ffhd_viscosity
Whether viscosity is added.
Definition: mod_ffhd_phys.t:34
logical, public, protected ffhd_radiative_cooling
Whether radiative cooling is added.
Definition: mod_ffhd_phys.t:29
subroutine ffhd_get_temperature_from_te(w, x, ixIL, ixOL, res)
subroutine rc_params_read(fl)
subroutine ffhd_handle_small_ei(w, x, ixIL, ixOL, ie, subname)
integer, public, protected q_
Definition: mod_ffhd_phys.t:72
procedure(sub_convert), pointer, public ffhd_to_primitive
integer, public, protected tweight_
Definition: mod_ffhd_phys.t:71
subroutine ffhd_get_cmax_origin(w, x, ixIL, ixOL, idim, cmax)
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
Definition: mod_ffhd_phys.t:96
logical, public, protected ffhd_trac
Whether TRAC method is used.
Definition: mod_ffhd_phys.t:40
subroutine get_tau(ixIL, ixOL, w, Te, tau, sigT5)
subroutine ffhd_check_w_origin(primitive, ixIL, ixOL, w, flag)
subroutine ffhd_get_pthermal_origin(w, x, ixIL, ixOL, pth)
subroutine, public ffhd_ei_to_e(ixIL, ixOL, w, x)
subroutine ffhd_tc_handle_small_e(w, x, ixIL, ixOL, step)
logical, public, protected ffhd_thermal_conduction
Whether thermal conduction is used.
Definition: mod_ffhd_phys.t:20
logical, public, protected ffhd_gravity
Whether gravity is added.
Definition: mod_ffhd_phys.t:37
subroutine add_hypertc_source(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
Definition: mod_ffhd_phys.t:64
subroutine ffhd_get_pthermal_iso(w, x, ixIL, ixOL, pth)
subroutine ffhd_get_csound_prim(w, x, ixIL, ixOL, idim, csound)
Calculate fast magnetosonic wave speed.
double precision function, dimension(ixo^s) ffhd_kin_en_origin(w, ixIL, ixOL, inv_rho)
double precision, public, protected ffhd_trac_mask
Height of the mask used in the TRAC method.
Definition: mod_ffhd_phys.t:46
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
Definition: mod_ffhd_phys.t:93
subroutine, public ffhd_get_csound2(w, x, ixIL, ixOL, csound2)
subroutine, public ffhd_get_rho(w, x, ixIL, ixOL, rho)
integer, public, protected ffhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
Definition: mod_ffhd_phys.t:49
subroutine ffhd_sts_set_source_tc_ffhd(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux)
Module for flux conservation near refinement boundaries.
Module with geometry-related routines (e.g., divergence, curl)
Definition: mod_geometry.t:2
subroutine gradient(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:321
subroutine divvector(qvec, ixIL, ixOL, divq, fourthorder, sixthorder)
Calculate divergence of a vector qvec within ixL.
Definition: mod_geometry.t:516
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 small_pressure
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 phys_trac_mask
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.
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, dimension(:), allocatable, parameter d
double precision dt
global time step
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision unit_velocity
Physical scaling factor for velocity.
logical b0field
split magnetic field as background B0 field
logical need_global_cs2max
global value for csound speed
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
logical phys_trac
Use TRAC for MHD or 1D HD.
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
double precision cs2max_global
global largest cs2 for hyperbolic thermal conduction
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
double precision small_density
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(w, ixIL, ixOL, dtnew, dxD, x)
Definition: mod_gravity.t:87
subroutine gravity_add_source(qdt, ixIL, ixOL, wCT, wCTprim, w, x, energy, rhov, 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
subroutine gravity_init()
Initialize the module.
Definition: mod_gravity.t:26
module ionization degree - get ionization degree for given temperature
subroutine ionization_degree_from_temperature(ixIL, ixOL, Te, iz_H, iz_He)
Module containing all the particle routines.
Definition: mod_particles.t:2
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 for HD and MHD
subroutine radiative_cooling_init(fl, read_params)
subroutine cooling_get_dt(w, ixIL, ixOL, dtnew, dxD, x, fl)
subroutine radiative_cooling_init_params(phys_gamma, He_abund)
Radiative cooling initialization.
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.
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
subroutine, public small_values_average(ixIL, ixOL, w, x, w_flag, windex)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
subroutine, public small_values_error(wprim, x, ixIL, ixOL, w_flag, subname)
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method 1) in amrvac.par in sts_list set the following parameters which have...
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 sts_set_source_tc_ffhd(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 tc_init_params(phys_gamma)
double precision function, public get_tc_dt_ffhd(w, ixIL, ixOL, dxD, x, fl)
Get the explicut timestep for the TC (ffhd implementation)
subroutine, public tc_get_ffhd_params(fl, read_ffhd_params)
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
The module add viscous source terms and check time step.
Definition: mod_viscosity.t:10
subroutine viscosity_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
subroutine viscosity_add_source(qdt, ixIL, ixOL, wCT, w, x, energy, qsourcesplit, active)
Definition: mod_viscosity.t:90
subroutine viscosity_init(phys_wider_stencil, phys_req_diagonal)
Initialize the module.
Definition: mod_viscosity.t:59