MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
mod_mhd_phys.t
Go to the documentation of this file.
1 !> Magneto-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
13 
14  implicit none
15  private
16 
17  !> The adiabatic index
18  double precision, public :: mhd_gamma = 5.d0/3.0d0
19  !> The adiabatic constant
20  double precision, public :: mhd_adiab = 1.0d0
21  !> The MHD resistivity
22  double precision, public :: mhd_eta = 0.0d0
23  !> The MHD hyper-resistivity
24  double precision, public :: mhd_eta_hyper = 0.0d0
25  !> Hall resistivity
26  double precision, public :: mhd_etah = 0.0d0
27  !> The MHD ambipolar coefficient
28  double precision, public :: mhd_eta_ambi = 0.0d0
29  !> The small_est allowed energy
30  double precision, protected :: small_e
31  !> Height of the mask used in the TRAC method
32  double precision, public, protected :: mhd_trac_mask = 0.d0
33  !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
34  !> taking values within [0, 1]
35  double precision, public :: mhd_glm_alpha = 0.5d0
36  !> Reduced speed of light for semirelativistic MHD: 2% of light speed
37  double precision, public, protected :: mhd_reduced_c = 0.02d0*const_c
38  !> The thermal conductivity kappa in hyperbolic thermal conduction
39  double precision, public :: hypertc_kappa
40  !> Coefficient of diffusive divB cleaning
41  double precision :: divbdiff = 0.8d0
42  !> Helium abundance over Hydrogen
43  double precision, public, protected :: he_abundance=0.1d0
44  !> Ionization fraction of H
45  !> H_ion_fr = H+/(H+ + H)
46  double precision, public, protected :: h_ion_fr=1d0
47  !> Ionization fraction of He
48  !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
49  double precision, public, protected :: he_ion_fr=1d0
50  !> Ratio of number He2+ / number He+ + He2+
51  !> He_ion_fr2 = He2+/(He2+ + He+)
52  double precision, public, protected :: he_ion_fr2=1d0
53  ! used for eq of state when it is not defined by units,
54  ! the units do not contain terms related to ionization fraction
55  ! and it is p = RR * rho * T
56  double precision, public, protected :: rr=1d0
57  !> gamma minus one and its inverse
58  double precision :: gamma_1, inv_gamma_1
59  !> inverse of squared speed of light c0 and reduced speed of light c
60  double precision :: inv_squared_c0, inv_squared_c
61  !> equi vars indices in the state%equi_vars array
62  integer, public :: equi_rho0_ = -1
63  integer, public :: equi_pe0_ = -1
64  !> Number of tracer species
65  integer, public, protected :: mhd_n_tracer = 0
66  !> Index of the density (in the w array)
67  integer, public, protected :: rho_
68  !> Indices of the momentum density
69  integer, allocatable, public, protected :: mom(:)
70  !> Index of the energy density (-1 if not present)
71  integer, public, protected :: e_
72  !> Index of the gas pressure (-1 if not present) should equal e_
73  integer, public, protected :: p_
74  !> Index of the heat flux q
75  integer, public, protected :: q_
76  !> Indices of the GLM psi
77  integer, public, protected :: psi_
78  !> Indices of temperature
79  integer, public, protected :: te_
80  !> Index of the cutoff temperature for the TRAC method
81  integer, public, protected :: tcoff_
82  integer, public, protected :: tweight_
83  !> Indices of the tracers
84  integer, allocatable, public, protected :: tracer(:)
85  !> The number of waves
86  integer :: nwwave=8
87  !> Method type in a integer for good performance
88  integer :: type_divb
89  !> To skip * layer of ghost cells during divB=0 fix for boundary
90  integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
91  ! DivB cleaning methods
92  integer, parameter :: divb_none = 0
93  integer, parameter :: divb_multigrid = -1
94  integer, parameter :: divb_glm = 1
95  integer, parameter :: divb_powel = 2
96  integer, parameter :: divb_janhunen = 3
97  integer, parameter :: divb_linde = 4
98  integer, parameter :: divb_lindejanhunen = 5
99  integer, parameter :: divb_lindepowel = 6
100  integer, parameter :: divb_lindeglm = 7
101  integer, parameter :: divb_ct = 8
102  !> Whether an energy equation is used
103  logical, public, protected :: mhd_energy = .true.
104  !> Whether thermal conduction is used
105  logical, public, protected :: mhd_thermal_conduction = .false.
106  !> Whether radiative cooling is added
107  logical, public, protected :: mhd_radiative_cooling = .false.
108  !> Whether thermal conduction is used
109  logical, public, protected :: mhd_hyperbolic_thermal_conduction = .false.
110  !> Whether viscosity is added
111  logical, public, protected :: mhd_viscosity = .false.
112  !> Whether gravity is added
113  logical, public, protected :: mhd_gravity = .false.
114  !> Whether rotating frame is activated
115  logical, public, protected :: mhd_rotating_frame = .false.
116  !> Whether Hall-MHD is used
117  logical, public, protected :: mhd_hall = .false.
118  !> Whether Ambipolar term is used
119  logical, public, protected :: mhd_ambipolar = .false.
120  !> Whether Ambipolar term is implemented using supertimestepping
121  logical, public, protected :: mhd_ambipolar_sts = .false.
122  !> Whether Ambipolar term is implemented explicitly
123  logical, public, protected :: mhd_ambipolar_exp = .false.
124  !> Whether particles module is added
125  logical, public, protected :: mhd_particles = .false.
126  !> Whether magnetofriction is added
127  logical, public, protected :: mhd_magnetofriction = .false.
128  !> Whether GLM-MHD is used to control div B
129  logical, public, protected :: mhd_glm = .false.
130  !> Whether extended GLM-MHD is used with additional sources
131  logical, public, protected :: mhd_glm_extended = .true.
132  !> Whether TRAC method is used
133  logical, public, protected :: mhd_trac = .false.
134  !> Which TRAC method is used
135  integer, public, protected :: mhd_trac_type=1
136  !> Distance between two adjacent traced magnetic field lines (in finest cell size)
137  integer, public, protected :: mhd_trac_finegrid=4
138  !> Whether internal energy is solved instead of total energy
139  logical, public, protected :: mhd_internal_e = .false.
140  !TODO this does not work with the splitting: check mhd_check_w_hde and mhd_handle_small_values_hde
141  !> Whether hydrodynamic energy is solved instead of total energy
142  logical, public, protected :: mhd_hydrodynamic_e = .false.
143  !> Whether divB cleaning sources are added splitting from fluid solver
144  logical, public, protected :: source_split_divb = .false.
145  !TODO this does not work with the splitting: check mhd_check_w_semirelati and mhd_handle_small_values_semirelati
146  !> Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved
147  logical, public, protected :: mhd_semirelativistic = .false.
148  !> Whether plasma is partially ionized
149  logical, public, protected :: mhd_partial_ionization = .false.
150  !> Whether CAK radiation line force is activated
151  logical, public, protected :: mhd_cak_force = .false.
152  !> MHD fourth order
153  logical, public, protected :: mhd_4th_order = .false.
154  !> whether split off equilibrium density
155  logical, public :: has_equi_rho0 = .false.
156  !> whether split off equilibrium thermal pressure
157  logical, public :: has_equi_pe0 = .false.
158  logical, public :: mhd_equi_thermal = .false.
159  !> whether dump full variables (when splitting is used) in a separate dat file
160  logical, public, protected :: mhd_dump_full_vars = .false.
161  !> Whether divB is computed with a fourth order approximation
162  logical, public, protected :: mhd_divb_4thorder = .false.
163  !> Use a compact way to add resistivity
164  logical :: compactres = .false.
165  !> Add divB wave in Roe solver
166  logical, public :: divbwave = .true.
167  !> clean initial divB
168  logical, public :: clean_initial_divb = .false.
169  ! remove the below flag and assume default value = .false.
170  ! when eq state properly implemented everywhere
171  ! and not anymore through units
172  logical, public, protected :: eq_state_units = .true.
173  !> To control divB=0 fix for boundary
174  logical, public, protected :: boundary_divbfix(2*^nd)=.true.
175  !> B0 field is force-free
176  logical, public, protected :: b0field_forcefree=.true.
177  !> Whether an total energy equation is used
178  logical :: total_energy = .true.
179  !> Whether an internal or hydrodynamic energy equation is used
180  logical :: partial_energy = .false.
181  !> Whether gravity work is included in energy equation
182  logical :: gravity_energy
183  !> gravity work is calculated use density times velocity or conservative momentum
184  logical :: gravity_rhov = .false.
185  !> Method type to clean divergence of B
186  character(len=std_len), public, protected :: typedivbfix = 'linde'
187  !> Method type of constrained transport
188  character(len=std_len), public, protected :: type_ct = 'uct_contact'
189  !> Update all equations due to divB cleaning
190  character(len=std_len) :: typedivbdiff = 'all'
191  !> type of fluid for thermal conduction
192  type(tc_fluid), public, allocatable :: tc_fl
193  !> type of fluid for thermal emission synthesis
194  type(te_fluid), public, allocatable :: te_fl_mhd
195  !> type of fluid for radiative cooling
196  type(rc_fluid), public, allocatable :: rc_fl
197 
198  !define the subroutine interface for the ambipolar mask
199  abstract interface
200 
201  subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
203  integer, intent(in) :: ixi^l, ixo^l
204  double precision, intent(in) :: x(ixi^s,1:ndim)
205  double precision, intent(in) :: w(ixi^s,1:nw)
206  double precision, intent(inout) :: res(ixi^s)
207  end subroutine mask_subroutine
208 
209  function fun_kin_en(w, ixI^L, ixO^L, inv_rho) result(ke)
210  use mod_global_parameters, only: nw, ndim,block
211  integer, intent(in) :: ixI^L, ixO^L
212  double precision, intent(in) :: w(ixI^S, nw)
213  double precision :: ke(ixO^S)
214  double precision, intent(in), optional :: inv_rho(ixO^S)
215  end function fun_kin_en
216 
217  end interface
218 
219  procedure(mask_subroutine), pointer :: usr_mask_ambipolar => null()
220  procedure(sub_convert), pointer :: mhd_to_primitive => null()
221  procedure(sub_convert), pointer :: mhd_to_conserved => null()
222  procedure(sub_small_values), pointer :: mhd_handle_small_values => null()
223  procedure(sub_get_pthermal), pointer :: mhd_get_pthermal => null()
224  procedure(sub_get_pthermal), pointer :: mhd_get_rfactor => null()
225  procedure(sub_get_pthermal), pointer :: mhd_get_temperature=> null()
226  procedure(sub_get_v), pointer :: mhd_get_v => null()
227  procedure(fun_kin_en), pointer :: mhd_kin_en => null()
228  ! Public methods
229  public :: usr_mask_ambipolar
230  public :: mhd_phys_init
231  public :: mhd_kin_en
232  public :: mhd_get_pthermal
233  public :: mhd_get_temperature
234  public :: mhd_get_v
235  public :: mhd_get_rho
236  public :: mhd_get_v_idim
237  public :: mhd_to_conserved
238  public :: mhd_to_primitive
239  public :: mhd_get_csound2
240  public :: mhd_e_to_ei
241  public :: mhd_ei_to_e
242  public :: mhd_face_to_center
243  public :: get_divb
244  public :: get_current
245  !> needed public if we want to use the ambipolar coefficient in the user file
246  public :: multiplyambicoef
247  public :: get_normalized_divb
248  public :: b_from_vector_potential
249  public :: mhd_mag_en_all
250  {^nooned
251  public :: mhd_clean_divb_multigrid
252  }
253 
254 contains
255 
256  !> Read this module"s parameters from a file
257  subroutine mhd_read_params(files)
259  use mod_particles, only: particles_eta, particles_etah
260  character(len=*), intent(in) :: files(:)
261  integer :: n
262 
263  namelist /mhd_list/ mhd_energy, mhd_n_tracer, mhd_gamma, mhd_adiab,&
267  typedivbdiff, type_ct, compactres, divbwave, he_abundance, &
270  particles_eta, particles_etah,has_equi_rho0, has_equi_pe0,mhd_equi_thermal,&
275 
276  do n = 1, size(files)
277  open(unitpar, file=trim(files(n)), status="old")
278  read(unitpar, mhd_list, end=111)
279 111 close(unitpar)
280  end do
281 
282  end subroutine mhd_read_params
283 
284  !> Write this module's parameters to a snapsoht
285  subroutine mhd_write_info(fh)
287  integer, intent(in) :: fh
288 
289  integer, parameter :: n_par = 1
290  double precision :: values(n_par)
291  integer, dimension(MPI_STATUS_SIZE) :: st
292  integer :: er
293  character(len=name_len) :: names(n_par)
294 
295  call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
296 
297  names(1) = "gamma"
298  values(1) = mhd_gamma
299  call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
300  call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
301  end subroutine mhd_write_info
302 
303  subroutine mhd_phys_init()
307  use mod_viscosity, only: viscosity_init
308  use mod_gravity, only: gravity_init
309  use mod_particles, only: particles_init, particles_eta, particles_etah
314  use mod_cak_force, only: cak_init
316  use mod_usr_methods, only: usr_rfactor
317  {^nooned
319  }
320 
321  integer :: itr, idir
322 
323  call mhd_read_params(par_files)
324 
325  if(mhd_internal_e) then
326  if(mhd_hydrodynamic_e) then
327  mhd_hydrodynamic_e=.false.
328  if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_internal_e=T'
329  end if
330  end if
331 
332  if(mhd_semirelativistic) then
333  if(b0field) b0fieldalloccoarse=.true.
334  end if
335 
336  if(.not. mhd_energy) then
337  if(mhd_internal_e) then
338  mhd_internal_e=.false.
339  if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_energy=F'
340  end if
341  if(mhd_hydrodynamic_e) then
342  mhd_hydrodynamic_e=.false.
343  if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_energy=F'
344  end if
345  if(mhd_thermal_conduction) then
346  mhd_thermal_conduction=.false.
347  if(mype==0) write(*,*) 'WARNING: set mhd_thermal_conduction=F when mhd_energy=F'
348  end if
349  if(mhd_thermal_conduction) then
351  if(mype==0) write(*,*) 'WARNING: set mhd_hyperbolic_thermal_conduction=F when mhd_energy=F'
352  end if
353  if(mhd_radiative_cooling) then
354  mhd_radiative_cooling=.false.
355  if(mype==0) write(*,*) 'WARNING: set mhd_radiative_cooling=F when mhd_energy=F'
356  end if
357  if(mhd_trac) then
358  mhd_trac=.false.
359  if(mype==0) write(*,*) 'WARNING: set mhd_trac=F when mhd_energy=F'
360  end if
361  if(mhd_partial_ionization) then
362  mhd_partial_ionization=.false.
363  if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when mhd_energy=F'
364  end if
365  end if
366  if(.not.eq_state_units) then
367  if(mhd_partial_ionization) then
368  mhd_partial_ionization=.false.
369  if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when eq_state_units=F'
370  end if
371  end if
372 
374  mhd_thermal_conduction=.false.
375  if(mype==0) write(*,*) 'WARNING: turn off parabolic TC when using hyperbolic TC'
376  end if
377 
378 
379  physics_type = "mhd"
380  phys_energy=mhd_energy
381  phys_internal_e=mhd_internal_e
384  phys_partial_ionization=mhd_partial_ionization
385 
386  phys_gamma = mhd_gamma
388 
389  if(mhd_energy) then
391  partial_energy=.true.
392  total_energy=.false.
393  else
394  partial_energy=.false.
395  total_energy=.true.
396  end if
397  else
398  total_energy=.false.
399  end if
400  phys_total_energy=total_energy
401  if(mhd_energy) then
402  if(mhd_internal_e) then
403  gravity_energy=.false.
404  else
405  gravity_energy=.true.
406  end if
407  if(has_equi_rho0) then
408  gravity_rhov=.true.
409  end if
410  if(mhd_semirelativistic.and..not.mhd_hydrodynamic_e) then
411  gravity_rhov=.true.
412  end if
413  else
414  gravity_energy=.false.
415  end if
416 
417  {^ifoned
418  if(mhd_trac .and. mhd_trac_type .gt. 2) then
419  mhd_trac_type=1
420  if(mype==0) write(*,*) 'WARNING: reset mhd_trac_type=1 for 1D simulation'
421  end if
422  }
423  if(mhd_trac .and. mhd_trac_type .le. 4) then
424  mhd_trac_mask=bigdouble
425  if(mype==0) write(*,*) 'WARNING: set mhd_trac_mask==bigdouble for global TRAC method'
426  end if
428 
429  ! set default gamma for polytropic/isothermal process
431  if(ndim==1) typedivbfix='none'
432  select case (typedivbfix)
433  case ('none')
434  type_divb = divb_none
435  {^nooned
436  case ('multigrid')
437  type_divb = divb_multigrid
438  use_multigrid = .true.
439  mg%operator_type = mg_laplacian
440  phys_global_source_after => mhd_clean_divb_multigrid
441  }
442  case ('glm')
443  mhd_glm = .true.
444  need_global_cmax = .true.
445  type_divb = divb_glm
446  case ('powel', 'powell')
447  type_divb = divb_powel
448  case ('janhunen')
449  type_divb = divb_janhunen
450  case ('linde')
451  type_divb = divb_linde
452  case ('lindejanhunen')
453  type_divb = divb_lindejanhunen
454  case ('lindepowel')
455  type_divb = divb_lindepowel
456  case ('lindeglm')
457  mhd_glm = .true.
458  need_global_cmax = .true.
459  type_divb = divb_lindeglm
460  case ('ct')
461  type_divb = divb_ct
462  stagger_grid = .true.
463  case default
464  call mpistop('Unknown divB fix')
465  end select
466 
467  allocate(start_indices(number_species),stop_indices(number_species))
468  ! set the index of the first flux variable for species 1
469  start_indices(1)=1
470  ! Determine flux variables
471  rho_ = var_set_rho()
472 
473  allocate(mom(ndir))
474  mom(:) = var_set_momentum(ndir)
475 
476  ! Set index of energy variable
477  if (mhd_energy) then
478  nwwave = 8
479  e_ = var_set_energy() ! energy density
480  p_ = e_ ! gas pressure
481  else
482  nwwave = 7
483  e_ = -1
484  p_ = -1
485  end if
486 
487  allocate(mag(ndir))
488  mag(:) = var_set_bfield(ndir)
489 
490  if (mhd_glm) then
491  psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
492  else
493  psi_ = -1
494  end if
495 
497  ! hyperbolic thermal conduction flux q
498  q_ = var_set_q()
499  need_global_cmax=.true.
500  else
501  q_=-1
502  end if
503 
504  allocate(tracer(mhd_n_tracer))
505  ! Set starting index of tracers
506  do itr = 1, mhd_n_tracer
507  tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
508  end do
509 
510  !if(mhd_hyperbolic_thermal_conduction) then
511  ! ! hyperbolic thermal conduction flux q
512  ! q_ = var_set_auxvar('q','q')
513  ! need_global_cmax=.true.
514  !else
515  ! q_=-1
516  !end if
517 
518  ! set temperature as an auxiliary variable to get ionization degree
519  if(mhd_partial_ionization) then
520  te_ = var_set_auxvar('Te','Te')
521  else
522  te_ = -1
523  end if
524 
525  ! set number of variables which need update ghostcells
526  nwgc=nwflux+nwaux
527 
528  ! set the index of the last flux variable for species 1
529  stop_indices(1)=nwflux
530 
531  ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
532  tweight_ = -1
533  if(mhd_trac) then
534  tcoff_ = var_set_wextra()
535  iw_tcoff=tcoff_
536  if(mhd_trac_type .ge. 3) then
537  tweight_ = var_set_wextra()
538  endif
539  else
540  tcoff_ = -1
541  end if
542 
543  ! set indices of equi vars and update number_equi_vars
544  number_equi_vars = 0
545  if(has_equi_rho0) then
548  iw_equi_rho = equi_rho0_
549  endif
550  if(has_equi_pe0) then
553  iw_equi_p = equi_pe0_
554  phys_equi_pe=.true.
555  endif
556  ! determine number of stagger variables
557  nws=ndim
558 
559  nvector = 2 ! No. vector vars
560  allocate(iw_vector(nvector))
561  iw_vector(1) = mom(1) - 1 ! TODO: why like this?
562  iw_vector(2) = mag(1) - 1 ! TODO: why like this?
563 
564  ! Check whether custom flux types have been defined
565  if (.not. allocated(flux_type)) then
566  allocate(flux_type(ndir, nwflux))
567  flux_type = flux_default
568  else if (any(shape(flux_type) /= [ndir, nwflux])) then
569  call mpistop("phys_check error: flux_type has wrong shape")
570  end if
571 
572  if(nwflux>mag(ndir)) then
573  ! for flux of tracers, using hll flux
574  flux_type(:,mag(ndir)+1:nwflux)=flux_hll
575  end if
576 
577  if(ndim>1) then
578  if(mhd_glm) then
579  flux_type(:,psi_)=flux_special
580  do idir=1,ndir
581  flux_type(idir,mag(idir))=flux_special
582  end do
583  else
584  do idir=1,ndir
585  flux_type(idir,mag(idir))=flux_tvdlf
586  end do
587  end if
588  end if
589 
590  phys_get_rho => mhd_get_rho
591  phys_get_dt => mhd_get_dt
592  if(mhd_semirelativistic) then
593  phys_get_cmax => mhd_get_cmax_semirelati
594  else
595  phys_get_cmax => mhd_get_cmax_origin
596  end if
597  phys_get_a2max => mhd_get_a2max
598  phys_get_tcutoff => mhd_get_tcutoff
599  phys_get_h_speed => mhd_get_h_speed
600  if(has_equi_rho0) then
601  phys_get_cbounds => mhd_get_cbounds_split_rho
602  else if(mhd_semirelativistic) then
603  phys_get_cbounds => mhd_get_cbounds_semirelati
604  else
605  phys_get_cbounds => mhd_get_cbounds
606  end if
607  if(mhd_hydrodynamic_e) then
608  phys_to_primitive => mhd_to_primitive_hde
610  phys_to_conserved => mhd_to_conserved_hde
612  else if(mhd_semirelativistic) then
613  phys_to_primitive => mhd_to_primitive_semirelati
615  phys_to_conserved => mhd_to_conserved_semirelati
617  else
618  if(has_equi_rho0) then
619  phys_to_primitive => mhd_to_primitive_split_rho
621  phys_to_conserved => mhd_to_conserved_split_rho
623  else if(mhd_internal_e) then
624  phys_to_primitive => mhd_to_primitive_inte
626  phys_to_conserved => mhd_to_conserved_inte
628  else
629  phys_to_primitive => mhd_to_primitive_origin
631  phys_to_conserved => mhd_to_conserved_origin
633  end if
634  end if
635  if(mhd_hydrodynamic_e) then
636  phys_get_flux => mhd_get_flux_hde
637  else if(mhd_semirelativistic) then
638  phys_get_flux => mhd_get_flux_semirelati
639  else
640  if(b0field.or.has_equi_rho0.or.has_equi_pe0) then
641  phys_get_flux => mhd_get_flux_split
642  else
643  phys_get_flux => mhd_get_flux
644  end if
645  end if
646  phys_get_v => mhd_get_v_origin
649  if(b0field.or.has_equi_rho0) then
650  phys_add_source_geom => mhd_add_source_geom_split
651  else
652  phys_add_source_geom => mhd_add_source_geom
653  end if
654  phys_add_source => mhd_add_source
655  phys_check_params => mhd_check_params
656  phys_write_info => mhd_write_info
657 
658  if(mhd_hydrodynamic_e) then
659  phys_handle_small_values => mhd_handle_small_values_hde
660  mhd_handle_small_values => mhd_handle_small_values_hde
661  phys_check_w => mhd_check_w_hde
662  else if(mhd_semirelativistic) then
663  phys_handle_small_values => mhd_handle_small_values_semirelati
664  mhd_handle_small_values => mhd_handle_small_values_semirelati
665  phys_check_w => mhd_check_w_semirelati
666  else
667  if(mhd_internal_e) then
668  phys_handle_small_values => mhd_handle_small_values_inte
669  mhd_handle_small_values => mhd_handle_small_values_inte
670  phys_check_w => mhd_check_w_inte
671  else
672  phys_handle_small_values => mhd_handle_small_values_origin
673  mhd_handle_small_values => mhd_handle_small_values_origin
674  phys_check_w => mhd_check_w_origin
675  end if
676  end if
677 
678  if(.not.mhd_energy) then
679  phys_get_pthermal => mhd_get_pthermal_iso
681  else
682  if(mhd_internal_e) then
683  phys_get_pthermal => mhd_get_pthermal_eint
685  else if(mhd_hydrodynamic_e) then
686  phys_get_pthermal => mhd_get_pthermal_hde
688  else if(mhd_semirelativistic) then
689  phys_get_pthermal => mhd_get_pthermal_semirelati
691  else
692  phys_get_pthermal => mhd_get_pthermal_origin
694  end if
695  end if
696  if(number_equi_vars>0) then
697  phys_set_equi_vars => set_equi_vars_grid
698  endif
699 
700  if(type_divb==divb_glm) then
701  phys_modify_wlr => mhd_modify_wlr
702  end if
703 
704  ! choose Rfactor in ideal gas law
705  if(mhd_partial_ionization) then
706  mhd_get_rfactor=>rfactor_from_temperature_ionization
707  phys_update_temperature => mhd_update_temperature
708  else if(associated(usr_rfactor)) then
709  mhd_get_rfactor=>usr_rfactor
710  else
711  mhd_get_rfactor=>rfactor_from_constant_ionization
712  end if
713 
714  if(mhd_partial_ionization) then
716  else
717  if(mhd_internal_e) then
718  if(has_equi_pe0 .and. has_equi_rho0) then
720  else
722  end if
723  else
724  if(has_equi_pe0 .and. has_equi_rho0) then
726  else
728  end if
729  end if
730  end if
731 
732  ! if using ct stagger grid, boundary divb=0 is not done here
733  if(stagger_grid) then
734  phys_get_ct_velocity => mhd_get_ct_velocity
735  phys_update_faces => mhd_update_faces
736  phys_face_to_center => mhd_face_to_center
737  phys_modify_wlr => mhd_modify_wlr
738  else if(ndim>1) then
739  phys_boundary_adjust => mhd_boundary_adjust
740  end if
741 
742  {^nooned
743  ! clean initial divb
744  if(clean_initial_divb) phys_clean_divb => mhd_clean_divb_multigrid
745  }
746 
747  ! Whether diagonal ghost cells are required for the physics
748  if(type_divb < divb_linde) phys_req_diagonal = .false.
749 
750  ! derive units from basic units
751  call mhd_physical_units()
752 
755  end if
756  if(.not. mhd_energy .and. mhd_thermal_conduction) then
757  call mpistop("thermal conduction needs mhd_energy=T")
758  end if
759  if(.not. mhd_energy .and. mhd_hyperbolic_thermal_conduction) then
760  call mpistop("hyperbolic thermal conduction needs mhd_energy=T")
761  end if
762  if(.not. mhd_energy .and. mhd_radiative_cooling) then
763  call mpistop("radiative cooling needs mhd_energy=T")
764  end if
765 
766  ! resistive MHD needs diagonal ghost cells
767  if(mhd_eta/=0.d0) phys_req_diagonal = .true.
768 
769  ! initialize thermal conduction module
770  if (mhd_thermal_conduction) then
771  phys_req_diagonal = .true.
772 
773  call sts_init()
775 
776  allocate(tc_fl)
779  if(phys_internal_e) then
780  if(has_equi_pe0 .and. has_equi_rho0) then
781  tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint_with_equi
782  else
783  tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint
784  end if
785  else
786  if(has_equi_pe0 .and. has_equi_rho0) then
787  tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_etot_with_equi
788  else
789  tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_etot
790  end if
791  end if
792  if(has_equi_pe0 .and. has_equi_rho0) then
793  tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint_with_equi
794  if(mhd_equi_thermal) then
795  tc_fl%has_equi = .true.
796  tc_fl%get_temperature_equi => mhd_get_temperature_equi
797  tc_fl%get_rho_equi => mhd_get_rho_equi
798  else
799  tc_fl%has_equi = .false.
800  end if
801  else
802  tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint
803  end if
804  if(.not.mhd_internal_e) then
805  if(mhd_hydrodynamic_e) then
807  else if(mhd_semirelativistic) then
809  else
811  end if
812  end if
814  tc_fl%get_rho => mhd_get_rho
815  tc_fl%e_ = e_
816  tc_fl%Tcoff_ = tcoff_
817  end if
818 
819  ! Initialize radiative cooling module
820  if (mhd_radiative_cooling) then
822  allocate(rc_fl)
824  rc_fl%get_rho => mhd_get_rho
825  rc_fl%get_pthermal => mhd_get_pthermal
826  rc_fl%get_var_Rfactor => mhd_get_rfactor
827  rc_fl%e_ = e_
828  rc_fl%Tcoff_ = tcoff_
829  if(has_equi_pe0 .and. has_equi_rho0 .and. mhd_equi_thermal) then
830  rc_fl%has_equi = .true.
831  rc_fl%get_rho_equi => mhd_get_rho_equi
832  rc_fl%get_pthermal_equi => mhd_get_pe_equi
833  else
834  rc_fl%has_equi = .false.
835  end if
836  end if
837  allocate(te_fl_mhd)
838  te_fl_mhd%get_rho=> mhd_get_rho
839  te_fl_mhd%get_pthermal=> mhd_get_pthermal
840  te_fl_mhd%get_var_Rfactor => mhd_get_rfactor
841 {^ifthreed
842  phys_te_images => mhd_te_images
843 }
844  ! Initialize viscosity module
845  if (mhd_viscosity) call viscosity_init(phys_wider_stencil,phys_req_diagonal)
846 
847  ! Initialize gravity module
848  if(mhd_gravity) then
849  call gravity_init()
850  end if
851 
852  ! Initialize rotating frame module
854 
855  ! Initialize particles module
856  if(mhd_particles) then
857  call particles_init()
858  if (particles_eta < zero) particles_eta = mhd_eta
859  if (particles_etah < zero) particles_eta = mhd_etah
860  phys_req_diagonal = .true.
861  if(mype==0) then
862  write(*,*) '*****Using particles: with mhd_eta, mhd_etah :', mhd_eta, mhd_etah
863  write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
864  end if
865  end if
866 
867  ! initialize magnetofriction module
868  if(mhd_magnetofriction) then
869  phys_req_diagonal = .true.
870  call magnetofriction_init()
871  end if
872 
873  ! For Hall, we need one more reconstructed layer since currents are computed
874  ! in mhd_get_flux: assuming one additional ghost layer (two for FOURTHORDER) was
875  ! added in nghostcells.
876  if(mhd_hall) then
877  phys_req_diagonal = .true.
878  if(mhd_4th_order) then
879  phys_wider_stencil = 2
880  else
881  phys_wider_stencil = 1
882  end if
883  end if
884 
885  if(mhd_ambipolar) then
886  phys_req_diagonal = .true.
887  if(mhd_ambipolar_sts) then
888  call sts_init()
889  if(mhd_internal_e) then
891  ndir,mag(1),ndir,.true.)
892  else
894  mag(ndir)-mom(ndir),mag(1),ndir,.true.)
895  end if
896  else
897  mhd_ambipolar_exp=.true.
898  ! For flux ambipolar term, we need one more reconstructed layer since currents are computed
899  ! in mhd_get_flux: assuming one additional ghost layer (two for FOURTHORDER) was
900  ! added in nghostcells.
901  if(mhd_4th_order) then
902  phys_wider_stencil = 2
903  else
904  phys_wider_stencil = 1
905  end if
906  end if
907  end if
908 
909  ! initialize ionization degree table
911 
912  ! Initialize CAK radiation force module
913  if (mhd_cak_force) call cak_init(mhd_gamma)
914 
915  end subroutine mhd_phys_init
916 
917 {^ifthreed
918  subroutine mhd_te_images
921 
922  select case(convert_type)
923  case('EIvtiCCmpi','EIvtuCCmpi')
925  case('ESvtiCCmpi','ESvtuCCmpi')
927  case('SIvtiCCmpi','SIvtuCCmpi')
929  case('WIvtiCCmpi','WIvtuCCmpi')
931  case default
932  call mpistop("Error in synthesize emission: Unknown convert_type")
933  end select
934  end subroutine mhd_te_images
935 }
936 
937 !!start th cond
938  ! wrappers for STS functions in thermal_conductivity module
939  ! which take as argument the tc_fluid (defined in the physics module)
940  subroutine mhd_sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
942  use mod_fix_conserve
944  integer, intent(in) :: ixI^L, ixO^L, igrid, nflux
945  double precision, intent(in) :: x(ixI^S,1:ndim)
946  double precision, intent(inout) :: wres(ixI^S,1:nw), w(ixI^S,1:nw)
947  double precision, intent(in) :: my_dt
948  logical, intent(in) :: fix_conserve_at_step
949  call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
950  end subroutine mhd_sts_set_source_tc_mhd
951 
952  function mhd_get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
953  !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
954  !where tc_k_para_i=tc_k_para*B_i**2/B**2
955  !and T=p/rho
958 
959  integer, intent(in) :: ixi^l, ixo^l
960  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
961  double precision, intent(in) :: w(ixi^s,1:nw)
962  double precision :: dtnew
963 
964  dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
965  end function mhd_get_tc_dt_mhd
966 
967  subroutine mhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
969 
970  integer, intent(in) :: ixI^L,ixO^L
971  double precision, intent(inout) :: w(ixI^S,1:nw)
972  double precision, intent(in) :: x(ixI^S,1:ndim)
973  integer, intent(in) :: step
974  character(len=140) :: error_msg
975 
976  write(error_msg,"(a,i3)") "Thermal conduction step ", step
977  call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
978  end subroutine mhd_tc_handle_small_e
979 
980  ! fill in tc_fluid fields from namelist
981  subroutine tc_params_read_mhd(fl)
983  type(tc_fluid), intent(inout) :: fl
984 
985  double precision :: tc_k_para=0d0
986  double precision :: tc_k_perp=0d0
987  integer :: n
988  ! list parameters
989  logical :: tc_perpendicular=.false.
990  logical :: tc_saturate=.false.
991  character(len=std_len) :: tc_slope_limiter="MC"
992 
993  namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp
994 
995  do n = 1, size(par_files)
996  open(unitpar, file=trim(par_files(n)), status="old")
997  read(unitpar, tc_list, end=111)
998 111 close(unitpar)
999  end do
1000 
1001  fl%tc_perpendicular = tc_perpendicular
1002  fl%tc_saturate = tc_saturate
1003  fl%tc_k_para = tc_k_para
1004  fl%tc_k_perp = tc_k_perp
1005  select case(tc_slope_limiter)
1006  case ('no','none')
1007  fl%tc_slope_limiter = 0
1008  case ('MC')
1009  ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
1010  fl%tc_slope_limiter = 1
1011  case('minmod')
1012  ! minmod limiter
1013  fl%tc_slope_limiter = 2
1014  case ('superbee')
1015  ! Roes superbee limiter (eq.3.51i)
1016  fl%tc_slope_limiter = 3
1017  case ('koren')
1018  ! Barry Koren Right variant
1019  fl%tc_slope_limiter = 4
1020  case default
1021  call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
1022  end select
1023  end subroutine tc_params_read_mhd
1024 !!end th cond
1025 
1026 !!rad cool
1027  subroutine rc_params_read(fl)
1029  use mod_constants, only: bigdouble
1030  type(rc_fluid), intent(inout) :: fl
1031 
1032  double precision :: cfrac=0.1d0
1033  !> Lower limit of temperature
1034  double precision :: tlow=bigdouble
1035  double precision :: rad_cut_hgt=0.5d0
1036  double precision :: rad_cut_dey=0.15d0
1037  integer :: n
1038  ! list parameters
1039  integer :: ncool = 4000
1040  !> Fixed temperature not lower than tlow
1041  logical :: Tfix=.false.
1042  !> Add cooling source in a split way (.true.) or un-split way (.false.)
1043  logical :: rc_split=.false.
1044  logical :: rad_cut=.false.
1045  !> Name of cooling curve
1046  character(len=std_len) :: coolcurve='JCcorona'
1047  !> Name of cooling method
1048  character(len=std_len) :: coolmethod='exact'
1049 
1050  namelist /rc_list/ coolcurve, coolmethod, ncool, cfrac, tlow, tfix, rc_split,rad_cut,rad_cut_hgt,rad_cut_dey
1051 
1052  do n = 1, size(par_files)
1053  open(unitpar, file=trim(par_files(n)), status="old")
1054  read(unitpar, rc_list, end=111)
1055 111 close(unitpar)
1056  end do
1057 
1058  fl%ncool=ncool
1059  fl%coolcurve=coolcurve
1060  fl%coolmethod=coolmethod
1061  fl%tlow=tlow
1062  fl%Tfix=tfix
1063  fl%rc_split=rc_split
1064  fl%cfrac=cfrac
1065  fl%rad_cut=rad_cut
1066  fl%rad_cut_hgt=rad_cut_hgt
1067  fl%rad_cut_dey=rad_cut_dey
1068  end subroutine rc_params_read
1069 !! end rad cool
1070 
1071  !> sets the equilibrium variables
1072  subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1074  use mod_usr_methods
1075  integer, intent(in) :: igrid, ixI^L, ixO^L
1076  double precision, intent(in) :: x(ixI^S,1:ndim)
1077 
1078  double precision :: delx(ixI^S,1:ndim)
1079  double precision :: xC(ixI^S,1:ndim),xshift^D
1080  integer :: idims, ixC^L, hxO^L, ix, idims2
1081 
1082  if(slab_uniform)then
1083  ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1084  else
1085  ! for all non-cartesian and stretched cartesian coordinates
1086  delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1087  endif
1088 
1089  do idims=1,ndim
1090  hxo^l=ixo^l-kr(idims,^d);
1091  if(stagger_grid) then
1092  ! ct needs all transverse cells
1093  ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1094  else
1095  ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1096  ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1097  end if
1098  ! always xshift=0 or 1/2
1099  xshift^d=half*(one-kr(^d,idims));
1100  do idims2=1,ndim
1101  select case(idims2)
1102  {case(^d)
1103  do ix = ixc^lim^d
1104  ! xshift=half: this is the cell center coordinate
1105  ! xshift=0: this is the cell edge i+1/2 coordinate
1106  xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1107  end do\}
1108  end select
1109  end do
1110  call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1111  end do
1112 
1113  end subroutine set_equi_vars_grid_faces
1114 
1115  !> sets the equilibrium variables
1116  subroutine set_equi_vars_grid(igrid)
1118  use mod_usr_methods
1119 
1120  integer, intent(in) :: igrid
1121 
1122  !values at the center
1123  call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1124 
1125  !values at the interfaces
1126  call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1127 
1128  end subroutine set_equi_vars_grid
1129 
1130  ! w, wnew conserved, add splitted variables back to wnew
1131  function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1133  integer, intent(in) :: ixi^l,ixo^l, nwc
1134  double precision, intent(in) :: w(ixi^s, 1:nw)
1135  double precision, intent(in) :: x(ixi^s,1:ndim)
1136  double precision :: wnew(ixo^s, 1:nwc)
1137  double precision :: rho(ixi^s)
1138 
1139  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
1140  wnew(ixo^s,rho_) = rho(ixo^s)
1141  wnew(ixo^s,mom(:)) = w(ixo^s,mom(:))
1142 
1143  if (b0field) then
1144  ! add background magnetic field B0 to B
1145  wnew(ixo^s,mag(:))=w(ixo^s,mag(:))+block%B0(ixo^s,:,0)
1146  else
1147  wnew(ixo^s,mag(:))=w(ixo^s,mag(:))
1148  end if
1149 
1150  if(mhd_energy) then
1151  wnew(ixo^s,e_) = w(ixo^s,e_)
1152  if(has_equi_pe0) then
1153  wnew(ixo^s,e_) = wnew(ixo^s,e_) + block%equi_vars(ixo^s,equi_pe0_,0)* inv_gamma_1
1154  end if
1155  if(b0field .and. .not. mhd_internal_e) then
1156  wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1157  + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1158  end if
1159  end if
1160 
1161  end function convert_vars_splitting
1162 
1163  subroutine mhd_check_params
1165  use mod_usr_methods
1166  use mod_convert, only: add_convert_method
1167 
1168  ! after user parameter setting
1169  gamma_1=mhd_gamma-1.d0
1170  if (.not. mhd_energy) then
1171  if (mhd_gamma <= 0.0d0) call mpistop ("Error: mhd_gamma <= 0")
1172  if (mhd_adiab < 0.0d0) call mpistop ("Error: mhd_adiab < 0")
1174  else
1175  if (mhd_gamma <= 0.0d0 .or. mhd_gamma == 1.0d0) &
1176  call mpistop ("Error: mhd_gamma <= 0 or mhd_gamma == 1")
1177  inv_gamma_1=1.d0/gamma_1
1178  small_e = small_pressure * inv_gamma_1
1179  end if
1180 
1181  if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1182  call mpistop("usr_set_equi_vars has to be implemented in the user file")
1183  endif
1184  if(convert .or. autoconvert) then
1185  if(convert_type .eq. 'dat_generic_mpi') then
1186  if(mhd_dump_full_vars) then
1187  if(mype .eq. 0) print*, " add conversion method: split -> full "
1188  call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1189  endif
1190  endif
1191  endif
1192  end subroutine mhd_check_params
1193 
1194  subroutine mhd_physical_units()
1196  double precision :: mp,kB,miu0,c_lightspeed
1197  double precision :: a,b
1198  ! Derive scaling units
1199  if(si_unit) then
1200  mp=mp_si
1201  kb=kb_si
1202  miu0=miu0_si
1203  c_lightspeed=c_si
1204  else
1205  mp=mp_cgs
1206  kb=kb_cgs
1207  miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
1208  c_lightspeed=const_c
1209  end if
1210  if(eq_state_units) then
1211  a = 1d0 + 4d0 * he_abundance
1212  if(mhd_partial_ionization) then
1213  b = 2+.3d0
1214  else
1215  b = 1d0 + h_ion_fr + he_abundance*(he_ion_fr*(he_ion_fr2 + 1d0)+1d0)
1216  end if
1217  rr = 1d0
1218  else
1219  a = 1d0
1220  b = 1d0
1221  rr = (1d0 + h_ion_fr + he_abundance*(he_ion_fr*(he_ion_fr2 + 1d0)+1d0))/(1d0 + 4d0 * he_abundance)
1222  end if
1223  if(unit_density/=1.d0) then
1225  else
1226  ! unit of numberdensity is independent by default
1228  end if
1229  if(unit_velocity/=1.d0) then
1233  else if(unit_pressure/=1.d0) then
1237  else if(unit_magneticfield/=1.d0) then
1241  else if(unit_temperature/=1.d0) then
1245  end if
1246  if(unit_time/=1.d0) then
1248  else
1249  ! unit of length is independent by default
1251  end if
1252  ! Additional units needed for the particles
1253  c_norm=c_lightspeed/unit_velocity
1255  if (.not. si_unit) unit_charge = unit_charge*const_c
1257 
1258  if(mhd_semirelativistic) then
1259  if(mhd_reduced_c<1.d0) then
1260  ! dimensionless speed
1261  inv_squared_c0=1.d0
1262  inv_squared_c=1.d0/mhd_reduced_c**2
1263  else
1264  inv_squared_c0=(unit_velocity/c_lightspeed)**2
1265  inv_squared_c=(unit_velocity/mhd_reduced_c)**2
1266  end if
1267  end if
1268 
1269  end subroutine mhd_physical_units
1270 
1271  subroutine mhd_check_w_semirelati(primitive,ixI^L,ixO^L,w,flag)
1273 
1274  logical, intent(in) :: primitive
1275  logical, intent(inout) :: flag(ixI^S,1:nw)
1276  integer, intent(in) :: ixI^L, ixO^L
1277  double precision, intent(in) :: w(ixI^S,nw)
1278 
1279  double precision :: tmp,b2,b(3),Ba(1:ndir)
1280  double precision :: v(1:ndir),gamma2,inv_rho
1281  integer :: ix^D, idir
1282 
1283  flag=.false.
1284  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1285 
1286  if(mhd_energy) then
1287  if(primitive) then
1288  where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1289  else
1290  if(mhd_internal_e) then
1291  {do ix^db=ixomin^db,ixomax^db \}
1292  if(w(ix^d,e_) < small_e) flag(ix^d,e_) = .true.
1293  {end do\}
1294  else
1295  {do ix^db=ixomin^db,ixomax^db \}
1296  if(b0field) then
1297  ba(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i)
1298  else
1299  ba(1:ndir)=w(ix^d,mag(1:ndir))
1300  end if
1301  b2=sum(ba(1:ndir)**2)
1302  if(b2>smalldouble) then
1303  tmp=1.d0/sqrt(b2)
1304  else
1305  tmp=0.d0
1306  end if
1307  do idir=1,ndir
1308  b(idir)=ba(idir)*tmp
1309  end do
1310  tmp=sum(b(1:ndir)*w(ix^d,mom(1:ndir)))
1311  inv_rho = 1d0/w(ix^d,rho_)
1312  ! Va^2/c^2
1313  b2=b2*inv_rho*inv_squared_c
1314  ! equation (15)
1315  gamma2=1.d0/(1.d0+b2)
1316  ! Convert momentum to velocity
1317  do idir = 1, ndir
1318  v(idir)=gamma2*(w(ix^d,mom(idir))+b2*b(idir)*tmp*inv_rho)
1319  end do
1320  ! E=Bxv
1321  {^ifthreed
1322  b(1)=ba(2)*v(3)-ba(3)*v(2)
1323  b(2)=ba(3)*v(1)-ba(1)*v(3)
1324  b(3)=ba(1)*v(2)-ba(2)*v(1)
1325  }
1326  {^nothreed
1327  if(ndir==3) then
1328  b(1)=ba(2)*v(3)-ba(3)*v(2)
1329  b(2)=ba(3)*v(1)-ba(1)*v(3)
1330  else
1331  b(1:2)=zero
1332  end if
1333  b(3)=ba(1)*v(2)-ba(2)*v(1)
1334  }
1335  ! Calculate internal e = e-eK-eB-eE
1336  tmp=w(ix^d,e_)-half*(sum(v(1:ndir)**2)*w(ix^d,rho_)&
1337  +sum(w(ix^d,mag(1:ndir))**2)+sum(b(1:3)**2)*inv_squared_c)
1338  if(tmp<small_e) flag(ix^d,e_)=.true.
1339  {end do\}
1340  end if
1341  end if
1342  end if
1343 
1344  end subroutine mhd_check_w_semirelati
1345 
1346  subroutine mhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1348 
1349  logical, intent(in) :: primitive
1350  integer, intent(in) :: ixI^L, ixO^L
1351  double precision, intent(in) :: w(ixI^S,nw)
1352  logical, intent(inout) :: flag(ixI^S,1:nw)
1353 
1354  double precision :: tmp(ixI^S)
1355 
1356  flag=.false.
1357  if(has_equi_rho0) then
1358  tmp(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,0)
1359  where(tmp(ixo^s) < small_density) flag(ixo^s,rho_) = .true.
1360  else
1361  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1362  end if
1363 
1364  if(mhd_energy) then
1365  if(primitive) then
1366  if(has_equi_pe0) then
1367  tmp(ixo^s) = w(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)
1368  where(tmp(ixo^s) < small_pressure) flag(ixo^s,e_) = .true.
1369  else
1370  where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
1371  end if
1372  else
1373  tmp(ixo^s)=w(ixo^s,e_)-&
1374  mhd_kin_en(w,ixi^l,ixo^l)-mhd_mag_en(w,ixi^l,ixo^l)
1375  if(has_equi_pe0) then
1376  tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
1377  end if
1378  where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
1379  end if
1380  end if
1381 
1382  end subroutine mhd_check_w_origin
1383 
1384  subroutine mhd_check_w_inte(primitive,ixI^L,ixO^L,w,flag)
1386 
1387  logical, intent(in) :: primitive
1388  integer, intent(in) :: ixI^L, ixO^L
1389  double precision, intent(in) :: w(ixI^S,nw)
1390  logical, intent(inout) :: flag(ixI^S,1:nw)
1391 
1392  double precision :: tmp(ixI^S)
1393 
1394  flag=.false.
1395  if(has_equi_rho0) then
1396  tmp(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,0)
1397  where(tmp(ixo^s) < small_density) flag(ixo^s,rho_) = .true.
1398  else
1399  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1400  end if
1401 
1402  if(mhd_energy) then
1403  if(primitive) then
1404  if(has_equi_pe0) then
1405  tmp(ixo^s) = w(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)
1406  where(tmp(ixo^s) < small_pressure) flag(ixo^s,e_) = .true.
1407  else
1408  where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
1409  end if
1410  else
1411  if(has_equi_pe0) then
1412  tmp(ixo^s) = w(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
1413  where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
1414  else
1415  where(w(ixo^s,e_) < small_e) flag(ixo^s,e_) = .true.
1416  end if
1417  end if
1418  end if
1419 
1420  end subroutine mhd_check_w_inte
1421 
1422  subroutine mhd_check_w_hde(primitive,ixI^L,ixO^L,w,flag)
1424 
1425  logical, intent(in) :: primitive
1426  integer, intent(in) :: ixI^L, ixO^L
1427  double precision, intent(in) :: w(ixI^S,nw)
1428  logical, intent(inout) :: flag(ixI^S,1:nw)
1429 
1430  double precision :: tmp(ixI^S)
1431 
1432  flag=.false.
1433  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1434 
1435  if(mhd_energy) then
1436  if(primitive) then
1437  where(w(ixo^s,e_) < small_pressure) flag(ixo^s,e_) = .true.
1438  else
1439  tmp(ixo^s)=w(ixo^s,e_)-mhd_kin_en(w,ixi^l,ixo^l)
1440  where(tmp(ixo^s) < small_e) flag(ixo^s,e_) = .true.
1441  end if
1442  end if
1443 
1444  end subroutine mhd_check_w_hde
1445 
1446  !> Transform primitive variables into conservative ones
1447  subroutine mhd_to_conserved_origin(ixI^L,ixO^L,w,x)
1449  integer, intent(in) :: ixI^L, ixO^L
1450  double precision, intent(inout) :: w(ixI^S, nw)
1451  double precision, intent(in) :: x(ixI^S, 1:ndim)
1452 
1453  integer :: idir, ix^D
1454 
1455  !if (fix_small_values) then
1456  ! call mhd_handle_small_values(.true., w, x, ixI^L, ixO^L, 'mhd_to_conserved')
1457  !end if
1458 
1459  ! Calculate total energy from pressure, kinetic and magnetic energy
1460  if(mhd_energy) then
1461  {do ix^db=ixomin^db,ixomax^db\}
1462  w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1463  +half*(sum(w(ix^d,mom(1:ndir))**2)*w(ix^d,rho_)&
1464  +sum(w(ix^d,mag(1:ndir))**2))
1465  {end do\}
1466  end if
1467 
1468  ! Convert velocity to momentum
1469  do idir = 1, ndir
1470  w(ixo^s, mom(idir)) = w(ixo^s,rho_)*w(ixo^s, mom(idir))
1471  end do
1472 
1473  end subroutine mhd_to_conserved_origin
1474 
1475  !> Transform primitive variables into conservative ones
1476  subroutine mhd_to_conserved_hde(ixI^L,ixO^L,w,x)
1478  integer, intent(in) :: ixI^L, ixO^L
1479  double precision, intent(inout) :: w(ixI^S, nw)
1480  double precision, intent(in) :: x(ixI^S, 1:ndim)
1481 
1482  integer :: idir
1483 
1484  ! Calculate total energy from pressure, kinetic and magnetic energy
1485  if(mhd_energy) then
1486  w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1&
1487  +half*sum(w(ixo^s,mom(:))**2,dim=ndim+1)*w(ixo^s,rho_)
1488  end if
1489 
1490  ! Convert velocity to momentum
1491  do idir = 1, ndir
1492  w(ixo^s, mom(idir)) = w(ixo^s,rho_)*w(ixo^s, mom(idir))
1493  end do
1494 
1495  end subroutine mhd_to_conserved_hde
1496 
1497  !> Transform primitive variables into conservative ones
1498  subroutine mhd_to_conserved_inte(ixI^L,ixO^L,w,x)
1500  integer, intent(in) :: ixI^L, ixO^L
1501  double precision, intent(inout) :: w(ixI^S, nw)
1502  double precision, intent(in) :: x(ixI^S, 1:ndim)
1503 
1504  integer :: idir
1505 
1506  ! Calculate total energy from pressure, kinetic and magnetic energy
1507  if(mhd_energy) then
1508  w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1
1509  end if
1510 
1511  ! Convert velocity to momentum
1512  do idir = 1, ndir
1513  w(ixo^s, mom(idir)) = w(ixo^s,rho_)*w(ixo^s, mom(idir))
1514  end do
1515 
1516  end subroutine mhd_to_conserved_inte
1517 
1518  !> Transform primitive variables into conservative ones
1519  subroutine mhd_to_conserved_split_rho(ixI^L,ixO^L,w,x)
1521  integer, intent(in) :: ixI^L, ixO^L
1522  double precision, intent(inout) :: w(ixI^S, nw)
1523  double precision, intent(in) :: x(ixI^S, 1:ndim)
1524 
1525  double precision :: rho(ixO^S)
1526  integer :: idir
1527 
1528  !if (fix_small_values) then
1529  ! call mhd_handle_small_values(.true., w, x, ixI^L, ixO^L, 'mhd_to_conserved')
1530  !end if
1531 
1532  rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
1533  ! Calculate total energy from pressure, kinetic and magnetic energy
1534  if(mhd_energy) then
1535  if(mhd_internal_e) then
1536  w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1
1537  else
1538  w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1&
1539  +half*sum(w(ixo^s,mom(:))**2,dim=ndim+1)*rho(ixo^s)&
1540  +mhd_mag_en(w, ixi^l, ixo^l)
1541  end if
1542  end if
1543 
1544  ! Convert velocity to momentum
1545  do idir = 1, ndir
1546  w(ixo^s, mom(idir)) = rho(ixo^s) * w(ixo^s, mom(idir))
1547  end do
1548 
1549  end subroutine mhd_to_conserved_split_rho
1550 
1551  !> Transform primitive variables into conservative ones
1552  subroutine mhd_to_conserved_semirelati(ixI^L,ixO^L,w,x)
1554  integer, intent(in) :: ixI^L, ixO^L
1555  double precision, intent(inout) :: w(ixI^S, nw)
1556  double precision, intent(in) :: x(ixI^S, 1:ndim)
1557 
1558  double precision :: E(1:3), B(1:ndir), S(1:3)
1559  integer :: ix^D, idir
1560 
1561 
1562  {do ix^db=ixomin^db,ixomax^db\}
1563  if(b0field) then
1564  b(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i)
1565  else
1566  b(1:ndir)=w(ix^d,mag(1:ndir))
1567  end if
1568  {^ifthreed
1569  e(1)=b(2)*w(ix^d,mom(3))-b(3)*w(ix^d,mom(2))
1570  e(2)=b(3)*w(ix^d,mom(1))-b(1)*w(ix^d,mom(3))
1571  e(3)=b(1)*w(ix^d,mom(2))-b(2)*w(ix^d,mom(1))
1572  }
1573  {^nothreed
1574  if(ndir==3) then
1575  e(1)=b(2)*w(ix^d,mom(3))-b(3)*w(ix^d,mom(2))
1576  e(2)=b(3)*w(ix^d,mom(1))-b(1)*w(ix^d,mom(3))
1577  else
1578  e(1:2)=zero
1579  end if
1580  e(3)=b(1)*w(ix^d,mom(2))-b(2)*w(ix^d,mom(1))
1581  }
1582  ! equation (5) Poynting vector
1583  {^ifthreed
1584  s(1)=e(2)*b(3)-e(3)*b(2)
1585  s(2)=e(3)*b(1)-e(1)*b(3)
1586  s(3)=e(1)*b(2)-e(2)*b(1)
1587  }
1588  {^nothreed
1589  if(ndir==3) then
1590  s(1)=e(2)*b(3)-e(3)*b(2)
1591  s(2)=e(3)*b(1)-e(1)*b(3)
1592  else
1593  s(1:2)=zero
1594  end if
1595  s(3)=e(1)*b(2)-e(2)*b(1)
1596  }
1597  if(mhd_internal_e) then
1598  ! internal energy
1599  w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1
1600  else if(mhd_energy) then
1601  ! equation (9)
1602  ! Calculate total energy from internal, kinetic and magnetic energy
1603  w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1604  +half*(sum(w(ix^d,mom(1:ndir))**2)*w(ix^d,rho_)&
1605  +sum(w(ix^d,mag(1:ndir))**2)&
1606  +sum(e(1:3)**2)*inv_squared_c)
1607  end if
1608 
1609  ! Convert velocity to momentum, equation (9)
1610  do idir = 1, ndir
1611  w(ix^d, mom(idir))=w(ix^d,rho_)*w(ix^d, mom(idir))+s(idir)*inv_squared_c
1612  end do
1613 
1614  {end do\}
1615 
1616  end subroutine mhd_to_conserved_semirelati
1617 
1618  !> Transform conservative variables into primitive ones
1619  subroutine mhd_to_primitive_origin(ixI^L,ixO^L,w,x)
1621  integer, intent(in) :: ixI^L, ixO^L
1622  double precision, intent(inout) :: w(ixI^S, nw)
1623  double precision, intent(in) :: x(ixI^S, 1:ndim)
1624 
1625  double precision :: inv_rho(ixO^S)
1626  integer :: idir, ix^D
1627 
1628  if (fix_small_values) then
1629  ! fix small values preventing NaN numbers in the following converting
1630  call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin')
1631  end if
1632 
1633  inv_rho(ixo^s) = 1d0/w(ixo^s,rho_)
1634 
1635  ! Convert momentum to velocity
1636  do idir = 1, ndir
1637  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))*inv_rho
1638  end do
1639 
1640  ! Calculate pressure = (gamma-1) * (e-ek-eb)
1641  if(mhd_energy) then
1642  {do ix^db=ixomin^db,ixomax^db\}
1643  w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
1644  -half*(w(ix^d,rho_)*sum(w(ix^d,mom(1:ndir))**2)&
1645  +sum(w(ix^d,mag(1:ndir))**2)))
1646  {end do\}
1647  end if
1648 
1649  end subroutine mhd_to_primitive_origin
1650 
1651  !> Transform conservative variables into primitive ones
1652  subroutine mhd_to_primitive_hde(ixI^L,ixO^L,w,x)
1654  integer, intent(in) :: ixI^L, ixO^L
1655  double precision, intent(inout) :: w(ixI^S, nw)
1656  double precision, intent(in) :: x(ixI^S, 1:ndim)
1657 
1658  double precision :: inv_rho(ixO^S)
1659  integer :: idir
1660 
1661  if (fix_small_values) then
1662  ! fix small values preventing NaN numbers in the following converting
1663  call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_hde')
1664  end if
1665 
1666  inv_rho(ixo^s) = 1d0/w(ixo^s,rho_)
1667 
1668  ! Convert momentum to velocity
1669  do idir = 1, ndir
1670  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))*inv_rho
1671  end do
1672 
1673  ! Calculate pressure = (gamma-1) * (e-ek)
1674  if(mhd_energy) then
1675  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)-0.5d0*w(ixo^s,rho_)*sum(w(ixo^s,mom(:))**2,dim=ndim+1))
1676  end if
1677 
1678  end subroutine mhd_to_primitive_hde
1679 
1680  !> Transform conservative variables into primitive ones
1681  subroutine mhd_to_primitive_inte(ixI^L,ixO^L,w,x)
1683  integer, intent(in) :: ixI^L, ixO^L
1684  double precision, intent(inout) :: w(ixI^S, nw)
1685  double precision, intent(in) :: x(ixI^S, 1:ndim)
1686 
1687  double precision :: inv_rho(ixO^S)
1688  integer :: idir
1689 
1690  if (fix_small_values) then
1691  ! fix small values preventing NaN numbers in the following converting
1692  call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_inte')
1693  end if
1694 
1695  inv_rho(ixo^s) = 1d0/w(ixo^s,rho_)
1696 
1697  ! Calculate pressure = (gamma-1) * e_internal
1698  if(mhd_energy) then
1699  w(ixo^s,p_)=w(ixo^s,e_)*gamma_1
1700  end if
1701 
1702  ! Convert momentum to velocity
1703  do idir = 1, ndir
1704  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))*inv_rho
1705  end do
1706 
1707  end subroutine mhd_to_primitive_inte
1708 
1709  !> Transform conservative variables into primitive ones
1710  subroutine mhd_to_primitive_split_rho(ixI^L,ixO^L,w,x)
1712  integer, intent(in) :: ixI^L, ixO^L
1713  double precision, intent(inout) :: w(ixI^S, nw)
1714  double precision, intent(in) :: x(ixI^S, 1:ndim)
1715 
1716  double precision :: inv_rho(ixO^S)
1717  integer :: idir
1718 
1719  if (fix_small_values) then
1720  ! fix small values preventing NaN numbers in the following converting
1721  call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_split_rho')
1722  end if
1723 
1724  inv_rho(ixo^s) = 1d0/(w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i))
1725 
1726  ! Convert momentum to velocity
1727  do idir = 1, ndir
1728  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))*inv_rho
1729  end do
1730 
1731  ! Calculate pressure = (gamma-1) * (e-ek-eb)
1732  if(mhd_energy) then
1733  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)&
1734  -0.5d0*(w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,b0i))*&
1735  sum(w(ixo^s,mom(:))**2,dim=ndim+1)&
1736  -mhd_mag_en(w,ixi^l,ixo^l))
1737  end if
1738 
1739  end subroutine mhd_to_primitive_split_rho
1740 
1741  !> Transform conservative variables into primitive ones
1742  subroutine mhd_to_primitive_semirelati(ixI^L,ixO^L,w,x)
1744  integer, intent(in) :: ixI^L, ixO^L
1745  double precision, intent(inout) :: w(ixI^S, nw)
1746  double precision, intent(in) :: x(ixI^S, 1:ndim)
1747 
1748  double precision :: b(1:3), Ba(1:ndir), tmp, b2, gamma2, inv_rho
1749  integer :: ix^D, idir
1750 
1751  if (fix_small_values) then
1752  ! fix small values preventing NaN numbers in the following converting
1753  call mhd_handle_small_values_semirelati(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati')
1754  end if
1755 
1756  {do ix^db=ixomin^db,ixomax^db\}
1757  if(b0field) then
1758  ba(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i)
1759  else
1760  ba(1:ndir)=w(ix^d,mag(1:ndir))
1761  end if
1762  b2=sum(ba(1:ndir)**2)
1763  if(b2>smalldouble) then
1764  tmp=1.d0/sqrt(b2)
1765  else
1766  tmp=0.d0
1767  end if
1768  do idir=1,ndir
1769  b(idir)=ba(idir)*tmp
1770  end do
1771  tmp=sum(b(1:ndir)*w(ix^d,mom(1:ndir)))
1772 
1773  inv_rho=1.d0/w(ix^d,rho_)
1774  ! Va^2/c^2
1775  b2=b2*inv_rho*inv_squared_c
1776  ! equation (15)
1777  gamma2=1.d0/(1.d0+b2)
1778  ! Convert momentum to velocity
1779  do idir = 1, ndir
1780  w(ix^d,mom(idir))=gamma2*(w(ix^d,mom(idir))+b2*b(idir)*tmp)*inv_rho
1781  end do
1782 
1783  if(mhd_internal_e) then
1784  ! internal energy to pressure
1785  w(ix^d,p_)=gamma_1*w(ix^d,e_)
1786  else if(mhd_energy) then
1787  ! E=Bxv
1788  {^ifthreed
1789  b(1)=ba(2)*w(ix^d,mom(3))-ba(3)*w(ix^d,mom(2))
1790  b(2)=ba(3)*w(ix^d,mom(1))-ba(1)*w(ix^d,mom(3))
1791  b(3)=ba(1)*w(ix^d,mom(2))-ba(2)*w(ix^d,mom(1))
1792  }
1793  {^nothreed
1794  if(ndir==3) then
1795  b(1)=ba(2)*w(ix^d,mom(3))-ba(3)*w(ix^d,mom(2))
1796  b(2)=ba(3)*w(ix^d,mom(1))-ba(1)*w(ix^d,mom(3))
1797  else
1798  b(1:2)=zero
1799  end if
1800  b(3)=ba(1)*w(ix^d,mom(2))-ba(2)*w(ix^d,mom(1))
1801  }
1802  ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
1803  w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
1804  -half*(sum(w(ix^d,mom(1:ndir))**2)*w(ix^d,rho_)&
1805  +sum(w(ix^d,mag(1:ndir))**2)&
1806  +sum(b(1:3)**2)*inv_squared_c))
1807  end if
1808  {end do\}
1809 
1810  end subroutine mhd_to_primitive_semirelati
1811 
1812  !> Transform internal energy to total energy
1813  subroutine mhd_ei_to_e(ixI^L,ixO^L,w,x)
1815  integer, intent(in) :: ixi^l, ixo^l
1816  double precision, intent(inout) :: w(ixi^s, nw)
1817  double precision, intent(in) :: x(ixi^s, 1:ndim)
1818 
1819  ! Calculate total energy from internal, kinetic and magnetic energy
1820  w(ixi^s,e_)=w(ixi^s,e_)&
1821  +mhd_kin_en(w,ixi^l,ixi^l)&
1822  +mhd_mag_en(w,ixi^l,ixi^l)
1823 
1824  end subroutine mhd_ei_to_e
1825 
1826  !> Transform internal energy to hydrodynamic energy
1827  subroutine mhd_ei_to_e_hde(ixI^L,ixO^L,w,x)
1829  integer, intent(in) :: ixI^L, ixO^L
1830  double precision, intent(inout) :: w(ixI^S, nw)
1831  double precision, intent(in) :: x(ixI^S, 1:ndim)
1832 
1833  ! Calculate hydrodynamic energy from internal and kinetic
1834  w(ixi^s,e_)=w(ixi^s,e_)+mhd_kin_en(w,ixi^l,ixi^l)
1835 
1836  end subroutine mhd_ei_to_e_hde
1837 
1838  !> Transform internal energy to total energy and velocity to momentum
1839  subroutine mhd_ei_to_e_semirelati(ixI^L,ixO^L,w,x)
1841  integer, intent(in) :: ixI^L, ixO^L
1842  double precision, intent(inout) :: w(ixI^S, nw)
1843  double precision, intent(in) :: x(ixI^S, 1:ndim)
1844 
1845  w(ixi^s,p_)=w(ixi^s,e_)*gamma_1
1846  call mhd_to_conserved_semirelati(ixi^l,ixi^l,w,x)
1847 
1848  end subroutine mhd_ei_to_e_semirelati
1849 
1850  !> Transform total energy to internal energy
1851  subroutine mhd_e_to_ei(ixI^L,ixO^L,w,x)
1853  integer, intent(in) :: ixi^l, ixo^l
1854  double precision, intent(inout) :: w(ixi^s, nw)
1855  double precision, intent(in) :: x(ixi^s, 1:ndim)
1856 
1857  ! Calculate ei = e - ek - eb
1858  w(ixi^s,e_)=w(ixi^s,e_)&
1859  -mhd_kin_en(w,ixi^l,ixi^l)&
1860  -mhd_mag_en(w,ixi^l,ixi^l)
1861 
1862  if(fix_small_values) then
1863  call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei')
1864  end if
1865 
1866  end subroutine mhd_e_to_ei
1867 
1868  !> Transform hydrodynamic energy to internal energy
1869  subroutine mhd_e_to_ei_hde(ixI^L,ixO^L,w,x)
1871  integer, intent(in) :: ixI^L, ixO^L
1872  double precision, intent(inout) :: w(ixI^S, nw)
1873  double precision, intent(in) :: x(ixI^S, 1:ndim)
1874 
1875  ! Calculate ei = e - ek
1876  w(ixi^s,e_)=w(ixi^s,e_)-mhd_kin_en(w,ixi^l,ixi^l)
1877 
1878  if(fix_small_values) then
1879  call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei_hde')
1880  end if
1881 
1882  end subroutine mhd_e_to_ei_hde
1883 
1884  !> Transform total energy to internal energy and momentum to velocity
1885  subroutine mhd_e_to_ei_semirelati(ixI^L,ixO^L,w,x)
1887  integer, intent(in) :: ixI^L, ixO^L
1888  double precision, intent(inout) :: w(ixI^S, nw)
1889  double precision, intent(in) :: x(ixI^S, 1:ndim)
1890 
1891  call mhd_to_primitive_semirelati(ixi^l,ixi^l,w,x)
1892  w(ixi^s,e_)=w(ixi^s,p_)*inv_gamma_1
1893 
1894  end subroutine mhd_e_to_ei_semirelati
1895 
1896  subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixI^L, ixO^L, subname)
1898  use mod_small_values
1899  logical, intent(in) :: primitive
1900  integer, intent(in) :: ixI^L,ixO^L
1901  double precision, intent(inout) :: w(ixI^S,1:nw)
1902  double precision, intent(in) :: x(ixI^S,1:ndim)
1903  character(len=*), intent(in) :: subname
1904 
1905  double precision :: Ba(1:ndir), tmp, b2, gamma2, inv_rho
1906  double precision :: b(ixI^S,1:3), pressure(ixI^S), v(ixI^S,1:ndir)
1907  integer :: ix^D, idir
1908  logical :: flag(ixI^S,1:nw)
1909 
1910  flag=.false.
1911  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1912 
1913  if(mhd_energy) then
1914  if(primitive) then
1915  where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1916  else
1917  if(mhd_internal_e) then
1918  pressure(ixi^s)=gamma_1*w(ixi^s,e_)
1919  where(pressure(ixo^s) < small_pressure) flag(ixo^s,p_) = .true.
1920  else
1921  {do ix^db=iximin^db,iximax^db\}
1922  if(b0field) then
1923  ba(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i)
1924  else
1925  ba(1:ndir)=w(ix^d,mag(1:ndir))
1926  end if
1927  b2=sum(ba(1:ndir)**2)
1928  if(b2>smalldouble) then
1929  tmp=1.d0/sqrt(b2)
1930  else
1931  tmp=0.d0
1932  end if
1933  do idir=1,ndir
1934  b(ix^d,idir)=ba(idir)*tmp
1935  end do
1936  tmp=sum(b(ix^d,1:ndir)*w(ix^d,mom(1:ndir)))
1937 
1938  inv_rho=1.d0/w(ix^d,rho_)
1939  ! Va^2/c^2
1940  b2=b2*inv_rho*inv_squared_c
1941  ! equation (15)
1942  gamma2=1.d0/(1.d0+b2)
1943  ! Convert momentum to velocity
1944  do idir = 1, ndir
1945  v(ix^d,idir)=gamma2*(w(ix^d,mom(idir))+b2*b(ix^d,idir)*tmp)*inv_rho
1946  end do
1947 
1948  if(mhd_internal_e) then
1949  ! internal energy to pressure
1950  w(ix^d,p_)=gamma_1*w(ix^d,e_)
1951  else if(mhd_energy) then
1952  ! E=Bxv
1953  {^ifthreed
1954  b(ix^d,1)=ba(2)*v(ix^d,3)-ba(3)*v(ix^d,2)
1955  b(ix^d,2)=ba(3)*v(ix^d,1)-ba(1)*v(ix^d,3)
1956  b(ix^d,3)=ba(1)*v(ix^d,2)-ba(2)*v(ix^d,1)
1957  }
1958  {^nothreed
1959  if(ndir==3) then
1960  b(ix^d,1)=ba(2)*v(ix^d,3)-ba(3)*v(ix^d,2)
1961  b(ix^d,2)=ba(3)*v(ix^d,1)-ba(1)*v(ix^d,3)
1962  else
1963  b(ix^d,1:2)=zero
1964  end if
1965  b(ix^d,3)=ba(1)*v(ix^d,2)-ba(2)*v(ix^d,1)
1966  }
1967  ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
1968  pressure(ix^d)=gamma_1*(w(ix^d,e_)&
1969  -half*(sum(v(ix^d,1:ndir)**2)*w(ix^d,rho_)&
1970  +sum(w(ix^d,mag(1:ndir))**2)&
1971  +sum(b(ix^d,1:3)**2)*inv_squared_c))
1972  if(pressure(ix^d) < small_pressure) flag(ix^d,p_) = .true.
1973  end if
1974  {end do\}
1975  end if
1976  end if
1977  end if
1978 
1979  if(any(flag)) then
1980  select case (small_values_method)
1981  case ("replace")
1982  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
1983  do idir = 1, ndir
1984  if(small_values_fix_iw(mom(idir))) then
1985  where(flag(ixo^s,rho_)) w(ixo^s, mom(idir)) = 0.0d0
1986  end if
1987  end do
1988  if(mhd_energy) then
1989  if(primitive) then
1990  where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
1991  else
1992  if(mhd_internal_e) then
1993  ! internal energy
1994  {do ix^db=ixomin^db,ixomax^db\}
1995  if(flag(ix^d,e_)) then
1996  w(ix^d,e_)=small_pressure*inv_gamma_1
1997  end if
1998  {end do\}
1999  else
2000  {do ix^db=ixomin^db,ixomax^db\}
2001  if(flag(ix^d,e_)) then
2002  w(ix^d,e_)=small_pressure*inv_gamma_1+half*(sum(v(ix^d,1:ndir)**2)*w(ix^d,rho_)&
2003  +sum(w(ix^d,mag(1:ndir))**2)+sum(b(ix^d,1:3)**2)*inv_squared_c)
2004  end if
2005  {end do\}
2006  end if
2007  end if
2008  end if
2009  case ("average")
2010  ! do averaging of density
2011  call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2012  if(mhd_energy) then
2013  if(primitive) then
2014  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2015  else
2016  if(mhd_internal_e) then
2017  ! internal energy
2018  w(ixi^s,e_)=pressure(ixi^s)
2019  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2020  w(ixi^s,e_)=w(ixi^s,p_)*inv_gamma_1
2021  else
2022  w(ixi^s,e_)=pressure(ixi^s)
2023  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2024  {do ix^db=iximin^db,iximax^db\}
2025  w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1+half*(sum(v(ix^d,1:ndir)**2)*w(ix^d,rho_)&
2026  +sum(w(ix^d,mag(1:ndir))**2)+sum(b(ix^d,1:3)**2)*inv_squared_c)
2027  {end do\}
2028  end if
2029  end if
2030  end if
2031  case default
2032  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2033  end select
2034  end if
2035  end subroutine mhd_handle_small_values_semirelati
2036 
2037  subroutine mhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
2039  use mod_small_values
2040  logical, intent(in) :: primitive
2041  integer, intent(in) :: ixI^L,ixO^L
2042  double precision, intent(inout) :: w(ixI^S,1:nw)
2043  double precision, intent(in) :: x(ixI^S,1:ndim)
2044  character(len=*), intent(in) :: subname
2045 
2046  double precision :: tmp2(ixI^S)
2047  integer :: idir
2048  logical :: flag(ixI^S,1:nw)
2049 
2050  call phys_check_w(primitive, ixi^l, ixi^l, w, flag)
2051 
2052  if(any(flag)) then
2053  select case (small_values_method)
2054  case ("replace")
2055  if(has_equi_rho0) then
2056  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = &
2057  small_density-block%equi_vars(ixo^s,equi_rho0_,0)
2058  else
2059  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
2060  end if
2061  do idir = 1, ndir
2062  if(small_values_fix_iw(mom(idir))) then
2063  where(flag(ixo^s,rho_)) w(ixo^s, mom(idir)) = 0.0d0
2064  end if
2065  end do
2066  if(mhd_energy) then
2067  if(primitive) then
2068  if(has_equi_pe0) then
2069  tmp2(ixo^s) = small_pressure - &
2070  block%equi_vars(ixo^s,equi_pe0_,0)
2071  where(flag(ixo^s,e_)) w(ixo^s,p_) = tmp2(ixo^s)
2072  else
2073  where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
2074  end if
2075  else
2076  ! conserved
2077  if(has_equi_pe0) then
2078  tmp2(ixo^s) = small_e - &
2079  block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
2080  where(flag(ixo^s,e_))
2081  w(ixo^s,e_) = tmp2(ixo^s)+&
2082  mhd_kin_en(w,ixi^l,ixo^l)+&
2083  mhd_mag_en(w,ixi^l,ixo^l)
2084  end where
2085  else
2086  where(flag(ixo^s,e_))
2087  w(ixo^s,e_) = small_e+&
2088  mhd_kin_en(w,ixi^l,ixo^l)+&
2089  mhd_mag_en(w,ixi^l,ixo^l)
2090  end where
2091  end if
2092  end if
2093  end if
2094  case ("average")
2095  ! do averaging of density
2096  call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2097  if(mhd_energy) then
2098  if(primitive)then
2099  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2100  else
2101  ! do averaging of internal energy
2102  w(ixi^s,e_)=w(ixi^s,e_)&
2103  -mhd_kin_en(w,ixi^l,ixi^l)&
2104  -mhd_mag_en(w,ixi^l,ixi^l)
2105  call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2106  ! convert back
2107  w(ixi^s,e_)=w(ixi^s,e_)&
2108  +mhd_kin_en(w,ixi^l,ixi^l)&
2109  +mhd_mag_en(w,ixi^l,ixi^l)
2110  end if
2111  end if
2112  case default
2113  if(.not.primitive) then
2114  !convert w to primitive
2115  ! Calculate pressure = (gamma-1) * (e-ek-eb)
2116  if(mhd_energy) then
2117  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)&
2118  -mhd_kin_en(w,ixi^l,ixo^l)&
2119  -mhd_mag_en(w,ixi^l,ixo^l))
2120  end if
2121  ! Convert momentum to velocity
2122  if(has_equi_rho0) then
2123  tmp2(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,0)
2124  else
2125  tmp2(ixo^s) = w(ixo^s,rho_)
2126  end if
2127  do idir = 1, ndir
2128  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/tmp2(ixo^s)
2129  end do
2130  end if
2131  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2132  end select
2133  end if
2134 
2135  end subroutine mhd_handle_small_values_origin
2136 
2137  subroutine mhd_handle_small_values_inte(primitive, w, x, ixI^L, ixO^L, subname)
2139  use mod_small_values
2140  logical, intent(in) :: primitive
2141  integer, intent(in) :: ixI^L,ixO^L
2142  double precision, intent(inout) :: w(ixI^S,1:nw)
2143  double precision, intent(in) :: x(ixI^S,1:ndim)
2144  character(len=*), intent(in) :: subname
2145 
2146  double precision :: tmp2(ixI^S)
2147  integer :: idir
2148  logical :: flag(ixI^S,1:nw)
2149 
2150  call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2151 
2152  if(any(flag)) then
2153  select case (small_values_method)
2154  case ("replace")
2155  if(has_equi_rho0) then
2156  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = &
2157  small_density-block%equi_vars(ixo^s,equi_rho0_,0)
2158  else
2159  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
2160  end if
2161  do idir = 1, ndir
2162  if(small_values_fix_iw(mom(idir))) then
2163  where(flag(ixo^s,rho_)) w(ixo^s, mom(idir)) = 0.0d0
2164  end if
2165  end do
2166  if(mhd_energy) then
2167  if(primitive) then
2168  if(has_equi_pe0) then
2169  tmp2(ixo^s) = small_pressure - &
2170  block%equi_vars(ixo^s,equi_pe0_,0)
2171  where(flag(ixo^s,e_)) w(ixo^s,p_) = tmp2(ixo^s)
2172  else
2173  where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
2174  end if
2175  else
2176  ! conserved
2177  if(has_equi_pe0) then
2178  tmp2(ixo^s) = small_e - &
2179  block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
2180  where(flag(ixo^s,e_))
2181  w(ixo^s,e_)=tmp2(ixo^s)
2182  end where
2183  else
2184  where(flag(ixo^s,e_))
2185  w(ixo^s,e_)=small_e
2186  end where
2187  end if
2188  end if
2189  end if
2190  case ("average")
2191  ! do averaging of density
2192  call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2193  if(mhd_energy) then
2194  if(primitive)then
2195  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2196  else
2197  ! do averaging of internal energy
2198  call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2199  end if
2200  end if
2201  case default
2202  if(.not.primitive) then
2203  !convert w to primitive
2204  if(mhd_energy) then
2205  w(ixo^s,p_)=w(ixo^s,e_)*gamma_1
2206  end if
2207  ! Convert momentum to velocity
2208  if(has_equi_rho0) then
2209  tmp2(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,0)
2210  else
2211  tmp2(ixo^s) = w(ixo^s,rho_)
2212  end if
2213  do idir = 1, ndir
2214  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/tmp2(ixo^s)
2215  end do
2216  end if
2217  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2218  end select
2219  end if
2220 
2221  end subroutine mhd_handle_small_values_inte
2222 
2223  subroutine mhd_handle_small_values_hde(primitive, w, x, ixI^L, ixO^L, subname)
2225  use mod_small_values
2226  logical, intent(in) :: primitive
2227  integer, intent(in) :: ixI^L,ixO^L
2228  double precision, intent(inout) :: w(ixI^S,1:nw)
2229  double precision, intent(in) :: x(ixI^S,1:ndim)
2230  character(len=*), intent(in) :: subname
2231 
2232  double precision :: tmp2(ixI^S)
2233  integer :: idir
2234  logical :: flag(ixI^S,1:nw)
2235 
2236  call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2237 
2238  if(any(flag)) then
2239  select case (small_values_method)
2240  case ("replace")
2241  where(flag(ixo^s,rho_)) w(ixo^s,rho_) = small_density
2242  do idir = 1, ndir
2243  if(small_values_fix_iw(mom(idir))) then
2244  where(flag(ixo^s,rho_)) w(ixo^s, mom(idir)) = 0.0d0
2245  end if
2246  end do
2247 
2248  if(mhd_energy) then
2249  if(primitive) then
2250  where(flag(ixo^s,e_)) w(ixo^s,p_) = small_pressure
2251  else
2252  where(flag(ixo^s,e_))
2253  w(ixo^s,e_) = small_e+mhd_kin_en(w,ixi^l,ixo^l)
2254  end where
2255  end if
2256  end if
2257  case ("average")
2258  ! do averaging of density
2259  call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2260  if(mhd_energy) then
2261  if(primitive) then
2262  call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2263  else
2264  ! do averaging of internal energy
2265  w(ixi^s,e_)=w(ixi^s,e_)-mhd_kin_en(w,ixi^l,ixi^l)
2266  call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2267  ! convert back
2268  w(ixi^s,e_)=w(ixi^s,e_)+mhd_kin_en(w,ixi^l,ixi^l)
2269  end if
2270  end if
2271  case default
2272  if(.not.primitive) then
2273  !convert w to primitive
2274  ! Calculate pressure = (gamma-1) * (e-ek)
2275  if(mhd_energy) then
2276  w(ixo^s,p_)=gamma_1*(w(ixo^s,e_)-mhd_kin_en(w,ixi^l,ixo^l))
2277  end if
2278  ! Convert momentum to velocity
2279  do idir = 1, ndir
2280  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/w(ixo^s,rho_)
2281  end do
2282  end if
2283  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2284  end select
2285  end if
2286 
2287  end subroutine mhd_handle_small_values_hde
2288 
2289  !> Calculate v vector
2290  subroutine mhd_get_v_origin(w,x,ixI^L,ixO^L,v)
2292 
2293  integer, intent(in) :: ixI^L, ixO^L
2294  double precision, intent(in) :: w(ixI^S,nw), x(ixI^S,1:ndim)
2295  double precision, intent(out) :: v(ixI^S,ndir)
2296 
2297  double precision :: rho(ixI^S)
2298  integer :: idir
2299 
2300  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2301 
2302  rho(ixo^s)=1.d0/rho(ixo^s)
2303  ! Convert momentum to velocity
2304  do idir = 1, ndir
2305  v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
2306  end do
2307 
2308  end subroutine mhd_get_v_origin
2309 
2310  !> Calculate v component
2311  subroutine mhd_get_v_idim(w,x,ixI^L,ixO^L,idim,v)
2313 
2314  integer, intent(in) :: ixi^l, ixo^l, idim
2315  double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
2316  double precision, intent(out) :: v(ixo^s)
2317 
2318  double precision :: rho(ixi^s)
2319 
2320  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2321 
2322  v(ixo^s) = w(ixo^s, mom(idim)) / rho(ixo^s)
2323 
2324  end subroutine mhd_get_v_idim
2325 
2326  !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2327  subroutine mhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
2329 
2330  integer, intent(in) :: ixI^L, ixO^L, idim
2331  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2332  double precision, intent(inout) :: cmax(ixI^S)
2333  double precision :: vel(ixO^S)
2334 
2335  call mhd_get_csound(w,x,ixi^l,ixo^l,idim,cmax)
2336  call mhd_get_v_idim(w,x,ixi^l,ixo^l,idim,vel)
2337 
2338  cmax(ixo^s)=abs(vel(ixo^s))+cmax(ixo^s)
2339 
2340  end subroutine mhd_get_cmax_origin
2341 
2342  !> Calculate cmax_idim for semirelativistic MHD
2343  subroutine mhd_get_cmax_semirelati(w,x,ixI^L,ixO^L,idim,cmax)
2345 
2346  integer, intent(in) :: ixI^L, ixO^L, idim
2347  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2348  double precision, intent(inout):: cmax(ixI^S)
2349 
2350  double precision :: wprim(ixI^S,nw)
2351  double precision :: csound, AvMinCs2, idim_Alfven_speed2
2352  double precision :: inv_rho, Alfven_speed2, gamma2
2353  integer :: ix^D
2354 
2355  wprim=w
2356  call mhd_to_primitive(ixi^l,ixo^l,wprim,x)
2357  if(b0field) then
2358  {do ix^db=ixomin^db,ixomax^db \}
2359  inv_rho=1.d0/w(ix^d,rho_)
2360  alfven_speed2=sum((w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i))**2)*inv_rho
2361  gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2362  cmax(ix^d)=1.d0-gamma2*wprim(ix^d,mom(idim))**2*inv_squared_c
2363  ! squared sound speed
2364  if(mhd_energy) then
2365  csound=mhd_gamma*wprim(ix^d,p_)*inv_rho
2366  else
2367  csound=mhd_gamma*mhd_adiab*w(ix^d,rho_)**gamma_1
2368  end if
2369  idim_alfven_speed2=(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2370  ! Va_hat^2+a_hat^2 equation (57)
2371  ! equation (69)
2372  alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2373  avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2374  if(avmincs2<zero) avmincs2=zero
2375  ! equation (68) fast magnetosonic wave speed
2376  csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2377  cmax(ix^d)=gamma2*abs(wprim(ix^d,mom(idim)))+csound
2378  {end do\}
2379  else
2380  {do ix^db=ixomin^db,ixomax^db \}
2381  inv_rho=1.d0/w(ix^d,rho_)
2382  alfven_speed2=sum(w(ix^d,mag(1:ndir))**2)*inv_rho
2383  gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2384  cmax(ix^d)=1.d0-gamma2*wprim(ix^d,mom(idim))**2*inv_squared_c
2385  ! squared sound speed
2386  if(mhd_energy) then
2387  csound=mhd_gamma*wprim(ix^d,p_)*inv_rho
2388  else
2389  csound=mhd_gamma*mhd_adiab*w(ix^d,rho_)**gamma_1
2390  end if
2391  idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
2392  ! Va_hat^2+a_hat^2 equation (57)
2393  ! equation (69)
2394  alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2395  avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2396  if(avmincs2<zero) avmincs2=zero
2397  ! equation (68) fast magnetosonic wave speed
2398  csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2399  cmax(ix^d)=gamma2*abs(wprim(ix^d,mom(idim)))+csound
2400  {end do\}
2401  end if
2402 
2403  end subroutine mhd_get_cmax_semirelati
2404 
2405  subroutine mhd_get_a2max(w,x,ixI^L,ixO^L,a2max)
2407 
2408  integer, intent(in) :: ixI^L, ixO^L
2409  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2410  double precision, intent(inout) :: a2max(ndim)
2411  double precision :: a2(ixI^S,ndim,nw)
2412  integer :: gxO^L,hxO^L,jxO^L,kxO^L,i,j
2413 
2414  a2=zero
2415  do i = 1,ndim
2416  !> 4th order
2417  hxo^l=ixo^l-kr(i,^d);
2418  gxo^l=hxo^l-kr(i,^d);
2419  jxo^l=ixo^l+kr(i,^d);
2420  kxo^l=jxo^l+kr(i,^d);
2421  a2(ixo^s,i,1:nw)=abs(-w(kxo^s,1:nw)+16.d0*w(jxo^s,1:nw)&
2422  -30.d0*w(ixo^s,1:nw)+16.d0*w(hxo^s,1:nw)-w(gxo^s,1:nw))
2423  a2max(i)=maxval(a2(ixo^s,i,1:nw))/12.d0/dxlevel(i)**2
2424  end do
2425  end subroutine mhd_get_a2max
2426 
2427  !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
2428  subroutine mhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
2430  use mod_geometry
2431  integer, intent(in) :: ixI^L,ixO^L
2432  double precision, intent(in) :: x(ixI^S,1:ndim)
2433  double precision, intent(inout) :: w(ixI^S,1:nw)
2434  double precision, intent(out) :: Tco_local,Tmax_local
2435 
2436  double precision, parameter :: trac_delta=0.25d0
2437  double precision :: tmp1(ixI^S),Te(ixI^S),lts(ixI^S)
2438  double precision, dimension(ixI^S,1:ndir) :: bunitvec
2439  double precision, dimension(ixI^S,1:ndim) :: gradT
2440  double precision :: Bdir(ndim)
2441  double precision :: ltrc,ltrp,altr(ixI^S)
2442  integer :: idims,jxO^L,hxO^L,ixA^D,ixB^D
2443  integer :: jxP^L,hxP^L,ixP^L,ixQ^L
2444  logical :: lrlt(ixI^S)
2445 
2446  call mhd_get_temperature(w,x,ixi^l,ixi^l,te)
2447  tco_local=zero
2448  tmax_local=maxval(te(ixo^s))
2449 
2450  {^ifoned
2451  select case(mhd_trac_type)
2452  case(0)
2453  !> test case, fixed cutoff temperature
2454  block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
2455  case(1)
2456  hxo^l=ixo^l-1;
2457  jxo^l=ixo^l+1;
2458  lts(ixo^s)=0.5d0*abs(te(jxo^s)-te(hxo^s))/te(ixo^s)
2459  lrlt=.false.
2460  where(lts(ixo^s) > trac_delta)
2461  lrlt(ixo^s)=.true.
2462  end where
2463  if(any(lrlt(ixo^s))) then
2464  tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
2465  end if
2466  case(2)
2467  !> iijima et al. 2021, LTRAC method
2468  ltrc=1.5d0
2469  ltrp=4.d0
2470  ixp^l=ixo^l^ladd1;
2471  hxo^l=ixo^l-1;
2472  jxo^l=ixo^l+1;
2473  hxp^l=ixp^l-1;
2474  jxp^l=ixp^l+1;
2475  lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
2476  lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
2477  lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
2478  block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
2479  case default
2480  call mpistop("mhd_trac_type not allowed for 1D simulation")
2481  end select
2482  }
2483  {^nooned
2484  select case(mhd_trac_type)
2485  case(0)
2486  !> test case, fixed cutoff temperature
2487  block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
2488  case(1,4,6)
2489  ! temperature gradient at cell centers
2490  do idims=1,ndim
2491  call gradient(te,ixi^l,ixo^l,idims,tmp1)
2492  gradt(ixo^s,idims)=tmp1(ixo^s)
2493  end do
2494  ! B vector
2495  if(b0field) then
2496  bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))+block%B0(ixo^s,:,0)
2497  else
2498  bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))
2499  end if
2500  if(mhd_trac_type .gt. 1) then
2501  ! B direction at cell center
2502  bdir=zero
2503  {do ixa^d=0,1\}
2504  ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
2505  bdir(1:ndim)=bdir(1:ndim)+bunitvec(ixb^d,1:ndim)
2506  {end do\}
2507  if(sum(bdir(:)**2) .gt. zero) then
2508  bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
2509  end if
2510  block%special_values(3:ndim+2)=bdir(1:ndim)
2511  end if
2512  tmp1(ixo^s)=dsqrt(sum(bunitvec(ixo^s,:)**2,dim=ndim+1))
2513  where(tmp1(ixo^s)/=0.d0)
2514  tmp1(ixo^s)=1.d0/tmp1(ixo^s)
2515  elsewhere
2516  tmp1(ixo^s)=bigdouble
2517  end where
2518  ! b unit vector: magnetic field direction vector
2519  do idims=1,ndim
2520  bunitvec(ixo^s,idims)=bunitvec(ixo^s,idims)*tmp1(ixo^s)
2521  end do
2522  ! temperature length scale inversed
2523  lts(ixo^s)=abs(sum(gradt(ixo^s,1:ndim)*bunitvec(ixo^s,1:ndim),dim=ndim+1))/te(ixo^s)
2524  ! fraction of cells size to temperature length scale
2525  if(slab_uniform) then
2526  lts(ixo^s)=minval(dxlevel)*lts(ixo^s)
2527  else
2528  lts(ixo^s)=minval(block%ds(ixo^s,:),dim=ndim+1)*lts(ixo^s)
2529  end if
2530  lrlt=.false.
2531  where(lts(ixo^s) > trac_delta)
2532  lrlt(ixo^s)=.true.
2533  end where
2534  if(any(lrlt(ixo^s))) then
2535  block%special_values(1)=maxval(te(ixo^s), mask=lrlt(ixo^s))
2536  else
2537  block%special_values(1)=zero
2538  end if
2539  block%special_values(2)=tmax_local
2540  case(2)
2541  !> iijima et al. 2021, LTRAC method
2542  ltrc=1.5d0
2543  ltrp=4.d0
2544  ixp^l=ixo^l^ladd2;
2545  ! temperature gradient at cell centers
2546  do idims=1,ndim
2547  ixq^l=ixp^l;
2548  hxp^l=ixp^l;
2549  jxp^l=ixp^l;
2550  select case(idims)
2551  {case(^d)
2552  ixqmin^d=ixqmin^d+1
2553  ixqmax^d=ixqmax^d-1
2554  hxpmax^d=ixpmin^d
2555  jxpmin^d=ixpmax^d
2556  \}
2557  end select
2558  call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
2559  call gradientx(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),.false.)
2560  call gradientq(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims))
2561  end do
2562  ! B vector
2563  if(b0field) then
2564  bunitvec(ixp^s,:)=w(ixp^s,iw_mag(:))+block%B0(ixp^s,:,0)
2565  else
2566  bunitvec(ixp^s,:)=w(ixp^s,iw_mag(:))
2567  end if
2568  tmp1(ixp^s)=1.d0/(dsqrt(sum(bunitvec(ixp^s,:)**2,dim=ndim+1))+smalldouble)
2569  ! b unit vector: magnetic field direction vector
2570  do idims=1,ndim
2571  bunitvec(ixp^s,idims)=bunitvec(ixp^s,idims)*tmp1(ixp^s)
2572  end do
2573  ! temperature length scale inversed
2574  lts(ixp^s)=abs(sum(gradt(ixp^s,1:ndim)*bunitvec(ixp^s,1:ndim),dim=ndim+1))/te(ixp^s)
2575  ! fraction of cells size to temperature length scale
2576  if(slab_uniform) then
2577  lts(ixp^s)=minval(dxlevel)*lts(ixp^s)
2578  else
2579  lts(ixp^s)=minval(block%ds(ixp^s,:),dim=ndim+1)*lts(ixp^s)
2580  end if
2581  lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
2582 
2583  altr=zero
2584  ! need one ghost layer for thermal conductivity
2585  ixp^l=ixo^l^ladd1;
2586  do idims=1,ndim
2587  hxo^l=ixp^l-kr(idims,^d);
2588  jxo^l=ixp^l+kr(idims,^d);
2589  altr(ixp^s)=altr(ixp^s)+0.25d0*(lts(hxo^s)+two*lts(ixp^s)+lts(jxo^s))*bunitvec(ixp^s,idims)**2
2590  end do
2591  block%wextra(ixp^s,tcoff_)=te(ixp^s)*altr(ixp^s)**0.4d0
2592  case(3,5)
2593  !> do nothing here
2594  case default
2595  call mpistop("unknown mhd_trac_type")
2596  end select
2597  }
2598  end subroutine mhd_get_tcutoff
2599 
2600  !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
2601  subroutine mhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
2603 
2604  integer, intent(in) :: ixI^L, ixO^L, idim
2605  double precision, intent(in) :: wprim(ixI^S, nw)
2606  double precision, intent(in) :: x(ixI^S,1:ndim)
2607  double precision, intent(out) :: Hspeed(ixI^S,1:number_species)
2608 
2609  double precision :: csound(ixI^S,ndim)
2610  double precision, allocatable :: tmp(:^D&)
2611  integer :: jxC^L, ixC^L, ixA^L, id, ix^D
2612 
2613  hspeed=0.d0
2614  ixa^l=ixo^l^ladd1;
2615  allocate(tmp(ixa^s))
2616  do id=1,ndim
2617  call mhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
2618  csound(ixa^s,id)=tmp(ixa^s)
2619  end do
2620  ixcmax^d=ixomax^d;
2621  ixcmin^d=ixomin^d+kr(idim,^d)-1;
2622  jxcmax^d=ixcmax^d+kr(idim,^d);
2623  jxcmin^d=ixcmin^d+kr(idim,^d);
2624  hspeed(ixc^s,1)=0.5d0*abs(wprim(jxc^s,mom(idim))+csound(jxc^s,idim)-wprim(ixc^s,mom(idim))+csound(ixc^s,idim))
2625 
2626  do id=1,ndim
2627  if(id==idim) cycle
2628  ixamax^d=ixcmax^d+kr(id,^d);
2629  ixamin^d=ixcmin^d+kr(id,^d);
2630  hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixa^s,mom(id))+csound(ixa^s,id)-wprim(ixc^s,mom(id))+csound(ixc^s,id)))
2631  ixamax^d=ixcmax^d-kr(id,^d);
2632  ixamin^d=ixcmin^d-kr(id,^d);
2633  hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixc^s,mom(id))+csound(ixc^s,id)-wprim(ixa^s,mom(id))+csound(ixa^s,id)))
2634  end do
2635 
2636  do id=1,ndim
2637  if(id==idim) cycle
2638  ixamax^d=jxcmax^d+kr(id,^d);
2639  ixamin^d=jxcmin^d+kr(id,^d);
2640  hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixa^s,mom(id))+csound(ixa^s,id)-wprim(jxc^s,mom(id))+csound(jxc^s,id)))
2641  ixamax^d=jxcmax^d-kr(id,^d);
2642  ixamin^d=jxcmin^d-kr(id,^d);
2643  hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(jxc^s,mom(id))+csound(jxc^s,id)-wprim(ixa^s,mom(id))+csound(ixa^s,id)))
2644  end do
2645  deallocate(tmp)
2646 
2647  end subroutine mhd_get_h_speed
2648 
2649  !> Estimating bounds for the minimum and maximum signal velocities without split
2650  subroutine mhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
2652 
2653  integer, intent(in) :: ixI^L, ixO^L, idim
2654  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
2655  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
2656  double precision, intent(in) :: x(ixI^S,1:ndim)
2657  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
2658  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
2659  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
2660 
2661  double precision :: wmean(ixI^S,nw), csoundL(ixO^S), csoundR(ixO^S)
2662  double precision :: umean, dmean, tmp1, tmp2, tmp3
2663  integer :: ix^D
2664 
2665  select case (boundspeed)
2666  case (1)
2667  ! This implements formula (10.52) from "Riemann Solvers and Numerical
2668  ! Methods for Fluid Dynamics" by Toro.
2669  call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2670  call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2671  if(present(cmin)) then
2672  {do ix^db=ixomin^db,ixomax^db\}
2673  tmp1=sqrt(wlp(ix^d,rho_))
2674  tmp2=sqrt(wrp(ix^d,rho_))
2675  tmp3=1.d0/(tmp1+tmp2)
2676  umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
2677  dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
2678  half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
2679  cmin(ix^d,1)=umean-dmean
2680  cmax(ix^d,1)=umean+dmean
2681  {end do\}
2682  if(h_correction) then
2683  {do ix^db=ixomin^db,ixomax^db\}
2684  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2685  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2686  {end do\}
2687  end if
2688  else
2689  {do ix^db=ixomin^db,ixomax^db\}
2690  tmp1=sqrt(wlp(ix^d,rho_))
2691  tmp2=sqrt(wrp(ix^d,rho_))
2692  tmp3=1.d0/(tmp1+tmp2)
2693  umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
2694  dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
2695  half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
2696  cmax(ix^d,1)=abs(umean)+dmean
2697  {end do\}
2698  end if
2699  case (2)
2700  wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
2701  call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
2702  if(present(cmin)) then
2703  {do ix^db=ixomin^db,ixomax^db\}
2704  cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
2705  cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
2706  {end do\}
2707  if(h_correction) then
2708  {do ix^db=ixomin^db,ixomax^db\}
2709  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2710  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2711  {end do\}
2712  end if
2713  else
2714  cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
2715  end if
2716  case (3)
2717  ! Miyoshi 2005 JCP 208, 315 equation (67)
2718  call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2719  call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2720  if(present(cmin)) then
2721  {do ix^db=ixomin^db,ixomax^db\}
2722  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2723  cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
2724  cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
2725  {end do\}
2726  if(h_correction) then
2727  {do ix^db=ixomin^db,ixomax^db\}
2728  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2729  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2730  {end do\}
2731  end if
2732  else
2733  {do ix^db=ixomin^db,ixomax^db\}
2734  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2735  cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
2736  {end do\}
2737  end if
2738  end select
2739 
2740  end subroutine mhd_get_cbounds
2741 
2742  !> Estimating bounds for the minimum and maximum signal velocities without split
2743  subroutine mhd_get_cbounds_semirelati(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
2745 
2746  integer, intent(in) :: ixI^L, ixO^L, idim
2747  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
2748  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
2749  double precision, intent(in) :: x(ixI^S,1:ndim)
2750  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
2751  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
2752  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
2753 
2754  double precision, dimension(ixO^S) :: csoundL, csoundR, gamma2L, gamma2R
2755  integer :: ix^D
2756 
2757  ! Miyoshi 2005 JCP 208, 315 equation (67)
2758  call mhd_get_csound_semirelati(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
2759  call mhd_get_csound_semirelati(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
2760  if(present(cmin)) then
2761  {do ix^db=ixomin^db,ixomax^db\}
2762  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2763  cmin(ix^d,1)=min(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))-csoundl(ix^d)
2764  cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
2765  {end do\}
2766  else
2767  {do ix^db=ixomin^db,ixomax^db\}
2768  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2769  cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
2770  {end do\}
2771  end if
2772 
2773  end subroutine mhd_get_cbounds_semirelati
2774 
2775  !> Estimating bounds for the minimum and maximum signal velocities with rho split
2776  subroutine mhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
2778 
2779  integer, intent(in) :: ixI^L, ixO^L, idim
2780  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
2781  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
2782  double precision, intent(in) :: x(ixI^S,1:ndim)
2783  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
2784  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
2785  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
2786 
2787  double precision :: wmean(ixI^S,nw), csoundL(ixO^S), csoundR(ixO^S)
2788  double precision :: umean, dmean, tmp1, tmp2, tmp3
2789  integer :: ix^D
2790 
2791  select case (boundspeed)
2792  case (1)
2793  ! This implements formula (10.52) from "Riemann Solvers and Numerical
2794  ! Methods for Fluid Dynamics" by Toro.
2795  call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2796  call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2797  if(present(cmin)) then
2798  {do ix^db=ixomin^db,ixomax^db\}
2799  tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2800  tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2801  tmp3=1.d0/(tmp1+tmp2)
2802  umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
2803  dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
2804  half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
2805  cmin(ix^d,1)=umean-dmean
2806  cmax(ix^d,1)=umean+dmean
2807  {end do\}
2808  if(h_correction) then
2809  {do ix^db=ixomin^db,ixomax^db\}
2810  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2811  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2812  {end do\}
2813  end if
2814  else
2815  {do ix^db=ixomin^db,ixomax^db\}
2816  tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2817  tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2818  tmp3=1.d0/(tmp1+tmp2)
2819  umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
2820  dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
2821  half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
2822  cmax(ix^d,1)=abs(umean)+dmean
2823  {end do\}
2824  end if
2825  case (2)
2826  wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
2827  call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
2828  if(present(cmin)) then
2829  {do ix^db=ixomin^db,ixomax^db\}
2830  cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
2831  cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
2832  {end do\}
2833  if(h_correction) then
2834  {do ix^db=ixomin^db,ixomax^db\}
2835  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2836  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2837  {end do\}
2838  end if
2839  else
2840  cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
2841  end if
2842  case (3)
2843  ! Miyoshi 2005 JCP 208, 315 equation (67)
2844  call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2845  call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2846  if(present(cmin)) then
2847  {do ix^db=ixomin^db,ixomax^db\}
2848  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2849  cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
2850  cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
2851  {end do\}
2852  if(h_correction) then
2853  {do ix^db=ixomin^db,ixomax^db\}
2854  cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2855  cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2856  {end do\}
2857  end if
2858  else
2859  {do ix^db=ixomin^db,ixomax^db\}
2860  csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
2861  cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
2862  {end do\}
2863  end if
2864  end select
2865 
2866  end subroutine mhd_get_cbounds_split_rho
2867 
2868  !> prepare velocities for ct methods
2869  subroutine mhd_get_ct_velocity(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
2871 
2872  integer, intent(in) :: ixI^L, ixO^L, idim
2873  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
2874  double precision, intent(in) :: cmax(ixI^S)
2875  double precision, intent(in), optional :: cmin(ixI^S)
2876  type(ct_velocity), intent(inout):: vcts
2877 
2878  integer :: idimE,idimN
2879 
2880  ! calculate velocities related to different UCT schemes
2881  select case(type_ct)
2882  case('average')
2883  case('uct_contact')
2884  if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
2885  ! get average normal velocity at cell faces
2886  vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
2887  case('uct_hll')
2888  if(.not.allocated(vcts%vbarC)) then
2889  allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
2890  allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
2891  end if
2892  ! Store magnitude of characteristics
2893  if(present(cmin)) then
2894  vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
2895  vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
2896  else
2897  vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
2898  vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
2899  end if
2900 
2901  idimn=mod(idim,ndir)+1 ! 'Next' direction
2902  idime=mod(idim+1,ndir)+1 ! Electric field direction
2903  ! Store velocities
2904  vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
2905  vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
2906  vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
2907  +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
2908  /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
2909 
2910  vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
2911  vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
2912  vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
2913  +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
2914  /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
2915  case default
2916  call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
2917  end select
2918 
2919  end subroutine mhd_get_ct_velocity
2920 
2921  !> Calculate fast magnetosonic wave speed
2922  subroutine mhd_get_csound(w,x,ixI^L,ixO^L,idim,csound)
2924 
2925  integer, intent(in) :: ixI^L, ixO^L, idim
2926  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2927  double precision, intent(out):: csound(ixI^S)
2928 
2929  double precision :: inv_rho, cfast2, AvMinCs2, b2, kmax
2930  double precision :: rho(ixO^S)
2931  integer :: ix^D
2932 
2933  if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2934  if(has_equi_rho0) then
2935  rho(ixo^s) = (w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i))
2936  else
2937  rho(ixo^s) = w(ixo^s,rho_)
2938  end if
2939 
2940  if(mhd_energy) then
2941  call mhd_get_pthermal(w,x,ixi^l,ixo^l,csound)
2942  csound(ixo^s)=mhd_gamma*csound(ixo^s)/rho(ixo^s)
2943  else
2944  csound(ixo^s)=mhd_gamma*mhd_adiab*rho(ixo^s)**gamma_1
2945  end if
2946 
2947  if(b0field) then
2948  {do ix^db=ixomin^db,ixomax^db \}
2949  inv_rho=1.d0/rho(ix^d)
2950  ! store |B|^2 in v
2951  b2=sum((w(ix^d, mag(:))+block%B0(ix^d,:,b0i))**2)
2952  cfast2=b2*inv_rho+csound(ix^d)
2953  avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2954  if(avmincs2<zero) avmincs2=zero
2955  csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2956  if(mhd_hall) then
2957  ! take the Hall velocity into account: most simple estimate, high k limit:
2958  ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2959  csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2960  end if
2961  {end do\}
2962  else
2963  {do ix^db=ixomin^db,ixomax^db \}
2964  inv_rho=1.d0/rho(ix^d)
2965  ! store |B|^2 in v
2966  b2=sum(w(ix^d, mag(1:ndir))**2)
2967  cfast2=b2*inv_rho+csound(ix^d)
2968  avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2969  if(avmincs2<zero) avmincs2=zero
2970  csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2971  if(mhd_hall) then
2972  ! take the Hall velocity into account: most simple estimate, high k limit:
2973  ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2974  csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2975  end if
2976  {end do\}
2977  end if
2978 
2979  end subroutine mhd_get_csound
2980 
2981  !> Calculate fast magnetosonic wave speed
2982  subroutine mhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
2984 
2985  integer, intent(in) :: ixI^L, ixO^L, idim
2986  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2987  double precision, intent(out):: csound(ixO^S)
2988 
2989  double precision :: inv_rho, cfast2, AvMinCs2, b2, kmax
2990  double precision :: rho(ixO^S)
2991  integer :: ix^D
2992 
2993  if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2994  if(has_equi_rho0) then
2995  rho(ixo^s) = (w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i))
2996  else
2997  rho(ixo^s) = w(ixo^s,rho_)
2998  end if
2999 
3000  if(mhd_energy) then
3001  if(has_equi_pe0) then
3002  csound(ixo^s)=mhd_gamma*(w(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,b0i))/rho(ixo^s)
3003  else
3004  csound(ixo^s)=mhd_gamma*w(ixo^s,e_)/rho(ixo^s)
3005  endif
3006  else
3007  csound(ixo^s)=mhd_gamma*mhd_adiab*rho(ixo^s)**gamma_1
3008  end if
3009 
3010  ! store |B|^2 in v
3011  if(b0field) then
3012  {do ix^db=ixomin^db,ixomax^db \}
3013  inv_rho=1.d0/rho(ix^d)
3014  b2=sum((w(ix^d, mag(1:ndir))+block%B0(ix^d,1:ndir,b0i))**2)
3015  cfast2=b2*inv_rho+csound(ix^d)
3016  avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3017  block%B0(ix^d,idim,b0i))**2*inv_rho
3018  if(avmincs2<zero) avmincs2=zero
3019  csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3020  if(mhd_hall) then
3021  csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3022  end if
3023  {end do\}
3024  else
3025  {do ix^db=ixomin^db,ixomax^db \}
3026  inv_rho=1.d0/rho(ix^d)
3027  b2=sum(w(ix^d, mag(1:ndir))**2)
3028  cfast2=b2*inv_rho+csound(ix^d)
3029  avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3030  if(avmincs2<zero) avmincs2=zero
3031  csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3032  if(mhd_hall) then
3033  csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3034  end if
3035  {end do\}
3036  end if
3037 
3038  end subroutine mhd_get_csound_prim
3039 
3040  !> Calculate cmax_idim for semirelativistic MHD
3041  subroutine mhd_get_csound_semirelati(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3043 
3044  integer, intent(in) :: ixI^L, ixO^L, idim
3045  ! here w is primitive variables
3046  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
3047  double precision, intent(out):: csound(ixO^S), gamma2(ixO^S)
3048 
3049  double precision :: AvMinCs2, kmax, inv_rho, Alfven_speed2, idim_Alfven_speed2
3050  double precision :: B(ixO^S,1:ndir)
3051  integer :: ix^D
3052 
3053  if(b0field) then
3054  {do ix^db=ixomin^db,ixomax^db\}
3055  inv_rho = 1.d0/w(ix^d,rho_)
3056  ! squared sound speed
3057  if(mhd_energy) then
3058  csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3059  else
3060  csound(ix^d)=mhd_gamma*mhd_adiab*w(ix^d,rho_)**gamma_1
3061  end if
3062  alfven_speed2=sum((w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,b0i))**2)*inv_rho
3063  gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3064  avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3065  idim_alfven_speed2=(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
3066  ! Va_hat^2+a_hat^2 equation (57)
3067  ! equation (69)
3068  alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3069  avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3070  if(avmincs2<zero) avmincs2=zero
3071  ! equation (68) fast magnetosonic speed
3072  csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3073  {end do\}
3074  else
3075  {do ix^db=ixomin^db,ixomax^db\}
3076  inv_rho = 1.d0/w(ix^d,rho_)
3077  ! squared sound speed
3078  if(mhd_energy) then
3079  csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3080  else
3081  csound(ix^d)=mhd_gamma*mhd_adiab*w(ix^d,rho_)**gamma_1
3082  end if
3083  alfven_speed2=sum(w(ix^d,mag(:))**2)*inv_rho
3084  gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3085  avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3086  idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3087  ! Va_hat^2+a_hat^2 equation (57)
3088  ! equation (69)
3089  alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3090  avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3091  if(avmincs2<zero) avmincs2=zero
3092  ! equation (68) fast magnetosonic speed
3093  csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3094  {end do\}
3095  end if
3096 
3097  end subroutine mhd_get_csound_semirelati
3098 
3099  !> Calculate isothermal thermal pressure
3100  subroutine mhd_get_pthermal_iso(w,x,ixI^L,ixO^L,pth)
3102 
3103  integer, intent(in) :: ixI^L, ixO^L
3104  double precision, intent(in) :: w(ixI^S,nw)
3105  double precision, intent(in) :: x(ixI^S,1:ndim)
3106  double precision, intent(out):: pth(ixI^S)
3107 
3108  call mhd_get_rho(w,x,ixi^l,ixo^l,pth)
3109  pth(ixo^s)=mhd_adiab*pth(ixo^s)**mhd_gamma
3110 
3111  end subroutine mhd_get_pthermal_iso
3112 
3113  !> Calculate thermal pressure from internal energy
3114  subroutine mhd_get_pthermal_eint(w,x,ixI^L,ixO^L,pth)
3117 
3118  integer, intent(in) :: ixI^L, ixO^L
3119  double precision, intent(in) :: w(ixI^S,nw)
3120  double precision, intent(in) :: x(ixI^S,1:ndim)
3121  double precision, intent(out):: pth(ixI^S)
3122  integer :: iw, ix^D
3123 
3124  pth(ixo^s)=gamma_1*w(ixo^s,e_)
3125 
3126  if(has_equi_pe0) then
3127  pth(ixo^s) = pth(ixo^s) + block%equi_vars(ixo^s,equi_pe0_,b0i)
3128  end if
3129 
3130  if (fix_small_values) then
3131  {do ix^db= ixo^lim^db\}
3132  if(pth(ix^d)<small_pressure) then
3133  pth(ix^d)=small_pressure
3134  end if
3135  {enddo^d&\}
3136  else if (check_small_values) then
3137  {do ix^db= ixo^lim^db\}
3138  if(pth(ix^d)<small_pressure) then
3139  write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3140  " encountered when call mhd_get_pthermal"
3141  write(*,*) "Iteration: ", it, " Time: ", global_time
3142  write(*,*) "Location: ", x(ix^d,:)
3143  write(*,*) "Cell number: ", ix^d
3144  do iw=1,nw
3145  write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3146  end do
3147  ! use erroneous arithmetic operation to crash the run
3148  if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3149  write(*,*) "Saving status at the previous time step"
3150  crash=.true.
3151  end if
3152  {enddo^d&\}
3153  end if
3154 
3155  end subroutine mhd_get_pthermal_eint
3156 
3157  !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L
3158  subroutine mhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
3161 
3162  integer, intent(in) :: ixI^L, ixO^L
3163  double precision, intent(in) :: w(ixI^S,nw)
3164  double precision, intent(in) :: x(ixI^S,1:ndim)
3165  double precision, intent(out):: pth(ixI^S)
3166  integer :: iw, ix^D
3167 
3168  pth(ixo^s)=gamma_1*(w(ixo^s,e_)&
3169  - mhd_kin_en(w,ixi^l,ixo^l)&
3170  - mhd_mag_en(w,ixi^l,ixo^l))
3171 
3172  if(has_equi_pe0) then
3173  pth(ixo^s) = pth(ixo^s) + block%equi_vars(ixo^s,equi_pe0_,b0i)
3174  end if
3175 
3176  if (fix_small_values) then
3177  {do ix^db= ixo^lim^db\}
3178  if(pth(ix^d)<small_pressure) then
3179  pth(ix^d)=small_pressure
3180  end if
3181  {enddo^d&\}
3182  else if (check_small_values) then
3183  {do ix^db= ixo^lim^db\}
3184  if(pth(ix^d)<small_pressure) then
3185  write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3186  " encountered when call mhd_get_pthermal"
3187  write(*,*) "Iteration: ", it, " Time: ", global_time
3188  write(*,*) "Location: ", x(ix^d,:)
3189  write(*,*) "Cell number: ", ix^d
3190  do iw=1,nw
3191  write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3192  end do
3193  ! use erroneous arithmetic operation to crash the run
3194  if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3195  write(*,*) "Saving status at the previous time step"
3196  crash=.true.
3197  end if
3198  {enddo^d&\}
3199  end if
3200 
3201  end subroutine mhd_get_pthermal_origin
3202 
3203  !> Calculate thermal pressure
3204  subroutine mhd_get_pthermal_semirelati(w,x,ixI^L,ixO^L,pth)
3207 
3208  integer, intent(in) :: ixI^L, ixO^L
3209  double precision, intent(in) :: w(ixI^S,nw)
3210  double precision, intent(in) :: x(ixI^S,1:ndim)
3211  double precision, intent(out):: pth(ixI^S)
3212  integer :: iw, ix^D
3213 
3214  double precision :: wprim(ixI^S,nw)
3215 
3216  wprim=w
3217  call mhd_to_primitive_semirelati(ixi^l,ixo^l,wprim,x)
3218  pth(ixo^s)=wprim(ixo^s,p_)
3219 
3220  if (.not.fix_small_values .and. check_small_values) then
3221  {do ix^db= ixo^lim^db\}
3222  if(pth(ix^d)<small_pressure) then
3223  write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3224  " encountered when call mhd_get_pthermal_semirelati"
3225  write(*,*) "Iteration: ", it, " Time: ", global_time
3226  write(*,*) "Location: ", x(ix^d,:)
3227  write(*,*) "Cell number: ", ix^d
3228  do iw=1,nw
3229  write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3230  end do
3231  ! use erroneous arithmetic operation to crash the run
3232  if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3233  write(*,*) "Saving status at the previous time step"
3234  crash=.true.
3235  end if
3236  {enddo^d&\}
3237  end if
3238 
3239  end subroutine mhd_get_pthermal_semirelati
3240 
3241  !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho) within ixO^L
3242  subroutine mhd_get_pthermal_hde(w,x,ixI^L,ixO^L,pth)
3245 
3246  integer, intent(in) :: ixI^L, ixO^L
3247  double precision, intent(in) :: w(ixI^S,nw)
3248  double precision, intent(in) :: x(ixI^S,1:ndim)
3249  double precision, intent(out):: pth(ixI^S)
3250  integer :: iw, ix^D
3251 
3252  pth(ixo^s)=gamma_1*(w(ixo^s,e_)-mhd_kin_en(w,ixi^l,ixo^l))
3253 
3254  if (fix_small_values) then
3255  {do ix^db= ixo^lim^db\}
3256  if(pth(ix^d)<small_pressure) then
3257  pth(ix^d)=small_pressure
3258  end if
3259  {enddo^d&\}
3260  else if (check_small_values) then
3261  {do ix^db= ixo^lim^db\}
3262  if(pth(ix^d)<small_pressure) then
3263  write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3264  " encountered when call mhd_get_pthermal_hde"
3265  write(*,*) "Iteration: ", it, " Time: ", global_time
3266  write(*,*) "Location: ", x(ix^d,:)
3267  write(*,*) "Cell number: ", ix^d
3268  do iw=1,nw
3269  write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3270  end do
3271  ! use erroneous arithmetic operation to crash the run
3272  if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3273  write(*,*) "Saving status at the previous time step"
3274  crash=.true.
3275  end if
3276  {enddo^d&\}
3277  end if
3278 
3279  end subroutine mhd_get_pthermal_hde
3280 
3281  !> copy temperature from stored Te variable
3282  subroutine mhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
3284  integer, intent(in) :: ixI^L, ixO^L
3285  double precision, intent(in) :: w(ixI^S, 1:nw)
3286  double precision, intent(in) :: x(ixI^S, 1:ndim)
3287  double precision, intent(out):: res(ixI^S)
3288  res(ixo^s) = w(ixo^s, te_)
3289  end subroutine mhd_get_temperature_from_te
3290 
3291  !> Calculate temperature=p/rho when in e_ the internal energy is stored
3292  subroutine mhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
3294  integer, intent(in) :: ixI^L, ixO^L
3295  double precision, intent(in) :: w(ixI^S, 1:nw)
3296  double precision, intent(in) :: x(ixI^S, 1:ndim)
3297  double precision, intent(out):: res(ixI^S)
3298 
3299  double precision :: R(ixI^S)
3300 
3301  call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
3302  res(ixo^s) = gamma_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
3303  end subroutine mhd_get_temperature_from_eint
3304 
3305  !> Calculate temperature=p/rho when in e_ the total energy is stored
3306  subroutine mhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
3308  integer, intent(in) :: ixI^L, ixO^L
3309  double precision, intent(in) :: w(ixI^S, 1:nw)
3310  double precision, intent(in) :: x(ixI^S, 1:ndim)
3311  double precision, intent(out):: res(ixI^S)
3312 
3313  double precision :: R(ixI^S)
3314 
3315  call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
3316  call mhd_get_pthermal(w,x,ixi^l,ixo^l,res)
3317  res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
3318 
3319  end subroutine mhd_get_temperature_from_etot
3320 
3321  subroutine mhd_get_temperature_from_etot_with_equi(w, x, ixI^L, ixO^L, res)
3323  integer, intent(in) :: ixI^L, ixO^L
3324  double precision, intent(in) :: w(ixI^S, 1:nw)
3325  double precision, intent(in) :: x(ixI^S, 1:ndim)
3326  double precision, intent(out):: res(ixI^S)
3327 
3328  double precision :: R(ixI^S)
3329 
3330  call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
3331  call mhd_get_pthermal(w,x,ixi^l,ixo^l,res)
3332  res(ixo^s)=res(ixo^s)/(r(ixo^s)*(w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,b0i)))
3333 
3335 
3336  subroutine mhd_get_temperature_from_eint_with_equi(w, x, ixI^L, ixO^L, res)
3338  integer, intent(in) :: ixI^L, ixO^L
3339  double precision, intent(in) :: w(ixI^S, 1:nw)
3340  double precision, intent(in) :: x(ixI^S, 1:ndim)
3341  double precision, intent(out):: res(ixI^S)
3342 
3343  double precision :: R(ixI^S)
3344 
3345  call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
3346  res(ixo^s) = (gamma_1 * w(ixo^s, e_) + block%equi_vars(ixo^s,equi_pe0_,b0i)) /&
3347  ((w(ixo^s,rho_) +block%equi_vars(ixo^s,equi_rho0_,b0i))*r(ixo^s))
3348 
3350 
3351  subroutine mhd_get_temperature_equi(w,x, ixI^L, ixO^L, res)
3353  integer, intent(in) :: ixI^L, ixO^L
3354  double precision, intent(in) :: w(ixI^S, 1:nw)
3355  double precision, intent(in) :: x(ixI^S, 1:ndim)
3356  double precision, intent(out):: res(ixI^S)
3357 
3358  double precision :: R(ixI^S)
3359 
3360  call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
3361  res(ixo^s)= block%equi_vars(ixo^s,equi_pe0_,b0i)/(block%equi_vars(ixo^s,equi_rho0_,b0i)*r(ixo^s))
3362 
3363  end subroutine mhd_get_temperature_equi
3364 
3365  subroutine mhd_get_rho_equi(w, x, ixI^L, ixO^L, res)
3367  integer, intent(in) :: ixI^L, ixO^L
3368  double precision, intent(in) :: w(ixI^S, 1:nw)
3369  double precision, intent(in) :: x(ixI^S, 1:ndim)
3370  double precision, intent(out):: res(ixI^S)
3371  res(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i)
3372  end subroutine mhd_get_rho_equi
3373 
3374  subroutine mhd_get_pe_equi(w,x, ixI^L, ixO^L, res)
3376  integer, intent(in) :: ixI^L, ixO^L
3377  double precision, intent(in) :: w(ixI^S, 1:nw)
3378  double precision, intent(in) :: x(ixI^S, 1:ndim)
3379  double precision, intent(out):: res(ixI^S)
3380  res(ixo^s) = block%equi_vars(ixo^s,equi_pe0_,b0i)
3381  end subroutine mhd_get_pe_equi
3382 
3383  !> Calculate the square of the thermal sound speed csound2 within ixO^L.
3384  !> csound2=gamma*p/rho
3385  subroutine mhd_get_csound2(w,x,ixI^L,ixO^L,csound2)
3387  integer, intent(in) :: ixi^l, ixo^l
3388  double precision, intent(in) :: w(ixi^s,nw)
3389  double precision, intent(in) :: x(ixi^s,1:ndim)
3390  double precision, intent(out) :: csound2(ixi^s)
3391  double precision :: rho(ixi^s)
3392 
3393  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
3394  if(mhd_energy) then
3395  call mhd_get_pthermal(w,x,ixi^l,ixo^l,csound2)
3396  csound2(ixo^s)=mhd_gamma*csound2(ixo^s)/rho(ixo^s)
3397  else
3398  csound2(ixo^s)=mhd_gamma*mhd_adiab*rho(ixo^s)**gamma_1
3399  end if
3400  end subroutine mhd_get_csound2
3401 
3402  !> Calculate total pressure within ixO^L including magnetic pressure
3403  subroutine mhd_get_p_total(w,x,ixI^L,ixO^L,p)
3405 
3406  integer, intent(in) :: ixI^L, ixO^L
3407  double precision, intent(in) :: w(ixI^S,nw)
3408  double precision, intent(in) :: x(ixI^S,1:ndim)
3409  double precision, intent(out) :: p(ixI^S)
3410 
3411  call mhd_get_pthermal(w,x,ixi^l,ixo^l,p)
3412 
3413  p(ixo^s) = p(ixo^s) + 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
3414 
3415  end subroutine mhd_get_p_total
3416 
3417  !> Calculate fluxes within ixO^L without any splitting
3418  subroutine mhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
3420  use mod_geometry
3421 
3422  integer, intent(in) :: ixI^L, ixO^L, idim
3423  ! conservative w
3424  double precision, intent(in) :: wC(ixI^S,nw)
3425  ! primitive w
3426  double precision, intent(in) :: w(ixI^S,nw)
3427  double precision, intent(in) :: x(ixI^S,1:ndim)
3428  double precision,intent(out) :: f(ixI^S,nwflux)
3429 
3430  double precision :: vHall(ixI^S,1:ndir)
3431  double precision :: ptotal
3432  integer :: idir, ix^D
3433 
3434  if (mhd_hall) then
3435  call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3436  end if
3437 
3438  {do ix^db=ixomin^db,ixomax^db\}
3439  ! Get flux of density
3440  f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3441 
3442  if(mhd_energy) then
3443  ptotal=w(ix^d,p_)+half*sum(w(ix^d,mag(1:ndir))**2)
3444  else
3445  ptotal=mhd_adiab*w(ix^d,rho_)**mhd_gamma+half*sum(w(ix^d,mag(1:ndir))**2)
3446  end if
3447 
3448  f(ix^d,mom(1:ndir))=0.d0
3449  f(ix^d,mom(idim))=ptotal
3450  ! Get flux of momentum and magnetic field
3451  do idir=1,ndir
3452  ! f_i[m_k]=v_i*m_k-b_k*b_i
3453  f(ix^d,mom(idir))=f(ix^d,mom(idir))+wc(ix^d,mom(idim))*w(ix^d,mom(idir))-w(ix^d,mag(idim))*w(ix^d,mag(idir))
3454  ! f_i[b_k]=v_i*b_k-v_k*b_i
3455  f(ix^d,mag(idir))=w(ix^d,mom(idim))*w(ix^d,mag(idir))-w(ix^d,mag(idim))*w(ix^d,mom(idir))
3456  if (mhd_hall) then
3457  ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3458  f(ix^d,mag(idir)) = f(ix^d,mag(idir)) &
3459  + vhall(ix^d,idim)*w(ix^d,mag(idir)) &
3460  - vhall(ix^d,idir)*w(ix^d,mag(idim))
3461  end if
3462  end do
3463  if(mhd_glm) then
3464  f(ix^d,mag(idim))=w(ix^d,psi_)
3465  !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3466  f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3467  end if
3468 
3469  ! Get flux of energy
3470  ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
3471  if(mhd_energy) then
3472  if(mhd_internal_e) then
3473  f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
3474  else
3475  f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
3476  -w(ix^d,mag(idim))*sum(w(ix^d,mag(1:ndir))*w(ix^d,mom(1:ndir)))
3477  if(mhd_hall) then
3478  ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
3479  f(ix^d,e_) = f(ix^d,e_) + vhall(ix^d,idim) * &
3480  sum(w(ix^d, mag(1:ndir))**2) &
3481  - w(ix^d,mag(idim)) * sum(vhall(ix^d,1:ndir)*w(ix^d,mag(1:ndir)))
3482  end if
3483  end if
3484  end if
3485 
3487  f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(sum(w(ix^d,mag(1:ndim))**2))+smalldouble)
3488  f(ix^d,q_)=zero
3489  end if
3490 
3491  ! Get flux of tracer
3492  do idir=1,mhd_n_tracer
3493  f(ix^d,tracer(idir))=w(ix^d,mom(idim))*w(ix^d,tracer(idir))
3494  end do
3495  {end do\}
3496 
3497  end subroutine mhd_get_flux
3498 
3499  !> Calculate fluxes with hydrodynamic energy equation
3500  subroutine mhd_get_flux_hde(wC,w,x,ixI^L,ixO^L,idim,f)
3502  use mod_geometry
3503 
3504  integer, intent(in) :: ixI^L, ixO^L, idim
3505  ! conservative w
3506  double precision, intent(in) :: wC(ixI^S,nw)
3507  ! primitive w
3508  double precision, intent(in) :: w(ixI^S,nw)
3509  double precision, intent(in) :: x(ixI^S,1:ndim)
3510  double precision,intent(out) :: f(ixI^S,nwflux)
3511 
3512  double precision :: vHall(ixI^S,1:ndir)
3513  double precision :: pgas
3514  integer :: idir, ix^D
3515 
3516  if (mhd_hall) then
3517  call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3518  end if
3519 
3520  {do ix^db=ixomin^db,ixomax^db\}
3521  ! Get flux of density
3522  f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3523 
3524  if(mhd_energy) then
3525  pgas=w(ix^d,p_)
3526  else
3527  pgas=mhd_adiab*w(ix^d,rho_)**mhd_gamma
3528  end if
3529 
3530  f(ix^d,mom(1:ndir))=0.d0
3531  f(ix^d,mom(idim))=pgas+half*sum(w(ix^d,mag(1:ndir))**2)
3532  ! Get flux of momentum and magnetic field
3533  do idir=1,ndir
3534  ! f_i[m_k]=v_i*m_k-b_k*b_i
3535  f(ix^d,mom(idir))=f(ix^d,mom(idir))+wc(ix^d,mom(idim))*w(ix^d,mom(idir))-w(ix^d,mag(idim))*w(ix^d,mag(idir))
3536  ! f_i[b_k]=v_i*b_k-v_k*b_i
3537  f(ix^d,mag(idir))=w(ix^d,mom(idim))*w(ix^d,mag(idir))-w(ix^d,mag(idim))*w(ix^d,mom(idir))
3538  if (mhd_hall) then
3539  ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3540  f(ix^d,mag(idir)) = f(ix^d,mag(idir)) &
3541  + vhall(ix^d,idim)*w(ix^d,mag(idir)) &
3542  - vhall(ix^d,idir)*w(ix^d,mag(idim))
3543  end if
3544  end do
3545 
3546  if(mhd_glm) then
3547  !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3548  f(ix^d,mag(idim))=w(ix^d,psi_)
3549  f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3550  end if
3551 
3552  ! Get flux of energy
3553  if(mhd_energy) then
3554  f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+pgas)
3555  end if
3556 
3558  f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(sum(w(ix^d,mag(1:ndim))**2))+smalldouble)
3559  f(ix^d,q_)=zero
3560  end if
3561 
3562  ! Get flux of tracer
3563  do idir=1,mhd_n_tracer
3564  f(ix^d,tracer(idir))=w(ix^d,mom(idim))*w(ix^d,tracer(idir))
3565  end do
3566  {end do\}
3567 
3568  end subroutine mhd_get_flux_hde
3569 
3570  !> Calculate fluxes within ixO^L with possible splitting
3571  subroutine mhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
3573  use mod_geometry
3574 
3575  integer, intent(in) :: ixI^L, ixO^L, idim
3576  ! conservative w
3577  double precision, intent(in) :: wC(ixI^S,nw)
3578  ! primitive w
3579  double precision, intent(in) :: w(ixI^S,nw)
3580  double precision, intent(in) :: x(ixI^S,1:ndim)
3581  double precision,intent(out) :: f(ixI^S,nwflux)
3582 
3583  double precision :: vHall(ixI^S,1:ndir)
3584  double precision :: ptotal, Btotal(1:ndir)
3585  integer :: idir, ix^D
3586 
3587  if (mhd_hall) then
3588  call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3589  end if
3590 
3591  {do ix^db=ixomin^db,ixomax^db\}
3592  ! Get flux of density
3593  if(has_equi_rho0) then
3594  f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3595  else
3596  f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3597  endif
3598 
3599  if(mhd_energy) then
3600  ptotal=w(ix^d,p_)+half*sum(w(ix^d,mag(1:ndir))**2)
3601  else
3602  ptotal=mhd_adiab*w(ix^d,rho_)**mhd_gamma+half*sum(w(ix^d,mag(1:ndir))**2)
3603  if(has_equi_pe0) then
3604  ptotal=ptotal-block%equi_vars(ix^d,equi_pe0_,b0i)
3605  end if
3606  end if
3607 
3608  f(ix^d,mom(1:ndir))=0.d0
3609  if(b0field) then
3610  btotal(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,idim)
3611  ptotal=ptotal+sum(w(ix^d,mag(1:ndir))*block%B0(ix^d,1:ndir,idim))
3612  f(ix^d,mom(idim))=ptotal
3613  ! Get flux of momentum and magnetic field
3614  do idir=1,ndir
3615  ! f_i[m_k]=v_i*m_k-b_k*b_i
3616  f(ix^d,mom(idir))=f(ix^d,mom(idir))+wc(ix^d,mom(idim))*w(ix^d,mom(idir))-&
3617  btotal(idim)*w(ix^d,mag(idir))-w(ix^d,mag(idim))*block%B0(ix^d,idir,idim)
3618  ! f_i[b_k]=v_i*b_k-v_k*b_i
3619  f(ix^d,mag(idir))=w(ix^d,mom(idim))*btotal(idir)-btotal(idim)*w(ix^d,mom(idir))
3620  if (mhd_hall) then
3621  ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3622  f(ix^d,mag(idir)) = f(ix^d,mag(idir)) &
3623  - vhall(ix^d,idir)*w(ix^d,mag(idim)) &
3624  + vhall(ix^d,idim)*w(ix^d,mag(idir))
3625  end if
3626  end do
3627  else
3628  btotal(1:ndir)=w(ix^d,mag(1:ndir))
3629  f(ix^d,mom(idim))=ptotal
3630  ! Get flux of momentum and magnetic field
3631  do idir=1,ndir
3632  ! f_i[m_k]=v_i*m_k-b_k*b_i
3633  f(ix^d,mom(idir))=f(ix^d,mom(idir))+wc(ix^d,mom(idim))*w(ix^d,mom(idir))-w(ix^d,mag(idim))*w(ix^d,mag(idir))
3634  ! f_i[b_k]=v_i*b_k-v_k*b_i
3635  f(ix^d,mag(idir))=w(ix^d,mom(idim))*w(ix^d,mag(idir))-w(ix^d,mag(idim))*w(ix^d,mom(idir))
3636  if (mhd_hall) then
3637  ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3638  f(ix^d,mag(idir)) = f(ix^d,mag(idir)) &
3639  + vhall(ix^d,idim)*w(ix^d,mag(idir)) &
3640  - vhall(ix^d,idir)*w(ix^d,mag(idim))
3641  end if
3642  end do
3643  end if
3644  if(mhd_glm) then
3645  f(ix^d,mag(idim))=w(ix^d,psi_)
3646  !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3647  f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3648  end if
3649 
3650  ! Get flux of energy
3651  ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
3652  if(mhd_energy) then
3653  if(mhd_internal_e) then
3654  f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
3655  else
3656  f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
3657  -btotal(idim)*sum(w(ix^d,mag(1:ndir))*w(ix^d,mom(1:ndir)))
3658  if(mhd_hall) then
3659  ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
3660  f(ix^d,e_) = f(ix^d,e_) + vhall(ix^d,idim) * &
3661  sum(w(ix^d, mag(1:ndir))*btotal(1:ndir)) &
3662  - btotal(idim) * sum(vhall(ix^d,1:ndir)*w(ix^d,mag(1:ndir)))
3663  end if
3664  end if
3665  end if
3666 
3668  if(b0field) then
3669  f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*btotal(idim)/(dsqrt(sum(btotal(1:ndim)**2))+smalldouble)
3670  else
3671  f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(sum(w(ix^d,mag(1:ndim))**2))+smalldouble)
3672  end if
3673  f(ix^d,q_)=zero
3674  end if
3675 
3676  ! Get flux of tracer
3677  do idir=1,mhd_n_tracer
3678  f(ix^d,tracer(idir))=w(ix^d,mom(idim))*w(ix^d,tracer(idir))
3679  end do
3680  {end do\}
3681 
3682  end subroutine mhd_get_flux_split
3683 
3684  !> Calculate semirelativistic fluxes within ixO^L without any splitting
3685  subroutine mhd_get_flux_semirelati(wC,w,x,ixI^L,ixO^L,idim,f)
3687  use mod_geometry
3688 
3689  integer, intent(in) :: ixI^L, ixO^L, idim
3690  ! conservative w
3691  double precision, intent(in) :: wC(ixI^S,nw)
3692  ! primitive w
3693  double precision, intent(in) :: w(ixI^S,nw)
3694  double precision, intent(in) :: x(ixI^S,1:ndim)
3695  double precision,intent(out) :: f(ixI^S,nwflux)
3696 
3697  double precision :: pgas, SA(1:3), E(1:3), B(1:ndir)
3698  integer :: iw, idir, ix^D
3699 
3700  {do ix^db=ixomin^db,ixomax^db\}
3701  ! gas thermal pressure
3702  if(mhd_energy) then
3703  pgas=w(ix^d,p_)
3704  else
3705  pgas=mhd_adiab*w(ix^d,rho_)**mhd_gamma
3706  end if
3707  if(b0field) then
3708  b(1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,idim)
3709  else
3710  b(1:ndir)=w(ix^d,mag(1:ndir))
3711  end if
3712  ! E=Bxv
3713  {^ifthreed
3714  e(1)=b(2)*w(ix^d,mom(3))-b(3)*w(ix^d,mom(2))
3715  e(2)=b(3)*w(ix^d,mom(1))-b(1)*w(ix^d,mom(3))
3716  e(3)=b(1)*w(ix^d,mom(2))-b(2)*w(ix^d,mom(1))
3717  }
3718  {^nothreed
3719  if(ndir==3) then
3720  e(1)=b(2)*w(ix^d,mom(3))-b(3)*w(ix^d,mom(2))
3721  e(2)=b(3)*w(ix^d,mom(1))-b(1)*w(ix^d,mom(3))
3722  else
3723  e(1:2)=zero
3724  end if
3725  e(3)=b(1)*w(ix^d,mom(2))-b(2)*w(ix^d,mom(1))
3726  }
3727  ! Get flux of total energy
3728  if(mhd_internal_e) then
3729  ! Get flux of internal energy
3730  f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
3731  else if(mhd_energy) then
3732  ! S=ExB
3733  {^ifthreed
3734  sa(1)=e(2)*w(ix^d,mag(3))-e(3)*w(ix^d,mag(2))
3735  sa(2)=e(3)*w(ix^d,mag(1))-e(1)*w(ix^d,mag(3))
3736  sa(3)=e(1)*w(ix^d,mag(2))-e(2)*w(ix^d,mag(1))
3737  }
3738  {^nothreed
3739  if(ndir==3) then
3740  sa(1)=e(2)*w(ix^d,mag(3))-e(3)*w(ix^d,mag(2))
3741  sa(2)=e(3)*w(ix^d,mag(1))-e(1)*w(ix^d,mag(3))
3742  else
3743  sa(1:2)=zero
3744  end if
3745  sa(3)=e(1)*w(ix^d,mag(2))-e(2)*w(ix^d,mag(1))
3746  }
3747  f(ix^d,e_)=w(ix^d,mom(idim))*(half*w(ix^d,rho_)*sum(w(ix^d,mom(1:ndir))**2)+&
3748  mhd_gamma*pgas*inv_gamma_1)+sa(idim)
3749  end if
3750 
3751  ! Get flux of density
3752  f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3753 
3754  ! Get flux of momentum
3755  f(ix^d,mom(1:3))=0.d0
3756  if(b0field) then
3757  ! gas pressure + magnetic pressure + electric pressure
3758  f(ix^d,mom(idim))=pgas+half*(sum(w(ix^d,mag(1:ndir))**2)+&
3759  sum(e(1:3)**2)*inv_squared_c)+sum(w(ix^d,mag(1:ndir))*block%B0(ix^d,1:ndir,idim))
3760  do idir=1,ndir
3761  f(ix^d,mom(idir))=f(ix^d,mom(idir))+w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,mom(idir))&
3762  -w(ix^d,mag(idim))*b(idir)-e(idim)*e(idir)*inv_squared_c&
3763  -block%B0(ix^d,idim,idim)*w(ix^d,mag(idir))
3764  end do
3765  else
3766  ! gas pressure + magnetic pressure + electric pressure
3767  f(ix^d,mom(idim))=pgas+half*(sum(w(ix^d,mag(1:ndir))**2)+&
3768  sum(e(1:3)**2)*inv_squared_c)
3769  do idir=1,ndir
3770  f(ix^d,mom(idir))=f(ix^d,mom(idir))+w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,mom(idir))&
3771  -w(ix^d,mag(idim))*w(ix^d,mag(idir))-e(idim)*e(idir)*inv_squared_c
3772  end do
3773  end if
3774 
3775  ! compute flux of magnetic field
3776  ! f_i[b_k]=v_i*b_k-v_k*b_i
3777  do idir=1,ndir
3778  f(ix^d,mag(idir))=w(ix^d,mom(idim))*b(idir)-b(idim)*w(ix^d,mom(idir))
3779  end do
3780  if(mhd_glm) then
3781  f(ix^d,mag(idim))=w(ix^d,psi_)
3782  !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3783  f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
3784  end if
3785  ! Get flux of tracer
3786  do iw=1,mhd_n_tracer
3787  f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
3788  end do
3789  {end do\}
3790 
3791  end subroutine mhd_get_flux_semirelati
3792 
3793  !> Source terms J.E in internal energy.
3794  !> For the ambipolar term E = ambiCoef * JxBxB=ambiCoef * B^2(-J_perpB)
3795  !=> the source term J.E = ambiCoef * B^2 * J_perpB^2 = ambiCoef * JxBxB^2/B^2
3796  !> ambiCoef is calculated as mhd_ambi_coef/rho^2, see also the subroutine mhd_get_Jambi
3797  subroutine add_source_ambipolar_internal_energy(qdt,ixI^L,ixO^L,wCT,w,x,ie)
3799  integer, intent(in) :: ixI^L, ixO^L,ie
3800  double precision, intent(in) :: qdt
3801  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
3802  double precision, intent(inout) :: w(ixI^S,1:nw)
3803  double precision :: tmp(ixI^S)
3804  double precision :: jxbxb(ixI^S,1:3)
3805 
3806  call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,jxbxb)
3807  tmp(ixo^s) = sum(jxbxb(ixo^s,1:3)**2,dim=ndim+1) / mhd_mag_en_all(wct, ixi^l, ixo^l)
3808  call multiplyambicoef(ixi^l,ixo^l,tmp,wct,x)
3809  w(ixo^s,ie)=w(ixo^s,ie)+qdt * tmp
3810 
3812 
3813  subroutine mhd_get_jxbxb(w,x,ixI^L,ixO^L,res)
3815 
3816  integer, intent(in) :: ixI^L, ixO^L
3817  double precision, intent(in) :: w(ixI^S,nw)
3818  double precision, intent(in) :: x(ixI^S,1:ndim)
3819  double precision, intent(out) :: res(:^D&,:)
3820 
3821  double precision :: btot(ixI^S,1:3)
3822  double precision :: current(ixI^S,7-2*ndir:3)
3823  double precision :: tmp(ixI^S),b2(ixI^S)
3824  integer :: idir, idirmin
3825 
3826  res=0.d0
3827  ! Calculate current density and idirmin
3828  call get_current(w,ixi^l,ixo^l,idirmin,current)
3829  !!!here we know that current has nonzero values only for components in the range idirmin, 3
3830 
3831  if(b0field) then
3832  do idir=1,3
3833  btot(ixo^s, idir) = w(ixo^s,mag(idir)) + block%B0(ixo^s,idir,b0i)
3834  enddo
3835  else
3836  btot(ixo^s,1:3) = w(ixo^s,mag(1:3))
3837  endif
3838 
3839  tmp(ixo^s) = sum(current(ixo^s,idirmin:3)*btot(ixo^s,idirmin:3),dim=ndim+1) !J.B
3840  b2(ixo^s) = sum(btot(ixo^s,1:3)**2,dim=ndim+1) !B^2
3841  do idir=1,idirmin-1
3842  res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s)
3843  enddo
3844  do idir=idirmin,3
3845  res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s) - current(ixo^s,idir) * b2(ixo^s)
3846  enddo
3847  end subroutine mhd_get_jxbxb
3848 
3849  !> Sets the sources for the ambipolar
3850  !> this is used for the STS method
3851  ! The sources are added directly (instead of fluxes as in the explicit)
3852  !> at the corresponding indices
3853  !> store_flux_var is explicitly called for each of the fluxes one by one
3854  subroutine sts_set_source_ambipolar(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
3856  use mod_fix_conserve
3857 
3858  integer, intent(in) :: ixI^L, ixO^L,igrid,nflux
3859  double precision, intent(in) :: x(ixI^S,1:ndim)
3860  double precision, intent(inout) :: wres(ixI^S,1:nw), w(ixI^S,1:nw)
3861  double precision, intent(in) :: my_dt
3862  logical, intent(in) :: fix_conserve_at_step
3863 
3864  double precision, dimension(ixI^S,1:3) :: tmp,ff
3865  double precision :: fluxall(ixI^S,1:nflux,1:ndim)
3866  double precision :: fE(ixI^S,sdim:3)
3867  double precision :: btot(ixI^S,1:3),tmp2(ixI^S)
3868  integer :: i, ixA^L, ie_
3869 
3870  ixa^l=ixo^l^ladd1;
3871 
3872  fluxall=zero
3873 
3874  call mhd_get_jxbxb(w,x,ixi^l,ixa^l,tmp)
3875 
3876  !set electric field in tmp: E=nuA * jxbxb, where nuA=-etaA/rho^2
3877  do i=1,3
3878  !tmp(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * tmp(ixA^S,i)
3879  call multiplyambicoef(ixi^l,ixa^l,tmp(ixi^s,i),w,x)
3880  enddo
3881 
3882  if(mhd_energy .and. .not.mhd_internal_e) then
3883  !btot should be only mag. pert.
3884  btot(ixa^s,1:3)=0.d0
3885  !if(B0field) then
3886  ! do i=1,ndir
3887  ! btot(ixA^S, i) = w(ixA^S,mag(i)) + block%B0(ixA^S,i,0)
3888  ! enddo
3889  !else
3890  btot(ixa^s,1:ndir) = w(ixa^s,mag(1:ndir))
3891  !endif
3892  call cross_product(ixi^l,ixa^l,tmp,btot,ff)
3893  call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
3894  if(fix_conserve_at_step) fluxall(ixi^s,1,1:ndim)=ff(ixi^s,1:ndim)
3895  !- sign comes from the fact that the flux divergence is a source now
3896  wres(ixo^s,e_)=-tmp2(ixo^s)
3897  endif
3898 
3899  if(stagger_grid) then
3900  if(ndir>ndim) then
3901  !!!Bz
3902  ff(ixa^s,1) = tmp(ixa^s,2)
3903  ff(ixa^s,2) = -tmp(ixa^s,1)
3904  ff(ixa^s,3) = 0.d0
3905  call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
3906  if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
3907  wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
3908  end if
3909  fe=0.d0
3910  call update_faces_ambipolar(ixi^l,ixo^l,w,x,tmp,fe,btot)
3911  ixamax^d=ixomax^d;
3912  ixamin^d=ixomin^d-1;
3913  wres(ixa^s,mag(1:ndim))=-btot(ixa^s,1:ndim)
3914  else
3915  !write curl(ele) as the divergence
3916  !m1={0,ele[[3]],-ele[[2]]}
3917  !m2={-ele[[3]],0,ele[[1]]}
3918  !m3={ele[[2]],-ele[[1]],0}
3919 
3920  !!!Bx
3921  ff(ixa^s,1) = 0.d0
3922  ff(ixa^s,2) = tmp(ixa^s,3)
3923  ff(ixa^s,3) = -tmp(ixa^s,2)
3924  call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
3925  if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
3926  !flux divergence is a source now
3927  wres(ixo^s,mag(1))=-tmp2(ixo^s)
3928  !!!By
3929  ff(ixa^s,1) = -tmp(ixa^s,3)
3930  ff(ixa^s,2) = 0.d0
3931  ff(ixa^s,3) = tmp(ixa^s,1)
3932  call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
3933  if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
3934  wres(ixo^s,mag(2))=-tmp2(ixo^s)
3935 
3936  if(ndir==3) then
3937  !!!Bz
3938  ff(ixa^s,1) = tmp(ixa^s,2)
3939  ff(ixa^s,2) = -tmp(ixa^s,1)
3940  ff(ixa^s,3) = 0.d0
3941  call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
3942  if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
3943  wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
3944  end if
3945 
3946  end if
3947 
3948  if(fix_conserve_at_step) then
3949  fluxall=my_dt*fluxall
3950  call store_flux(igrid,fluxall,1,ndim,nflux)
3951  if(stagger_grid) then
3952  call store_edge(igrid,ixi^l,my_dt*fe,1,ndim)
3953  end if
3954  end if
3955 
3956  end subroutine sts_set_source_ambipolar
3957 
3958  !> get ambipolar electric field and the integrals around cell faces
3959  subroutine update_faces_ambipolar(ixI^L,ixO^L,w,x,ECC,fE,circ)
3961 
3962  integer, intent(in) :: ixI^L, ixO^L
3963  double precision, intent(in) :: w(ixI^S,1:nw)
3964  double precision, intent(in) :: x(ixI^S,1:ndim)
3965  ! amibipolar electric field at cell centers
3966  double precision, intent(in) :: ECC(ixI^S,1:3)
3967  double precision, intent(out) :: fE(ixI^S,sdim:3)
3968  double precision, intent(out) :: circ(ixI^S,1:ndim)
3969 
3970  integer :: hxC^L,ixC^L,ixA^L
3971  integer :: idim1,idim2,idir,ix^D
3972 
3973  fe=zero
3974  ! calcuate ambipolar electric field on cell edges from cell centers
3975  do idir=sdim,3
3976  ixcmax^d=ixomax^d;
3977  ixcmin^d=ixomin^d+kr(idir,^d)-1;
3978  {do ix^db=0,1\}
3979  if({ ix^d==1 .and. ^d==idir | .or.}) cycle
3980  ixamin^d=ixcmin^d+ix^d;
3981  ixamax^d=ixcmax^d+ix^d;
3982  fe(ixc^s,idir)=fe(ixc^s,idir)+ecc(ixa^s,idir)
3983  {end do\}
3984  fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0*block%dsC(ixc^s,idir)
3985  end do
3986 
3987  ! Calculate circulation on each face to get value of line integral of
3988  ! electric field in the positive idir direction.
3989  ixcmax^d=ixomax^d;
3990  ixcmin^d=ixomin^d-1;
3991 
3992  circ=zero
3993 
3994  do idim1=1,ndim ! Coordinate perpendicular to face
3995  do idim2=1,ndim
3996  do idir=sdim,3 ! Direction of line integral
3997  ! Assemble indices
3998  hxc^l=ixc^l-kr(idim2,^d);
3999  ! Add line integrals in direction idir
4000  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4001  +lvc(idim1,idim2,idir)&
4002  *(fe(ixc^s,idir)&
4003  -fe(hxc^s,idir))
4004  end do
4005  end do
4006  circ(ixc^s,idim1)=circ(ixc^s,idim1)/block%surfaceC(ixc^s,idim1)
4007  end do
4008 
4009  end subroutine update_faces_ambipolar
4010 
4011  !> use cell-center flux to get cell-face flux
4012  !> and get the source term as the divergence of the flux
4013  subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
4015 
4016  integer, intent(in) :: ixI^L, ixO^L
4017  double precision, dimension(:^D&,:), intent(inout) :: ff
4018  double precision, intent(out) :: src(ixI^S)
4019 
4020  double precision :: ffc(ixI^S,1:ndim)
4021  double precision :: dxinv(ndim)
4022  integer :: idims, ix^D, ixA^L, ixB^L, ixC^L
4023 
4024  ixa^l=ixo^l^ladd1;
4025  dxinv=1.d0/dxlevel
4026  ! cell corner flux in ffc
4027  ffc=0.d0
4028  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
4029  {do ix^db=0,1\}
4030  ixbmin^d=ixcmin^d+ix^d;
4031  ixbmax^d=ixcmax^d+ix^d;
4032  ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
4033  {end do\}
4034  ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
4035  ! flux at cell face
4036  ff(ixi^s,1:ndim)=0.d0
4037  do idims=1,ndim
4038  ixb^l=ixo^l-kr(idims,^d);
4039  ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
4040  {do ix^db=0,1 \}
4041  if({ ix^d==0 .and. ^d==idims | .or.}) then
4042  ixbmin^d=ixcmin^d-ix^d;
4043  ixbmax^d=ixcmax^d-ix^d;
4044  ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
4045  end if
4046  {end do\}
4047  ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
4048  end do
4049  src=0.d0
4050  if(slab_uniform) then
4051  do idims=1,ndim
4052  ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
4053  ixb^l=ixo^l-kr(idims,^d);
4054  src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4055  end do
4056  else
4057  do idims=1,ndim
4058  ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
4059  ixb^l=ixo^l-kr(idims,^d);
4060  src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4061  end do
4062  src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
4063  end if
4064  end subroutine get_flux_on_cell_face
4065 
4066  !> Calculates the explicit dt for the ambipokar term
4067  !> This function is used by both explicit scheme and STS method
4068  function get_ambipolar_dt(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
4070 
4071  integer, intent(in) :: ixi^l, ixo^l
4072  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
4073  double precision, intent(in) :: w(ixi^s,1:nw)
4074  double precision :: dtnew
4075 
4076  double precision :: coef
4077  double precision :: dxarr(ndim)
4078  double precision :: tmp(ixi^s)
4079 
4080  ^d&dxarr(^d)=dx^d;
4081  tmp(ixo^s) = mhd_mag_en_all(w, ixi^l, ixo^l)
4082  call multiplyambicoef(ixi^l,ixo^l,tmp,w,x)
4083  coef = maxval(abs(tmp(ixo^s)))
4084  if(coef/=0.d0) then
4085  coef=1.d0/coef
4086  else
4087  coef=bigdouble
4088  end if
4089  if(slab_uniform) then
4090  dtnew=minval(dxarr(1:ndim))**2.0d0*coef
4091  else
4092  dtnew=minval(block%ds(ixo^s,1:ndim))**2.0d0*coef
4093  end if
4094 
4095  end function get_ambipolar_dt
4096 
4097  !> multiply res by the ambipolar coefficient
4098  !> The ambipolar coefficient is calculated as -mhd_eta_ambi/rho^2
4099  !> The user may mask its value in the user file
4100  !> by implemneting usr_mask_ambipolar subroutine
4101  subroutine multiplyambicoef(ixI^L,ixO^L,res,w,x)
4103  integer, intent(in) :: ixi^l, ixo^l
4104  double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
4105  double precision, intent(inout) :: res(ixi^s)
4106  double precision :: tmp(ixi^s)
4107  double precision :: rho(ixi^s)
4108 
4109  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
4110  tmp=0.d0
4111  tmp(ixo^s)=-mhd_eta_ambi/rho(ixo^s)**2
4112  if (associated(usr_mask_ambipolar)) then
4113  call usr_mask_ambipolar(ixi^l,ixo^l,w,x,tmp)
4114  end if
4115 
4116  res(ixo^s) = tmp(ixo^s) * res(ixo^s)
4117  end subroutine multiplyambicoef
4118 
4119  !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
4120  subroutine mhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
4124  use mod_gravity, only: gravity_add_source
4125  use mod_cak_force, only: cak_add_source
4126 
4127  integer, intent(in) :: ixI^L, ixO^L
4128  double precision, intent(in) :: qdt,dtfactor
4129  double precision, intent(in) :: wCT(ixI^S,1:nw),wCTprim(ixI^S,1:nw), x(ixI^S,1:ndim)
4130  double precision, intent(inout) :: w(ixI^S,1:nw)
4131  logical, intent(in) :: qsourcesplit
4132  logical, intent(inout) :: active
4133 
4134  !TODO local_timestep support is only added for splitting
4135  ! but not for other nonideal terms such gravity, RC, viscosity,..
4136  ! it will also only work for divbfix 'linde', which does not require
4137  ! modification as it does not use dt in the update
4138 
4139  if (.not. qsourcesplit) then
4140  if(mhd_internal_e) then
4141  ! Source for solving internal energy
4142  active = .true.
4143  call add_source_internal_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4144  else
4145  if(has_equi_pe0) then
4146  active = .true.
4147  call add_pe0_divv(qdt,dtfactor,ixi^l,ixo^l,wct,w,x)
4148  end if
4149  end if
4150 
4152  call add_hypertc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4153  end if
4154 
4155  ! Source for B0 splitting
4156  if (b0field) then
4157  active = .true.
4158  call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wct,w,x)
4159  end if
4160 
4161  ! Sources for resistivity in eqs. for e, B1, B2 and B3
4162  if (abs(mhd_eta)>smalldouble)then
4163  active = .true.
4164  call add_source_res2(qdt,ixi^l,ixo^l,wct,w,x)
4165  end if
4166 
4167  if (mhd_eta_hyper>0.d0)then
4168  active = .true.
4169  call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
4170  end if
4171 
4172  if(mhd_hydrodynamic_e) then
4173  ! Source for solving hydrodynamic energy
4174  active = .true.
4175  call add_source_hydrodynamic_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4176  else if (mhd_semirelativistic) then
4177  ! add sources for semirelativistic MHD
4178  active = .true.
4179  call add_source_semirelativistic(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4180  end if
4181  end if
4182 
4183  {^nooned
4184  if(source_split_divb .eqv. qsourcesplit) then
4185  ! Sources related to div B
4186  select case (type_divb)
4187  case (divb_ct)
4188  continue ! Do nothing
4189  case (divb_linde)
4190  active = .true.
4191  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4192  case (divb_glm)
4193  active = .true.
4194  call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
4195  case (divb_powel)
4196  active = .true.
4197  call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
4198  case (divb_janhunen)
4199  active = .true.
4200  call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
4201  case (divb_lindejanhunen)
4202  active = .true.
4203  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4204  call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
4205  case (divb_lindepowel)
4206  active = .true.
4207  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4208  call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
4209  case (divb_lindeglm)
4210  active = .true.
4211  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4212  call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
4213  case (divb_multigrid)
4214  continue ! Do nothing
4215  case (divb_none)
4216  ! Do nothing
4217  case default
4218  call mpistop('Unknown divB fix')
4219  end select
4220  end if
4221  }
4222 
4223  if(mhd_radiative_cooling) then
4224  call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
4225  w,x,qsourcesplit,active, rc_fl)
4226  end if
4227 
4228  if(mhd_viscosity) then
4229  call viscosity_add_source(qdt,ixi^l,ixo^l,wct,&
4230  w,x,mhd_energy,qsourcesplit,active)
4231  end if
4232 
4233  if(mhd_gravity) then
4234  call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
4235  w,x,gravity_energy,gravity_rhov,qsourcesplit,active)
4236  end if
4237 
4238  if (mhd_cak_force) then
4239  call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,mhd_energy,qsourcesplit,active)
4240  end if
4241 
4242  ! update temperature from new pressure, density, and old ionization degree
4243  if(mhd_partial_ionization) then
4244  if(.not.qsourcesplit) then
4245  active = .true.
4246  call mhd_update_temperature(ixi^l,ixo^l,wct,w,x)
4247  end if
4248  end if
4249 
4250  end subroutine mhd_add_source
4251 
4252  subroutine add_pe0_divv(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
4254  use mod_geometry
4255 
4256  integer, intent(in) :: ixI^L, ixO^L
4257  double precision, intent(in) :: qdt,dtfactor
4258  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4259  double precision, intent(inout) :: w(ixI^S,1:nw)
4260  double precision :: v(ixI^S,1:ndir)
4261  double precision :: divv(ixI^S)
4262 
4263  call mhd_get_v(wct,x,ixi^l,ixi^l,v)
4264 
4265  if(slab_uniform) then
4266  if(nghostcells .gt. 2) then
4267  call divvector(v,ixi^l,ixo^l,divv,sixthorder=.true.)
4268  else
4269  call divvector(v,ixi^l,ixo^l,divv,fourthorder=.true.)
4270  end if
4271  else
4272  call divvector(v,ixi^l,ixo^l,divv)
4273  end if
4274  if(local_timestep) then
4275  w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
4276  else
4277  w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
4278  endif
4279  end subroutine add_pe0_divv
4280 
4281  subroutine get_tau(ixI^L,ixO^L,w,Te,tau,sigT5)
4283  integer, intent(in) :: ixI^L, ixO^L
4284  double precision, dimension(ixI^S,1:nw), intent(in) :: w
4285  double precision, dimension(ixI^S), intent(in) :: Te
4286  double precision, dimension(ixI^S), intent(out) :: tau,sigT5
4287 
4288  double precision :: dxmin,taumin
4289  double precision, dimension(ixI^S) :: sigT7,eint
4290  integer :: ix^D
4291 
4292  taumin=4.d0
4293  !> w supposed to be wCTprim here
4294  if(mhd_trac) then
4295  where(te(ixo^s) .lt. block%wextra(ixo^s,tcoff_))
4296  sigt5(ixo^s)=hypertc_kappa*sqrt(block%wextra(ixo^s,tcoff_)**5)
4297  sigt7(ixo^s)=sigt5(ixo^s)*block%wextra(ixo^s,tcoff_)
4298  else where
4299  sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
4300  sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
4301  end where
4302  else
4303  sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
4304  sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
4305  end if
4306  eint(ixo^s)=w(ixo^s,p_)/(mhd_gamma-one)
4307  tau(ixo^s)=max(taumin*dt,sigt7(ixo^s)/eint(ixo^s)/cmax_global**2)
4308  end subroutine get_tau
4309 
4310  subroutine add_hypertc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
4312  integer, intent(in) :: ixI^L,ixO^L
4313  double precision, intent(in) :: qdt
4314  double precision, dimension(ixI^S,1:ndim), intent(in) :: x
4315  double precision, dimension(ixI^S,1:nw), intent(in) :: wCT,wCTprim
4316  double precision, dimension(ixI^S,1:nw), intent(inout) :: w
4317 
4318  double precision :: invdx
4319  double precision, dimension(ixI^S) :: Te,tau,sigT,htc_qsrc,Tface,R
4320  double precision, dimension(ixI^S) :: htc_esrc,Bsum,Bunit
4321  double precision, dimension(ixI^S,1:ndim) :: Btot
4322  integer :: idims
4323  integer :: hxC^L,hxO^L,ixC^L,jxC^L,jxO^L,kxC^L
4324 
4325  call mhd_get_rfactor(wctprim,x,ixi^l,ixi^l,r)
4326  !Te(ixI^S)=wCTprim(ixI^S,p_)/wCT(ixI^S,rho_)
4327  te(ixi^s)=wctprim(ixi^s,p_)/(r(ixi^s)*w(ixi^s,rho_))
4328  call get_tau(ixi^l,ixo^l,wctprim,te,tau,sigt)
4329  htc_qsrc=zero
4330  do idims=1,ndim
4331  if(b0field) then
4332  btot(ixo^s,idims)=wct(ixo^s,mag(idims))+block%B0(ixo^s,idims,0)
4333  else
4334  btot(ixo^s,idims)=wct(ixo^s,mag(idims))
4335  endif
4336  enddo
4337  bsum(ixo^s)=sqrt(sum(btot(ixo^s,:)**2,dim=ndim+1))+smalldouble
4338  do idims=1,ndim
4339  invdx=1.d0/dxlevel(idims)
4340  ixc^l=ixo^l;
4341  ixcmin^d=ixomin^d-kr(idims,^d);ixcmax^d=ixomax^d;
4342  jxc^l=ixc^l+kr(idims,^d);
4343  kxc^l=jxc^l+kr(idims,^d);
4344  hxc^l=ixc^l-kr(idims,^d);
4345  hxo^l=ixo^l-kr(idims,^d);
4346  tface(ixc^s)=(7.d0*(te(ixc^s)+te(jxc^s))-(te(hxc^s)+te(kxc^s)))/12.d0
4347  bunit(ixo^s)=btot(ixo^s,idims)/bsum(ixo^s)
4348  htc_qsrc(ixo^s)=htc_qsrc(ixo^s)+sigt(ixo^s)*bunit(ixo^s)*(tface(ixo^s)-tface(hxo^s))*invdx
4349  end do
4350  htc_qsrc(ixo^s)=(htc_qsrc(ixo^s)+wct(ixo^s,q_))/tau(ixo^s)
4351  w(ixo^s,q_)=w(ixo^s,q_)-qdt*htc_qsrc(ixo^s)
4352  end subroutine add_hypertc_source
4353 
4354  !> Compute the Lorentz force (JxB)
4355  subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
4357  integer, intent(in) :: ixI^L, ixO^L
4358  double precision, intent(in) :: w(ixI^S,1:nw)
4359  double precision, intent(inout) :: JxB(ixI^S,3)
4360  double precision :: a(ixI^S,3), b(ixI^S,3)
4361  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
4362  double precision :: current(ixI^S,7-2*ndir:3)
4363  integer :: idir, idirmin
4364 
4365  b=0.0d0
4366  do idir = 1, ndir
4367  b(ixo^s, idir) = mhd_mag_i_all(w, ixi^l, ixo^l,idir)
4368  end do
4369 
4370  ! store J current in a
4371  call get_current(w,ixi^l,ixo^l,idirmin,current)
4372 
4373  a=0.0d0
4374  do idir=7-2*ndir,3
4375  a(ixo^s,idir)=current(ixo^s,idir)
4376  end do
4377 
4378  call cross_product(ixi^l,ixo^l,a,b,jxb)
4379  end subroutine get_lorentz_force
4380 
4381  !> Compute 1/(1+v_A^2/c^2) for semirelativistic MHD, where v_A is the Alfven
4382  !> velocity
4383  subroutine mhd_gamma2_alfven(ixI^L, ixO^L, w, gamma_A2)
4385  integer, intent(in) :: ixI^L, ixO^L
4386  double precision, intent(in) :: w(ixI^S, nw)
4387  double precision, intent(out) :: gamma_A2(ixO^S)
4388  double precision :: rho(ixI^S)
4389 
4390  ! mhd_get_rho cannot be used as x is not a param
4391  if(has_equi_rho0) then
4392  rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
4393  else
4394  rho(ixo^s) = w(ixo^s,rho_)
4395  endif
4396  ! Compute the inverse of 1 + B^2/(rho * c^2)
4397  gamma_a2(ixo^s) = 1.0d0/(1.0d0+mhd_mag_en_all(w, ixi^l, ixo^l)/rho(ixo^s)*inv_squared_c)
4398  end subroutine mhd_gamma2_alfven
4399 
4400  !> Compute 1/sqrt(1+v_A^2/c^2) for semirelativisitic MHD, where v_A is the
4401  !> Alfven velocity
4402  function mhd_gamma_alfven(w, ixI^L, ixO^L) result(gamma_A)
4404  integer, intent(in) :: ixi^l, ixo^l
4405  double precision, intent(in) :: w(ixi^s, nw)
4406  double precision :: gamma_a(ixo^s)
4407 
4408  call mhd_gamma2_alfven(ixi^l, ixo^l, w, gamma_a)
4409  gamma_a = sqrt(gamma_a)
4410  end function mhd_gamma_alfven
4411 
4412  subroutine mhd_get_rho(w,x,ixI^L,ixO^L,rho)
4414  integer, intent(in) :: ixi^l, ixo^l
4415  double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
4416  double precision, intent(out) :: rho(ixi^s)
4417 
4418  if(has_equi_rho0) then
4419  rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
4420  else
4421  rho(ixo^s) = w(ixo^s,rho_)
4422  endif
4423 
4424  end subroutine mhd_get_rho
4425 
4426  !> handle small or negative internal energy
4427  subroutine mhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
4429  use mod_small_values
4430  integer, intent(in) :: ixI^L,ixO^L, ie
4431  double precision, intent(inout) :: w(ixI^S,1:nw)
4432  double precision, intent(in) :: x(ixI^S,1:ndim)
4433  character(len=*), intent(in) :: subname
4434 
4435  double precision :: rho(ixI^S)
4436  integer :: idir
4437  logical :: flag(ixI^S,1:nw)
4438 
4439  flag=.false.
4440  if(has_equi_pe0) then
4441  where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1<small_e)&
4442  flag(ixo^s,ie)=.true.
4443  else
4444  where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
4445  endif
4446  if(any(flag(ixo^s,ie))) then
4447  select case (small_values_method)
4448  case ("replace")
4449  if(has_equi_pe0) then
4450  where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
4451  block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
4452  else
4453  where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
4454  endif
4455  case ("average")
4456  call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
4457  case default
4458  ! small values error shows primitive variables
4459  w(ixo^s,e_)=w(ixo^s,e_)*gamma_1
4460  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
4461  do idir = 1, ndir
4462  w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
4463  end do
4464  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
4465  end select
4466  end if
4467 
4468  end subroutine mhd_handle_small_ei
4469 
4470  subroutine mhd_update_temperature(ixI^L,ixO^L,wCT,w,x)
4473 
4474  integer, intent(in) :: ixI^L, ixO^L
4475  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4476  double precision, intent(inout) :: w(ixI^S,1:nw)
4477 
4478  double precision :: iz_H(ixO^S),iz_He(ixO^S), pth(ixI^S)
4479 
4480  call ionization_degree_from_temperature(ixi^l,ixo^l,wct(ixi^s,te_),iz_h,iz_he)
4481 
4482  call mhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
4483 
4484  w(ixo^s,te_)=(2.d0+3.d0*he_abundance)*pth(ixo^s)/(w(ixo^s,rho_)*(1.d0+iz_h(ixo^s)+&
4485  he_abundance*(iz_he(ixo^s)*(iz_he(ixo^s)+1.d0)+1.d0)))
4486 
4487  end subroutine mhd_update_temperature
4488 
4489  !> Source terms after split off time-independent magnetic field
4490  subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
4492 
4493  integer, intent(in) :: ixI^L, ixO^L
4494  double precision, intent(in) :: qdt, dtfactor,wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4495  double precision, intent(inout) :: w(ixI^S,1:nw)
4496 
4497  double precision :: a(ixI^S,3), b(ixI^S,3), axb(ixI^S,3)
4498  integer :: idir
4499 
4500  a=0.d0
4501  b=0.d0
4502  ! for force-free field J0xB0 =0
4503  if(.not.b0field_forcefree) then
4504  ! store B0 magnetic field in b
4505  b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
4506 
4507  ! store J0 current in a
4508  do idir=7-2*ndir,3
4509  a(ixo^s,idir)=block%J0(ixo^s,idir)
4510  end do
4511  call cross_product(ixi^l,ixo^l,a,b,axb)
4512  if(local_timestep) then
4513  do idir=1,3
4514  axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
4515  enddo
4516  else
4517  axb(ixo^s,:)=axb(ixo^s,:)*qdt
4518  endif
4519  ! add J0xB0 source term in momentum equations
4520  w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
4521  end if
4522 
4523  if(total_energy) then
4524  a=0.d0
4525  ! for free-free field -(vxB0) dot J0 =0
4526  b(ixo^s,:)=wct(ixo^s,mag(:))
4527  ! store full magnetic field B0+B1 in b
4528  if(.not.b0field_forcefree) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
4529  ! store velocity in a
4530  call mhd_get_v(wct,x,ixi^l,ixo^l,a(ixi^s,1:ndir))
4531  call cross_product(ixi^l,ixo^l,a,b,axb)
4532  if(local_timestep) then
4533  do idir=1,3
4534  axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
4535  enddo
4536  else
4537  axb(ixo^s,:)=axb(ixo^s,:)*qdt
4538  endif
4539  ! add -(vxB) dot J0 source term in energy equation
4540  do idir=7-2*ndir,3
4541  w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
4542  end do
4543  if(mhd_ambipolar) then
4544  !reuse axb
4545  call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,axb)
4546  ! source J0 * E
4547  do idir=sdim,3
4548  !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
4549  call multiplyambicoef(ixi^l,ixo^l,axb(ixi^s,idir),wct,x)
4550  w(ixo^s,e_)=w(ixo^s,e_)+axb(ixo^s,idir)*block%J0(ixo^s,idir)
4551  enddo
4552  endif
4553  end if
4554 
4555  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
4556 
4557  end subroutine add_source_b0split
4558 
4559  !> Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176
4560  subroutine add_source_semirelativistic(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
4562  use mod_geometry
4563 
4564  integer, intent(in) :: ixI^L, ixO^L
4565  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4566  double precision, intent(inout) :: w(ixI^S,1:nw)
4567  double precision, intent(in), optional :: wCTprim(ixI^S,1:nw)
4568 
4569  double precision :: B(ixI^S,3), v(ixI^S,3), E(ixI^S,3), divE(ixI^S)
4570  integer :: idir, idirmin, ix^D
4571 
4572  {do ix^db=iximin^db,iximax^db\}
4573  if(b0field) then
4574  b(ix^d,1:ndir)=w(ix^d,mag(1:ndir))+block%B0(ix^d,1:ndir,0)
4575  else
4576  b(ix^d,1:ndir)=w(ix^d,mag(1:ndir))
4577  end if
4578  ! E=Bxv
4579  {^ifthreed
4580  e(ix^d,1)=b(ix^d,2)*wctprim(ix^d,mom(3))-b(ix^d,3)*wctprim(ix^d,mom(2))
4581  e(ix^d,2)=b(ix^d,3)*wctprim(ix^d,mom(1))-b(ix^d,1)*wctprim(ix^d,mom(3))
4582  e(ix^d,3)=b(ix^d,1)*wctprim(ix^d,mom(2))-b(ix^d,2)*wctprim(ix^d,mom(1))
4583  }
4584  {^nothreed
4585  if(ndir==3) then
4586  e(ix^d,1)=b(ix^d,2)*wctprim(ix^d,mom(3))-b(ix^d,3)*wctprim(ix^d,mom(2))
4587  e(ix^d,2)=b(ix^d,3)*wctprim(ix^d,mom(1))-b(ix^d,1)*wctprim(ix^d,mom(3))
4588  else
4589  e(ix^d,1:2)=zero
4590  b(ix^d,3)=zero
4591  end if
4592  e(ix^d,3)=b(ix^d,1)*wctprim(ix^d,mom(2))-b(ix^d,2)*wctprim(ix^d,mom(1))
4593  }
4594  {end do\}
4595  call divvector(e,ixi^l,ixo^l,dive)
4596  ! curl E => B
4597  call curlvector(e,ixi^l,ixo^l,b,idirmin,1,3)
4598  ! E x (curl E) => v
4599  call cross_product(ixi^l,ixo^l,e,b,v)
4600  ! add source term in momentum equations (1/c0^2-1/c^2)(E dot divE - E x curlE)
4601  ! equation (26) and (27)
4602  do idir=1,ndir
4603  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))+qdt*(inv_squared_c0-inv_squared_c)*&
4604  (e(ixo^s,idir)*dive(ixo^s)-v(ixo^s,idir))
4605  end do
4606 
4607  end subroutine add_source_semirelativistic
4608 
4609  !> Source terms for internal energy version of MHD
4610  subroutine add_source_internal_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
4612  use mod_geometry
4613 
4614  integer, intent(in) :: ixI^L, ixO^L
4615  double precision, intent(in) :: qdt
4616  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4617  double precision, intent(inout) :: w(ixI^S,1:nw)
4618  double precision, intent(in) :: wCTprim(ixI^S,1:nw)
4619 
4620  double precision :: divv(ixI^S)
4621 
4622  if(slab_uniform) then
4623  if(nghostcells .gt. 2) then
4624  call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,sixthorder=.true.)
4625  else
4626  call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,fourthorder=.true.)
4627  end if
4628  else
4629  call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv)
4630  end if
4631  divv(ixo^s)=qdt*wctprim(ixo^s,p_)*divv(ixo^s)
4632  where(w(ixo^s,e_)-divv(ixo^s)>small_e)
4633  w(ixo^s,e_)=w(ixo^s,e_)-divv(ixo^s)
4634  end where
4635  !w(ixO^S,e_)=w(ixO^S,e_)-qdt*wCTprim(ixO^S,p_)*divv(ixO^S)
4636  if(mhd_ambipolar)then
4637  call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x,e_)
4638  end if
4639 
4640  if(fix_small_values) then
4641  call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'add_source_internal_e')
4642  end if
4643  end subroutine add_source_internal_e
4644 
4645  !> Source terms for hydrodynamic energy version of MHD
4646  subroutine add_source_hydrodynamic_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
4648  use mod_geometry
4649  use mod_usr_methods, only: usr_gravity
4650 
4651  integer, intent(in) :: ixI^L, ixO^L
4652  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4653  double precision, intent(inout) :: w(ixI^S,1:nw)
4654  double precision, intent(in), optional :: wCTprim(ixI^S,1:nw)
4655 
4656  double precision :: B(ixI^S,3), J(ixI^S,3), JxB(ixI^S,3)
4657  double precision :: current(ixI^S,7-2*ndir:3)
4658  double precision :: bu(ixO^S,1:ndir), tmp(ixO^S), b2(ixO^S)
4659  double precision :: gravity_field(ixI^S,1:ndir), Vaoc
4660  integer :: idir, idirmin, idims, ix^D
4661 
4662  {^nothreed
4663  b=0.0d0
4664  do idir = 1, ndir
4665  b(ixo^s, idir) = wct(ixo^s,mag(idir))
4666  end do
4667 
4668  !call get_current(wCT,ixI^L,ixO^L,idirmin,current)
4669  call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
4670 
4671  j=0.0d0
4672  do idir=7-2*ndir,3
4673  j(ixo^s,idir)=current(ixo^s,idir)
4674  end do
4675 
4676  ! get Lorentz force JxB
4677  call cross_product(ixi^l,ixo^l,j,b,jxb)
4678  }
4679  {^ifthreed
4680  !call get_current(wCT,ixI^L,ixO^L,idirmin,current)
4681  ! get current in fourth order accuracy in Cartesian
4682  call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,1,ndir,.true.)
4683  ! get Lorentz force JxB
4684  call cross_product(ixi^l,ixo^l,current,wct(ixi^s,mag(1:ndir)),jxb)
4685  }
4686 
4687  if(mhd_semirelativistic) then
4688  ! (v . nabla) v
4689  do idir=1,ndir
4690  do idims=1,ndim
4691  call gradient(wctprim(ixi^s,mom(idir)),ixi^l,ixo^l,idims,j(ixi^s,idims))
4692  end do
4693  b(ixo^s,idir)=sum(wctprim(ixo^s,mom(1:ndir))*j(ixo^s,1:ndir),dim=ndim+1)
4694  end do
4695  ! nabla p
4696  do idir=1,ndir
4697  call gradient(wctprim(ixi^s,p_),ixi^l,ixo^l,idir,j(ixi^s,idir))
4698  end do
4699 
4700  if(mhd_gravity) then
4701  gravity_field=0.d0
4702  call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field(ixi^s,1:ndim))
4703  do idir=1,ndir
4704  b(ixo^s,idir)=wct(ixo^s,rho_)*(b(ixo^s,idir)-gravity_field(ixo^s,idir))+j(ixo^s,idir)-jxb(ixo^s,idir)
4705  end do
4706  else
4707  do idir=1,ndir
4708  b(ixo^s,idir)=wct(ixo^s,rho_)*b(ixo^s,idir)+j(ixo^s,idir)-jxb(ixo^s,idir)
4709  end do
4710  end if
4711 
4712  b2(ixo^s)=sum(wct(ixo^s,mag(:))**2,dim=ndim+1)
4713  tmp(ixo^s)=sqrt(b2(ixo^s))
4714  where(tmp(ixo^s)>smalldouble)
4715  tmp(ixo^s)=1.d0/tmp(ixo^s)
4716  else where
4717  tmp(ixo^s)=0.d0
4718  end where
4719  ! unit vector of magnetic field
4720  do idir=1,ndir
4721  bu(ixo^s,idir)=wct(ixo^s,mag(idir))*tmp(ixo^s)
4722  end do
4723 
4724  !b2(ixO^S)=b2(ixO^S)/w(ixO^S,rho_)*inv_squared_c
4725  !b2(ixO^S)=b2(ixO^S)/(1.d0+b2(ixO^S))
4726  {do ix^db=ixomin^db,ixomax^db\}
4727  ! Va^2/c^2
4728  vaoc=b2(ix^d)/w(ix^d,rho_)*inv_squared_c
4729  ! Va^2/c^2 / (1+Va^2/c^2)
4730  b2(ix^d)=vaoc/(1.d0+vaoc)
4731  {end do\}
4732  ! bu . F
4733  tmp(ixo^s)=sum(bu(ixo^s,1:ndir)*b(ixo^s,1:ndir),dim=ndim+1)
4734  ! Rempel 2017 ApJ 834, 10 equation (54)
4735  do idir=1,ndir
4736  j(ixo^s,idir)=b2(ixo^s)*(b(ixo^s,idir)-bu(ixo^s,idir)*tmp(ixo^s))
4737  end do
4738  !! Rempel 2017 ApJ 834, 10 equation (29) add SR force at momentum equation
4739  do idir=1,ndir
4740  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))+qdt*j(ixo^s,idir)
4741  end do
4742  ! Rempel 2017 ApJ 834, 10 equation (30) add work of Lorentz force and SR force
4743  w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*&
4744  (jxb(ixo^s,1:ndir)+j(ixo^s,1:ndir)),dim=ndim+1)
4745  else
4746  ! add work of Lorentz force
4747  w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*jxb(ixo^s,1:ndir),dim=ndim+1)
4748  end if
4749 
4750  end subroutine add_source_hydrodynamic_e
4751 
4752  !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
4753  !> each direction, non-conservative. If the fourthorder precompiler flag is
4754  !> set, uses fourth order central difference for the laplacian. Then the
4755  !> stencil is 5 (2 neighbours).
4756  subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
4758  use mod_usr_methods
4759  use mod_geometry
4760 
4761  integer, intent(in) :: ixI^L, ixO^L
4762  double precision, intent(in) :: qdt
4763  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4764  double precision, intent(inout) :: w(ixI^S,1:nw)
4765  integer :: ixA^L,idir,jdir,kdir,idirmin,idim,jxO^L,hxO^L,ix
4766  integer :: lxO^L, kxO^L
4767 
4768  double precision :: tmp(ixI^S),tmp2(ixI^S)
4769 
4770  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
4771  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S)
4772  double precision :: gradeta(ixI^S,1:ndim), Bf(ixI^S,1:ndir)
4773 
4774  ! Calculating resistive sources involve one extra layer
4775  if (mhd_4th_order) then
4776  ixa^l=ixo^l^ladd2;
4777  else
4778  ixa^l=ixo^l^ladd1;
4779  end if
4780 
4781  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
4782  call mpistop("Error in add_source_res1: Non-conforming input limits")
4783 
4784  ! Calculate current density and idirmin
4785  call get_current(wct,ixi^l,ixo^l,idirmin,current)
4786 
4787  if (mhd_eta>zero)then
4788  eta(ixa^s)=mhd_eta
4789  gradeta(ixo^s,1:ndim)=zero
4790  else
4791  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
4792  ! assumes that eta is not function of current?
4793  do idim=1,ndim
4794  call gradient(eta,ixi^l,ixo^l,idim,tmp)
4795  gradeta(ixo^s,idim)=tmp(ixo^s)
4796  end do
4797  end if
4798 
4799  if(b0field) then
4800  bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
4801  else
4802  bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
4803  end if
4804 
4805  do idir=1,ndir
4806  ! Put B_idir into tmp2 and eta*Laplace B_idir into tmp
4807  if (mhd_4th_order) then
4808  tmp(ixo^s)=zero
4809  tmp2(ixi^s)=bf(ixi^s,idir)
4810  do idim=1,ndim
4811  lxo^l=ixo^l+2*kr(idim,^d);
4812  jxo^l=ixo^l+kr(idim,^d);
4813  hxo^l=ixo^l-kr(idim,^d);
4814  kxo^l=ixo^l-2*kr(idim,^d);
4815  tmp(ixo^s)=tmp(ixo^s)+&
4816  (-tmp2(lxo^s)+16.0d0*tmp2(jxo^s)-30.0d0*tmp2(ixo^s)+16.0d0*tmp2(hxo^s)-tmp2(kxo^s)) &
4817  /(12.0d0 * dxlevel(idim)**2)
4818  end do
4819  else
4820  tmp(ixo^s)=zero
4821  tmp2(ixi^s)=bf(ixi^s,idir)
4822  do idim=1,ndim
4823  jxo^l=ixo^l+kr(idim,^d);
4824  hxo^l=ixo^l-kr(idim,^d);
4825  tmp(ixo^s)=tmp(ixo^s)+&
4826  (tmp2(jxo^s)-2.0d0*tmp2(ixo^s)+tmp2(hxo^s))/dxlevel(idim)**2
4827  end do
4828  end if
4829 
4830  ! Multiply by eta
4831  tmp(ixo^s)=tmp(ixo^s)*eta(ixo^s)
4832 
4833  ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
4834  if (mhd_eta<zero)then
4835  do jdir=1,ndim; do kdir=idirmin,3
4836  if (lvc(idir,jdir,kdir)/=0)then
4837  if (lvc(idir,jdir,kdir)==1)then
4838  tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
4839  else
4840  tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
4841  end if
4842  end if
4843  end do; end do
4844  end if
4845 
4846  ! Add sources related to eta*laplB-grad(eta) x J to B and e
4847  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
4848  if(total_energy) then
4849  w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
4850  end if
4851  end do ! idir
4852 
4853  if(mhd_energy) then
4854  ! de/dt+=eta*J**2
4855  w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
4856  end if
4857 
4858  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
4859 
4860  end subroutine add_source_res1
4861 
4862  !> Add resistive source to w within ixO
4863  !> Uses 5 point stencil (2 neighbours) in each direction, conservative
4864  subroutine add_source_res2(qdt,ixI^L,ixO^L,wCT,w,x)
4866  use mod_usr_methods
4867  use mod_geometry
4868 
4869  integer, intent(in) :: ixI^L, ixO^L
4870  double precision, intent(in) :: qdt
4871  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4872  double precision, intent(inout) :: w(ixI^S,1:nw)
4873 
4874  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
4875  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S),curlj(ixI^S,1:3)
4876  double precision :: tmpvec(ixI^S,1:3),tmp(ixO^S)
4877  integer :: ixA^L,idir,idirmin,idirmin1
4878 
4879  ixa^l=ixo^l^ladd2;
4880 
4881  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
4882  call mpistop("Error in add_source_res2: Non-conforming input limits")
4883 
4884  ixa^l=ixo^l^ladd1;
4885  ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
4886  ! Determine exact value of idirmin while doing the loop.
4887  call get_current(wct,ixi^l,ixa^l,idirmin,current)
4888 
4889  tmpvec=zero
4890  if(mhd_eta>zero)then
4891  do idir=idirmin,3
4892  tmpvec(ixa^s,idir)=current(ixa^s,idir)*mhd_eta
4893  end do
4894  else
4895  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
4896  do idir=idirmin,3
4897  tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
4898  end do
4899  end if
4900 
4901  ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
4902  call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
4903  if(stagger_grid) then
4904  if(ndim==2.and.ndir==3) then
4905  ! if 2.5D
4906  w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
4907  end if
4908  else
4909  w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
4910  end if
4911 
4912  if(mhd_energy) then
4913  if(mhd_eta>zero)then
4914  tmp(ixo^s)=qdt*mhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
4915  else
4916  tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
4917  end if
4918  if(total_energy) then
4919  ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
4920  ! de1/dt= eta J^2 - B1 dot curl(eta J)
4921  w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
4922  qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
4923  else
4924  ! add eta*J**2 source term in the internal energy equation
4925  w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
4926  end if
4927  end if
4928 
4929  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res2')
4930  end subroutine add_source_res2
4931 
4932  !> Add Hyper-resistive source to w within ixO
4933  !> Uses 9 point stencil (4 neighbours) in each direction.
4934  subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
4936  use mod_geometry
4937 
4938  integer, intent(in) :: ixI^L, ixO^L
4939  double precision, intent(in) :: qdt
4940  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4941  double precision, intent(inout) :: w(ixI^S,1:nw)
4942  !.. local ..
4943  double precision :: current(ixI^S,7-2*ndir:3)
4944  double precision :: tmpvec(ixI^S,1:3),tmpvec2(ixI^S,1:3),tmp(ixI^S),ehyper(ixI^S,1:3)
4945  integer :: ixA^L,idir,jdir,kdir,idirmin,idirmin1
4946 
4947  ixa^l=ixo^l^ladd3;
4948  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
4949  call mpistop("Error in add_source_hyperres: Non-conforming input limits")
4950 
4951  call get_current(wct,ixi^l,ixa^l,idirmin,current)
4952  tmpvec(ixa^s,1:ndir)=zero
4953  do jdir=idirmin,3
4954  tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
4955  end do
4956 
4957  ixa^l=ixo^l^ladd2;
4958  call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
4959 
4960  ixa^l=ixo^l^ladd1;
4961  tmpvec(ixa^s,1:ndir)=zero
4962  call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
4963  ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mhd_eta_hyper
4964 
4965  ixa^l=ixo^l;
4966  tmpvec2(ixa^s,1:ndir)=zero
4967  call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
4968 
4969  do idir=1,ndir
4970  w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
4971  end do
4972 
4973  if(total_energy) then
4974  ! de/dt= +div(B x Ehyper)
4975  ixa^l=ixo^l^ladd1;
4976  tmpvec2(ixa^s,1:ndir)=zero
4977  do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
4978  tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
4979  + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
4980  end do; end do; end do
4981  tmp(ixo^s)=zero
4982  call divvector(tmpvec2,ixi^l,ixo^l,tmp)
4983  w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
4984  end if
4985 
4986  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
4987 
4988  end subroutine add_source_hyperres
4989 
4990  subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
4991  ! Add divB related sources to w within ixO
4992  ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
4993  ! giving the EGLM-MHD scheme or GLM-MHD scheme
4995  use mod_geometry
4996 
4997  integer, intent(in) :: ixI^L, ixO^L
4998  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
4999  double precision, intent(inout) :: w(ixI^S,1:nw)
5000 
5001  double precision:: divb(ixI^S)
5002  double precision :: gradPsi(ixI^S)
5003  integer :: idim,idir
5004 
5005 
5006  ! dPsi/dt = - Ch^2/Cp^2 Psi
5007  if (mhd_glm_alpha < zero) then
5008  w(ixo^s,psi_) = abs(mhd_glm_alpha)*wct(ixo^s,psi_)
5009  else
5010  ! implicit update of Psi variable
5011  ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
5012  if(slab_uniform) then
5013  w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
5014  else
5015  w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
5016  end if
5017  end if
5018 
5019  if(mhd_glm_extended) then
5020  ! gradient of Psi
5021  if(total_energy) then
5022  do idim=1,ndim
5023  select case(typegrad)
5024  case("central")
5025  call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
5026  case("limited")
5027  call gradients(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
5028  end select
5029  ! e = e -qdt (b . grad(Psi))
5030  w(ixo^s,e_) = w(ixo^s,e_)-qdt*wct(ixo^s,mag(idim))*gradpsi(ixo^s)
5031  end do
5032  end if
5033 
5034  ! We calculate now div B
5035  call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_4thorder)
5036 
5037  ! m = m - qdt b div b
5038  do idir=1,ndir
5039  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*mhd_mag_i_all(w,ixi^l,ixo^l,idir)*divb(ixo^s)
5040  end do
5041  end if
5042 
5043  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
5044 
5045  end subroutine add_source_glm
5046 
5047  !> Add divB related sources to w within ixO corresponding to Powel
5048  subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
5050 
5051  integer, intent(in) :: ixI^L, ixO^L
5052  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
5053  double precision, intent(inout) :: w(ixI^S,1:nw)
5054  double precision :: divb(ixI^S),v(ixI^S,1:ndir)
5055  integer :: idir
5056 
5057  ! We calculate now div B
5058  call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_4thorder)
5059 
5060  ! calculate velocity
5061  call mhd_get_v(wct,x,ixi^l,ixo^l,v)
5062 
5063  if (total_energy) then
5064  ! e = e - qdt (v . b) * div b
5065  w(ixo^s,e_)=w(ixo^s,e_)-&
5066  qdt*sum(v(ixo^s,:)*wct(ixo^s,mag(:)),dim=ndim+1)*divb(ixo^s)
5067  end if
5068 
5069  ! b = b - qdt v * div b
5070  do idir=1,ndir
5071  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*v(ixo^s,idir)*divb(ixo^s)
5072  end do
5073 
5074  ! m = m - qdt b div b
5075  do idir=1,ndir
5076  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*mhd_mag_i_all(w,ixi^l,ixo^l,idir)*divb(ixo^s)
5077  end do
5078 
5079  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
5080 
5081  end subroutine add_source_powel
5082 
5083  subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
5084  ! Add divB related sources to w within ixO
5085  ! corresponding to Janhunen, just the term in the induction equation.
5087 
5088  integer, intent(in) :: ixI^L, ixO^L
5089  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
5090  double precision, intent(inout) :: w(ixI^S,1:nw)
5091  double precision :: divb(ixI^S),vel(ixI^S,1:ndir)
5092  integer :: idir
5093 
5094  ! We calculate now div B
5095  call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_4thorder)
5096 
5097  call mhd_get_v(wct,x,ixi^l,ixo^l,vel)
5098  ! b = b - qdt v * div b
5099  do idir=1,ndir
5100  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*vel(ixo^s,idir)*divb(ixo^s)
5101  end do
5102 
5103  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
5104 
5105  end subroutine add_source_janhunen
5106 
5107  subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
5108  ! Add Linde's divB related sources to wnew within ixO
5110  use mod_geometry
5111 
5112  integer, intent(in) :: ixI^L, ixO^L
5113  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
5114  double precision, intent(inout) :: w(ixI^S,1:nw)
5115 
5116  double precision :: divb(ixI^S),graddivb(ixI^S)
5117  integer :: idim, idir, ixp^L, i^D, iside
5118  logical, dimension(-1:1^D&) :: leveljump
5119 
5120  ! Calculate div B
5121  ixp^l=ixo^l^ladd1;
5122  call get_divb(wct,ixi^l,ixp^l,divb, mhd_divb_4thorder)
5123 
5124  ! for AMR stability, retreat one cell layer from the boarders of level jump
5125  {do i^db=-1,1\}
5126  if(i^d==0|.and.) cycle
5127  if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
5128  leveljump(i^d)=.true.
5129  else
5130  leveljump(i^d)=.false.
5131  end if
5132  {end do\}
5133 
5134  ixp^l=ixo^l;
5135  do idim=1,ndim
5136  select case(idim)
5137  {case(^d)
5138  do iside=1,2
5139  i^dd=kr(^dd,^d)*(2*iside-3);
5140  if (leveljump(i^dd)) then
5141  if (iside==1) then
5142  ixpmin^d=ixomin^d-i^d
5143  else
5144  ixpmax^d=ixomax^d-i^d
5145  end if
5146  end if
5147  end do
5148  \}
5149  end select
5150  end do
5151 
5152  ! Add Linde's diffusive terms
5153  do idim=1,ndim
5154  ! Calculate grad_idim(divb)
5155  select case(typegrad)
5156  case("central")
5157  call gradient(divb,ixi^l,ixp^l,idim,graddivb)
5158  case("limited")
5159  call gradients(divb,ixi^l,ixp^l,idim,graddivb)
5160  end select
5161 
5162  ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
5163  if (slab_uniform) then
5164  graddivb(ixp^s)=graddivb(ixp^s)*divbdiff/(^d&1.0d0/dxlevel(^d)**2+)
5165  else
5166  graddivb(ixp^s)=graddivb(ixp^s)*divbdiff &
5167  /(^d&1.0d0/block%ds(ixp^s,^d)**2+)
5168  end if
5169 
5170  w(ixp^s,mag(idim))=w(ixp^s,mag(idim))+graddivb(ixp^s)
5171 
5172  if (typedivbdiff=='all' .and. total_energy) then
5173  ! e += B_idim*eta*grad_idim(divb)
5174  w(ixp^s,e_)=w(ixp^s,e_)+wct(ixp^s,mag(idim))*graddivb(ixp^s)
5175  end if
5176  end do
5177 
5178  if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
5179 
5180  end subroutine add_source_linde
5181 
5182 
5183  !> get dimensionless div B = |divB| * volume / area / |B|
5184  subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
5185 
5187 
5188  integer, intent(in) :: ixi^l, ixo^l
5189  double precision, intent(in) :: w(ixi^s,1:nw)
5190  double precision :: divb(ixi^s), dsurface(ixi^s)
5191 
5192  double precision :: invb(ixo^s)
5193  integer :: ixa^l,idims
5194 
5195  call get_divb(w,ixi^l,ixo^l,divb)
5196  invb(ixo^s)=sqrt(mhd_mag_en_all(w,ixi^l,ixo^l))
5197  where(invb(ixo^s)/=0.d0)
5198  invb(ixo^s)=1.d0/invb(ixo^s)
5199  end where
5200  if(slab_uniform) then
5201  divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
5202  else
5203  ixamin^d=ixomin^d-1;
5204  ixamax^d=ixomax^d-1;
5205  dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
5206  do idims=1,ndim
5207  ixa^l=ixo^l-kr(idims,^d);
5208  dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
5209  end do
5210  divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
5211  block%dvolume(ixo^s)/dsurface(ixo^s)
5212  end if
5213 
5214  end subroutine get_normalized_divb
5215 
5216  !> Calculate idirmin and the idirmin:3 components of the common current array
5217  !> make sure that dxlevel(^D) is set correctly.
5218  subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
5220  use mod_geometry
5221 
5222  integer, intent(in) :: ixo^l, ixi^l
5223  double precision, intent(in) :: w(ixi^s,1:nw)
5224  integer, intent(out) :: idirmin
5225 
5226  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5227  double precision :: current(ixi^s,7-2*ndir:3)
5228  integer :: idir, idirmin0
5229 
5230  idirmin0 = 7-2*ndir
5231 
5232  call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
5233 
5234  if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
5235  block%J0(ixo^s,idirmin0:3)
5236  end subroutine get_current
5237 
5238  !> If resistivity is not zero, check diffusion time limit for dt
5239  subroutine mhd_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
5241  use mod_usr_methods
5243  use mod_viscosity, only: viscosity_get_dt
5244  use mod_gravity, only: gravity_get_dt
5245  use mod_cak_force, only: cak_get_dt
5246 
5247  integer, intent(in) :: ixI^L, ixO^L
5248  double precision, intent(inout) :: dtnew
5249  double precision, intent(in) :: dx^D
5250  double precision, intent(in) :: w(ixI^S,1:nw)
5251  double precision, intent(in) :: x(ixI^S,1:ndim)
5252 
5253  double precision :: dxarr(ndim)
5254  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S)
5255  integer :: idirmin,idim
5256 
5257  dtnew = bigdouble
5258 
5259  ^d&dxarr(^d)=dx^d;
5260  if (mhd_eta>zero)then
5261  dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mhd_eta
5262  else if (mhd_eta<zero)then
5263  call get_current(w,ixi^l,ixo^l,idirmin,current)
5264  call usr_special_resistivity(w,ixi^l,ixo^l,idirmin,x,current,eta)
5265  dtnew=bigdouble
5266  do idim=1,ndim
5267  if(slab_uniform) then
5268  dtnew=min(dtnew,&
5269  dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
5270  else
5271  dtnew=min(dtnew,&
5272  dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
5273  end if
5274  end do
5275  end if
5276 
5277  if(mhd_eta_hyper>zero) then
5278  if(slab_uniform) then
5279  dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mhd_eta_hyper,dtnew)
5280  else
5281  dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mhd_eta_hyper,dtnew)
5282  end if
5283  end if
5284 
5285  if(mhd_radiative_cooling) then
5286  call cooling_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x,rc_fl)
5287  end if
5288 
5289  if(mhd_viscosity) then
5290  call viscosity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
5291  end if
5292 
5293  if(mhd_gravity) then
5294  call gravity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
5295  end if
5296 
5297  if(mhd_ambipolar_exp) then
5298  dtnew=min(dtdiffpar*get_ambipolar_dt(w,ixi^l,ixo^l,dx^d,x),dtnew)
5299  endif
5300 
5301  if (mhd_cak_force) then
5302  call cak_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
5303  end if
5304 
5305  end subroutine mhd_get_dt
5306 
5307  ! Add geometrical source terms to w
5308  subroutine mhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
5310  use mod_geometry
5312 
5313  integer, intent(in) :: ixI^L, ixO^L
5314  double precision, intent(in) :: qdt, dtfactor,x(ixI^S,1:ndim)
5315  double precision, intent(inout) :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
5316 
5317  double precision :: tmp(ixI^S),tmp1(ixI^S),tmp2(ixI^S),invrho(ixO^S),invr(ixO^S)
5318  integer :: iw,idir, h1x^L{^NOONED, h2x^L}
5319  integer :: mr_,mphi_ ! Polar var. names
5320  integer :: br_,bphi_
5321 
5322  mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
5323  br_=mag(1); bphi_=mag(1)-1+phi_
5324 
5325  ! 1/rho
5326  invrho(ixo^s)=1.d0/wct(ixo^s,rho_)
5327  ! include dt in invr, invr is always used with qdt
5328  if(local_timestep) then
5329  invr(ixo^s) = block%dt(ixo^s) * dtfactor/x(ixo^s,1)
5330  else
5331  invr(ixo^s) = qdt/x(ixo^s,1)
5332  endif
5333 
5334 
5335  select case (coordinate)
5336  case (cylindrical)
5337  call mhd_get_p_total(wct,x,ixi^l,ixo^l,tmp)
5338  if(phi_>0) then
5339  w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*(tmp(ixo^s)-&
5340  wct(ixo^s,bphi_)**2+wct(ixo^s,mphi_)**2*invrho(ixo^s))
5341  w(ixo^s,mphi_)=w(ixo^s,mphi_)+invr(ixo^s)*(&
5342  -wct(ixo^s,mphi_)*wct(ixo^s,mr_)*invrho(ixo^s) &
5343  +wct(ixo^s,bphi_)*wct(ixo^s,br_))
5344  if(.not.stagger_grid) then
5345  w(ixo^s,bphi_)=w(ixo^s,bphi_)+invr(ixo^s)*&
5346  (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
5347  -wct(ixo^s,br_)*wct(ixo^s,mphi_)) &
5348  *invrho(ixo^s)
5349  end if
5350  else
5351  w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*tmp(ixo^s)
5352  end if
5353  if(mhd_glm) w(ixo^s,br_)=w(ixo^s,br_)+wct(ixo^s,psi_)*invr(ixo^s)
5354  case (spherical)
5355  h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
5356  call mhd_get_p_total(wct,x,ixi^l,ixo^l,tmp1)
5357  ! m1
5358  tmp(ixo^s)=tmp1(ixo^s)*x(ixo^s,1) &
5359  *(block%surfaceC(ixo^s,1)-block%surfaceC(h1x^s,1))/block%dvolume(ixo^s)
5360  do idir=2,ndir
5361  tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom(idir))**2*invrho(ixo^s)-wct(ixo^s,mag(idir))**2
5362  end do
5363  w(ixo^s,mom(1))=w(ixo^s,mom(1))+tmp(ixo^s)*invr(ixo^s)
5364  ! b1
5365  if(mhd_glm) then
5366  w(ixo^s,mag(1))=w(ixo^s,mag(1))+invr(ixo^s)*2.0d0*wct(ixo^s,psi_)
5367  end if
5368 
5369  {^nooned
5370  ! m2
5371  ! This will make hydrostatic p=const an exact solution
5372  if(local_timestep) then
5373  tmp(ixo^s) = block%dt(ixo^s) * tmp1(ixo^s)
5374  else
5375  tmp(ixo^s) = qdt * tmp1(ixo^s)
5376  endif
5377  w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp(ixo^s) &
5378  *(block%surfaceC(ixo^s,2)-block%surfaceC(h2x^s,2)) &
5379  /block%dvolume(ixo^s)
5380  tmp(ixo^s)=-(wct(ixo^s,mom(1))*wct(ixo^s,mom(2))*invrho(ixo^s) &
5381  -wct(ixo^s,mag(1))*wct(ixo^s,mag(2)))
5382  if(ndir==3) then
5383  tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(3))**2*invrho(ixo^s) &
5384  -wct(ixo^s,mag(3))**2)*dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
5385  end if
5386  w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp(ixo^s)*invr(ixo^s)
5387  ! b2
5388  if(.not.stagger_grid) then
5389  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
5390  -wct(ixo^s,mom(2))*wct(ixo^s,mag(1)))*invrho(ixo^s)
5391  if(mhd_glm) then
5392  tmp(ixo^s)=tmp(ixo^s) &
5393  + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
5394  end if
5395  w(ixo^s,mag(2))=w(ixo^s,mag(2))+tmp(ixo^s)*invr(ixo^s)
5396  end if
5397  }
5398 
5399  if(ndir==3) then
5400  ! m3
5401  tmp(ixo^s)=-(wct(ixo^s,mom(3))*wct(ixo^s,mom(1))*invrho(ixo^s) &
5402  -wct(ixo^s,mag(3))*wct(ixo^s,mag(1))) {^nooned &
5403  -(wct(ixo^s,mom(2))*wct(ixo^s,mom(3))*invrho(ixo^s) &
5404  -wct(ixo^s,mag(2))*wct(ixo^s,mag(3))) &
5405  *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
5406  w(ixo^s,mom(3))=w(ixo^s,mom(3))+tmp(ixo^s)*invr(ixo^s)
5407  ! b3
5408  if(.not.stagger_grid) then
5409  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
5410  -wct(ixo^s,mom(3))*wct(ixo^s,mag(1)))*invrho(ixo^s) {^nooned &
5411  -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
5412  -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
5413  /(wct(ixo^s,rho_)*dsin(x(ixo^s,2))) }
5414  w(ixo^s,mag(3))=w(ixo^s,mag(3))+tmp(ixo^s)*invr(ixo^s)
5415  end if
5416  end if
5417  end select
5418 
5419  if (mhd_rotating_frame) then
5420  call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wct,w,x)
5421  endif
5422 
5423  end subroutine mhd_add_source_geom
5424 
5425  ! Add geometrical source terms to w
5426  subroutine mhd_add_source_geom_split(qdt,dtfactor, ixI^L,ixO^L,wCT,w,x)
5428  use mod_geometry
5429 
5430  integer, intent(in) :: ixI^L, ixO^L
5431  double precision, intent(in) :: qdt, dtfactor, x(ixI^S,1:ndim)
5432  double precision, intent(inout) :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
5433 
5434  double precision :: tmp(ixI^S),tmp1(ixI^S),tmp2(ixI^S),invrho(ixO^S),invr(ixO^S)
5435  integer :: iw,idir, h1x^L{^NOONED, h2x^L}
5436  integer :: mr_,mphi_ ! Polar var. names
5437  integer :: br_,bphi_
5438 
5439  mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
5440  br_=mag(1); bphi_=mag(1)-1+phi_
5441 
5442  if(has_equi_rho0) then
5443  invrho(ixo^s) = 1d0/(wct(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i))
5444  else
5445  invrho(ixo^s) = 1d0/wct(ixo^s,rho_)
5446  end if
5447  ! include dt in invr, invr is always used with qdt
5448  if(local_timestep) then
5449  invr(ixo^s) = block%dt(ixo^s) * dtfactor/x(ixo^s,1)
5450  else
5451  invr(ixo^s) = qdt/x(ixo^s,1)
5452  endif
5453 
5454  select case (coordinate)
5455  case (cylindrical)
5456  call mhd_get_p_total(wct,x,ixi^l,ixo^l,tmp)
5457  if(phi_>0) then
5458  w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*(tmp(ixo^s)-&
5459  wct(ixo^s,bphi_)**2+wct(ixo^s,mphi_)**2*invrho(ixo^s))
5460  w(ixo^s,mphi_)=w(ixo^s,mphi_)+qdt*invr(ixo^s)*(&
5461  -wct(ixo^s,mphi_)*wct(ixo^s,mr_)*invrho(ixo^s) &
5462  +wct(ixo^s,bphi_)*wct(ixo^s,br_))
5463  if(.not.stagger_grid) then
5464  w(ixo^s,bphi_)=w(ixo^s,bphi_)+invr(ixo^s)*&
5465  (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
5466  -wct(ixo^s,br_)*wct(ixo^s,mphi_)) &
5467  *invrho(ixo^s)
5468  end if
5469  else
5470  w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*tmp(ixo^s)
5471  end if
5472  if(mhd_glm) w(ixo^s,br_)=w(ixo^s,br_)+wct(ixo^s,psi_)*invr(ixo^s)
5473  case (spherical)
5474  h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
5475  call mhd_get_p_total(wct,x,ixi^l,ixo^l,tmp1)
5476  tmp(ixo^s)=tmp1(ixo^s)
5477  if(b0field) then
5478  tmp2(ixo^s)=sum(block%B0(ixo^s,:,0)*wct(ixo^s,mag(:)),dim=ndim+1)
5479  tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
5480  end if
5481  ! m1
5482  tmp(ixo^s)=tmp(ixo^s)*x(ixo^s,1) &
5483  *(block%surfaceC(ixo^s,1)-block%surfaceC(h1x^s,1))/block%dvolume(ixo^s)
5484  if(ndir>1) then
5485  do idir=2,ndir
5486  tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom(idir))**2*invrho(ixo^s)-wct(ixo^s,mag(idir))**2
5487  if(b0field) tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,idir,0)*wct(ixo^s,mag(idir))
5488  end do
5489  end if
5490  w(ixo^s,mom(1))=w(ixo^s,mom(1))+tmp(ixo^s)*invr(ixo^s)
5491  ! b1
5492  if(mhd_glm) then
5493  w(ixo^s,mag(1))=w(ixo^s,mag(1))+invr(ixo^s)*2.0d0*wct(ixo^s,psi_)
5494  end if
5495 
5496  {^nooned
5497  ! m2
5498  tmp(ixo^s)=tmp1(ixo^s)
5499  if(b0field) then
5500  tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
5501  end if
5502  if(local_timestep) then
5503  tmp1(ixo^s) = block%dt(ixo^s) * tmp(ixo^s)
5504  else
5505  tmp1(ixo^s) = qdt * tmp(ixo^s)
5506  endif
5507  ! This will make hydrostatic p=const an exact solution
5508  w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp1(ixo^s) &
5509  *(block%surfaceC(ixo^s,2)-block%surfaceC(h2x^s,2)) &
5510  /block%dvolume(ixo^s)
5511  tmp(ixo^s)=-(wct(ixo^s,mom(1))*wct(ixo^s,mom(2))*invrho(ixo^s) &
5512  -wct(ixo^s,mag(1))*wct(ixo^s,mag(2)))
5513  if (b0field) then
5514  tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(2)) &
5515  +wct(ixo^s,mag(1))*block%B0(ixo^s,2,0)
5516  end if
5517  if(ndir==3) then
5518  tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(3))**2*invrho(ixo^s) &
5519  -wct(ixo^s,mag(3))**2)*dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
5520  if (b0field) then
5521  tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,3,0)*wct(ixo^s,mag(3))&
5522  *dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
5523  end if
5524  end if
5525  w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp(ixo^s)*invr(ixo^s)
5526  ! b2
5527  if(.not.stagger_grid) then
5528  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
5529  -wct(ixo^s,mom(2))*wct(ixo^s,mag(1)))*invrho(ixo^s)
5530  if(b0field) then
5531  tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(1))*block%B0(ixo^s,2,0) &
5532  -wct(ixo^s,mom(2))*block%B0(ixo^s,1,0))*invrho(ixo^s)
5533  end if
5534  if(mhd_glm) then
5535  tmp(ixo^s)=tmp(ixo^s) &
5536  + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
5537  end if
5538  w(ixo^s,mag(2))=w(ixo^s,mag(2))+tmp(ixo^s)*invr(ixo^s)
5539  end if
5540  }
5541 
5542  if(ndir==3) then
5543  ! m3
5544  tmp(ixo^s)=-(wct(ixo^s,mom(3))*wct(ixo^s,mom(1))*invrho(ixo^s) &
5545  -wct(ixo^s,mag(3))*wct(ixo^s,mag(1))) {^nooned &
5546  -(wct(ixo^s,mom(2))*wct(ixo^s,mom(3))*invrho(ixo^s) &
5547  -wct(ixo^s,mag(2))*wct(ixo^s,mag(3))) &
5548  *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
5549  if (b0field) then
5550  tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(3)) &
5551  +wct(ixo^s,mag(1))*block%B0(ixo^s,3,0) {^nooned &
5552  +(block%B0(ixo^s,2,0)*wct(ixo^s,mag(3)) &
5553  +wct(ixo^s,mag(2))*block%B0(ixo^s,3,0)) &
5554  *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
5555  end if
5556  w(ixo^s,mom(3))=w(ixo^s,mom(3))+tmp(ixo^s)*invr(ixo^s)
5557  ! b3
5558  if(.not.stagger_grid) then
5559  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
5560  -wct(ixo^s,mom(3))*wct(ixo^s,mag(1)))*invrho(ixo^s) {^nooned &
5561  -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
5562  -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
5563  *invrho(ixo^s)/dsin(x(ixo^s,2)) }
5564  if (b0field) then
5565  tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(1))*block%B0(ixo^s,3,0) &
5566  -wct(ixo^s,mom(3))*block%B0(ixo^s,1,0))*invrho(ixo^s){^nooned &
5567  -(wct(ixo^s,mom(3))*block%B0(ixo^s,2,0) &
5568  -wct(ixo^s,mom(2))*block%B0(ixo^s,3,0))*dcos(x(ixo^s,2)) &
5569  *invrho(ixo^s)/dsin(x(ixo^s,2)) }
5570  end if
5571  w(ixo^s,mag(3))=w(ixo^s,mag(3))+tmp(ixo^s)*invr(ixo^s)
5572  end if
5573  end if
5574  end select
5575  end subroutine mhd_add_source_geom_split
5576 
5577  !> Compute 2 times total magnetic energy
5578  function mhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
5580  integer, intent(in) :: ixi^l, ixo^l
5581  double precision, intent(in) :: w(ixi^s, nw)
5582  double precision :: mge(ixo^s)
5583 
5584  if (b0field) then
5585  mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
5586  else
5587  mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
5588  end if
5589  end function mhd_mag_en_all
5590 
5591  !> Compute full magnetic field by direction
5592  function mhd_mag_i_all(w, ixI^L, ixO^L,idir) result(mgf)
5594  integer, intent(in) :: ixi^l, ixo^l, idir
5595  double precision, intent(in) :: w(ixi^s, nw)
5596  double precision :: mgf(ixo^s)
5597 
5598  if (b0field) then
5599  mgf = w(ixo^s, mag(idir))+block%B0(ixo^s,idir,b0i)
5600  else
5601  mgf = w(ixo^s, mag(idir))
5602  end if
5603  end function mhd_mag_i_all
5604 
5605  !> Compute evolving magnetic energy
5606  function mhd_mag_en(w, ixI^L, ixO^L) result(mge)
5607  use mod_global_parameters, only: nw, ndim
5608  integer, intent(in) :: ixi^l, ixo^l
5609  double precision, intent(in) :: w(ixi^s, nw)
5610  double precision :: mge(ixo^s)
5611 
5612  mge = 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
5613  end function mhd_mag_en
5614 
5615  !> compute kinetic energy
5616  function mhd_kin_en_origin(w, ixI^L, ixO^L, inv_rho) result(ke)
5617  use mod_global_parameters, only: nw, ndim,block
5618  integer, intent(in) :: ixi^l, ixo^l
5619  double precision, intent(in) :: w(ixi^s, nw)
5620  double precision, intent(in), optional :: inv_rho(ixo^s)
5621  double precision :: ke(ixo^s)
5622 
5623  if (present(inv_rho)) then
5624  ke = 0.5d0 * sum(w(ixo^s, mom(:))**2, dim=ndim+1) * inv_rho
5625  else
5626  if(has_equi_rho0) then
5627  ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom(:))**2, dim=ndim+1) / (w(ixo^s, rho_) + block%equi_vars(ixo^s,equi_rho0_,0))
5628  else
5629  ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom(:))**2, dim=ndim+1) / w(ixo^s, rho_)
5630  end if
5631  end if
5632  end function mhd_kin_en_origin
5633 
5634  subroutine mhd_getv_hall(w,x,ixI^L,ixO^L,vHall)
5636 
5637  integer, intent(in) :: ixI^L, ixO^L
5638  double precision, intent(in) :: w(ixI^S,nw)
5639  double precision, intent(in) :: x(ixI^S,1:ndim)
5640  double precision, intent(inout) :: vHall(ixI^S,1:3)
5641 
5642  double precision :: current(ixI^S,7-2*ndir:3)
5643  double precision :: rho(ixI^S)
5644  integer :: idir, idirmin
5645 
5646  call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
5647  ! Calculate current density and idirmin
5648  call get_current(w,ixi^l,ixo^l,idirmin,current)
5649  vhall(ixo^s,1:3) = zero
5650  vhall(ixo^s,idirmin:3) = - mhd_etah*current(ixo^s,idirmin:3)
5651  do idir = idirmin, 3
5652  vhall(ixo^s,idir) = vhall(ixo^s,idir)/rho(ixo^s)
5653  end do
5654 
5655  end subroutine mhd_getv_hall
5656 
5657  subroutine mhd_get_jambi(w,x,ixI^L,ixO^L,res)
5659 
5660  integer, intent(in) :: ixI^L, ixO^L
5661  double precision, intent(in) :: w(ixI^S,nw)
5662  double precision, intent(in) :: x(ixI^S,1:ndim)
5663  double precision, allocatable, intent(inout) :: res(:^D&,:)
5664 
5665 
5666  double precision :: current(ixI^S,7-2*ndir:3)
5667  integer :: idir, idirmin
5668 
5669  res = 0d0
5670 
5671  ! Calculate current density and idirmin
5672  call get_current(w,ixi^l,ixo^l,idirmin,current)
5673 
5674  res(ixo^s,idirmin:3)=-current(ixo^s,idirmin:3)
5675  do idir = idirmin, 3
5676  call multiplyambicoef(ixi^l,ixo^l,res(ixi^s,idir),w,x)
5677  enddo
5678 
5679  end subroutine mhd_get_jambi
5680 
5681  subroutine mhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
5683  use mod_usr_methods
5684  integer, intent(in) :: ixI^L, ixO^L, idir
5685  double precision, intent(in) :: qt
5686  double precision, intent(inout) :: wLC(ixI^S,1:nw), wRC(ixI^S,1:nw)
5687  double precision, intent(inout) :: wLp(ixI^S,1:nw), wRp(ixI^S,1:nw)
5688  type(state) :: s
5689 
5690  double precision :: dB(ixI^S), dPsi(ixI^S)
5691 
5692  if(stagger_grid) then
5693  wlc(ixo^s,mag(idir))=s%ws(ixo^s,idir)
5694  wrc(ixo^s,mag(idir))=s%ws(ixo^s,idir)
5695  wlp(ixo^s,mag(idir))=s%ws(ixo^s,idir)
5696  wrp(ixo^s,mag(idir))=s%ws(ixo^s,idir)
5697  else
5698  ! Solve the Riemann problem for the linear 2x2 system for normal
5699  ! B-field and GLM_Psi according to Dedner 2002:
5700  ! This implements eq. (42) in Dedner et al. 2002 JcP 175
5701  ! Gives the Riemann solution on the interface
5702  ! for the normal B component and Psi in the GLM-MHD system.
5703  ! 23/04/2013 Oliver Porth
5704  db(ixo^s) = wrp(ixo^s,mag(idir)) - wlp(ixo^s,mag(idir))
5705  dpsi(ixo^s) = wrp(ixo^s,psi_) - wlp(ixo^s,psi_)
5706 
5707  wlp(ixo^s,mag(idir)) = 0.5d0 * (wrp(ixo^s,mag(idir)) + wlp(ixo^s,mag(idir))) &
5708  - 0.5d0/cmax_global * dpsi(ixo^s)
5709  wlp(ixo^s,psi_) = 0.5d0 * (wrp(ixo^s,psi_) + wlp(ixo^s,psi_)) &
5710  - 0.5d0*cmax_global * db(ixo^s)
5711 
5712  wrp(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5713  wrp(ixo^s,psi_) = wlp(ixo^s,psi_)
5714 
5715  if(total_energy) then
5716  wrc(ixo^s,e_)=wrc(ixo^s,e_)-half*wrc(ixo^s,mag(idir))**2
5717  wlc(ixo^s,e_)=wlc(ixo^s,e_)-half*wlc(ixo^s,mag(idir))**2
5718  end if
5719  wrc(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5720  wrc(ixo^s,psi_) = wlp(ixo^s,psi_)
5721  wlc(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5722  wlc(ixo^s,psi_) = wlp(ixo^s,psi_)
5723  ! modify total energy according to the change of magnetic field
5724  if(total_energy) then
5725  wrc(ixo^s,e_)=wrc(ixo^s,e_)+half*wrc(ixo^s,mag(idir))**2
5726  wlc(ixo^s,e_)=wlc(ixo^s,e_)+half*wlc(ixo^s,mag(idir))**2
5727  end if
5728  end if
5729 
5730  if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
5731 
5732  end subroutine mhd_modify_wlr
5733 
5734  subroutine mhd_boundary_adjust(igrid,psb)
5736  integer, intent(in) :: igrid
5737  type(state), target :: psb(max_blocks)
5738 
5739  integer :: iB, idims, iside, ixO^L, i^D
5740 
5741  block=>ps(igrid)
5742  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
5743  do idims=1,ndim
5744  ! to avoid using as yet unknown corner info in more than 1D, we
5745  ! fill only interior mesh ranges of the ghost cell ranges at first,
5746  ! and progressively enlarge the ranges to include corners later
5747  do iside=1,2
5748  i^d=kr(^d,idims)*(2*iside-3);
5749  if (neighbor_type(i^d,igrid)/=1) cycle
5750  ib=(idims-1)*2+iside
5751  if(.not.boundary_divbfix(ib)) cycle
5752  if(any(typeboundary(:,ib)==bc_special)) then
5753  ! MF nonlinear force-free B field extrapolation and data driven
5754  ! require normal B of the first ghost cell layer to be untouched by
5755  ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
5756  select case (idims)
5757  {case (^d)
5758  if (iside==2) then
5759  ! maximal boundary
5760  ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
5761  ixomax^dd=ixghi^dd;
5762  else
5763  ! minimal boundary
5764  ixomin^dd=ixglo^dd;
5765  ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
5766  end if \}
5767  end select
5768  call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
5769  end if
5770  end do
5771  end do
5772 
5773  end subroutine mhd_boundary_adjust
5774 
5775  subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
5777 
5778  integer, intent(in) :: ixG^L,ixO^L,iB
5779  double precision, intent(inout) :: w(ixG^S,1:nw)
5780  double precision, intent(in) :: x(ixG^S,1:ndim)
5781 
5782  double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
5783  integer :: ix^D,ixF^L
5784 
5785  select case(ib)
5786  case(1)
5787  ! 2nd order CD for divB=0 to set normal B component better
5788  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
5789  {^iftwod
5790  ixfmin1=ixomin1+1
5791  ixfmax1=ixomax1+1
5792  ixfmin2=ixomin2+1
5793  ixfmax2=ixomax2-1
5794  if(slab_uniform) then
5795  dx1x2=dxlevel(1)/dxlevel(2)
5796  do ix1=ixfmax1,ixfmin1,-1
5797  w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
5798  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
5799  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
5800  enddo
5801  else
5802  do ix1=ixfmax1,ixfmin1,-1
5803  w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
5804  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
5805  +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
5806  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
5807  -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
5808  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
5809  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
5810  end do
5811  end if
5812  }
5813  {^ifthreed
5814  ixfmin1=ixomin1+1
5815  ixfmax1=ixomax1+1
5816  ixfmin2=ixomin2+1
5817  ixfmax2=ixomax2-1
5818  ixfmin3=ixomin3+1
5819  ixfmax3=ixomax3-1
5820  if(slab_uniform) then
5821  dx1x2=dxlevel(1)/dxlevel(2)
5822  dx1x3=dxlevel(1)/dxlevel(3)
5823  do ix1=ixfmax1,ixfmin1,-1
5824  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5825  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
5826  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
5827  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
5828  +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
5829  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
5830  end do
5831  else
5832  do ix1=ixfmax1,ixfmin1,-1
5833  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5834  ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
5835  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
5836  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
5837  +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
5838  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
5839  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
5840  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
5841  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
5842  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
5843  +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
5844  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
5845  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
5846  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
5847  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5848  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
5849  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
5850  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
5851  end do
5852  end if
5853  }
5854  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
5855  case(2)
5856  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
5857  {^iftwod
5858  ixfmin1=ixomin1-1
5859  ixfmax1=ixomax1-1
5860  ixfmin2=ixomin2+1
5861  ixfmax2=ixomax2-1
5862  if(slab_uniform) then
5863  dx1x2=dxlevel(1)/dxlevel(2)
5864  do ix1=ixfmin1,ixfmax1
5865  w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
5866  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
5867  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
5868  enddo
5869  else
5870  do ix1=ixfmin1,ixfmax1
5871  w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
5872  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
5873  -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
5874  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
5875  +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
5876  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
5877  /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
5878  end do
5879  end if
5880  }
5881  {^ifthreed
5882  ixfmin1=ixomin1-1
5883  ixfmax1=ixomax1-1
5884  ixfmin2=ixomin2+1
5885  ixfmax2=ixomax2-1
5886  ixfmin3=ixomin3+1
5887  ixfmax3=ixomax3-1
5888  if(slab_uniform) then
5889  dx1x2=dxlevel(1)/dxlevel(2)
5890  dx1x3=dxlevel(1)/dxlevel(3)
5891  do ix1=ixfmin1,ixfmax1
5892  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5893  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
5894  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
5895  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
5896  -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
5897  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
5898  end do
5899  else
5900  do ix1=ixfmin1,ixfmax1
5901  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5902  ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
5903  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
5904  block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
5905  -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
5906  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
5907  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
5908  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
5909  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
5910  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
5911  -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
5912  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
5913  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
5914  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
5915  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5916  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
5917  /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
5918  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
5919  end do
5920  end if
5921  }
5922  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
5923  case(3)
5924  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
5925  {^iftwod
5926  ixfmin1=ixomin1+1
5927  ixfmax1=ixomax1-1
5928  ixfmin2=ixomin2+1
5929  ixfmax2=ixomax2+1
5930  if(slab_uniform) then
5931  dx2x1=dxlevel(2)/dxlevel(1)
5932  do ix2=ixfmax2,ixfmin2,-1
5933  w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
5934  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
5935  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
5936  enddo
5937  else
5938  do ix2=ixfmax2,ixfmin2,-1
5939  w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
5940  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
5941  +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
5942  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
5943  -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
5944  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
5945  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
5946  end do
5947  end if
5948  }
5949  {^ifthreed
5950  ixfmin1=ixomin1+1
5951  ixfmax1=ixomax1-1
5952  ixfmin3=ixomin3+1
5953  ixfmax3=ixomax3-1
5954  ixfmin2=ixomin2+1
5955  ixfmax2=ixomax2+1
5956  if(slab_uniform) then
5957  dx2x1=dxlevel(2)/dxlevel(1)
5958  dx2x3=dxlevel(2)/dxlevel(3)
5959  do ix2=ixfmax2,ixfmin2,-1
5960  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
5961  ix2+1,ixfmin3:ixfmax3,mag(2)) &
5962  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
5963  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
5964  +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
5965  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
5966  end do
5967  else
5968  do ix2=ixfmax2,ixfmin2,-1
5969  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
5970  ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
5971  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
5972  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
5973  +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
5974  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5975  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
5976  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
5977  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5978  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
5979  +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
5980  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
5981  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
5982  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
5983  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5984  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
5985  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
5986  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
5987  end do
5988  end if
5989  }
5990  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
5991  case(4)
5992  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
5993  {^iftwod
5994  ixfmin1=ixomin1+1
5995  ixfmax1=ixomax1-1
5996  ixfmin2=ixomin2-1
5997  ixfmax2=ixomax2-1
5998  if(slab_uniform) then
5999  dx2x1=dxlevel(2)/dxlevel(1)
6000  do ix2=ixfmin2,ixfmax2
6001  w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
6002  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
6003  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
6004  end do
6005  else
6006  do ix2=ixfmin2,ixfmax2
6007  w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
6008  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
6009  -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
6010  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
6011  +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
6012  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
6013  /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
6014  end do
6015  end if
6016  }
6017  {^ifthreed
6018  ixfmin1=ixomin1+1
6019  ixfmax1=ixomax1-1
6020  ixfmin3=ixomin3+1
6021  ixfmax3=ixomax3-1
6022  ixfmin2=ixomin2-1
6023  ixfmax2=ixomax2-1
6024  if(slab_uniform) then
6025  dx2x1=dxlevel(2)/dxlevel(1)
6026  dx2x3=dxlevel(2)/dxlevel(3)
6027  do ix2=ixfmin2,ixfmax2
6028  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
6029  ix2-1,ixfmin3:ixfmax3,mag(2)) &
6030  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
6031  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
6032  -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
6033  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
6034  end do
6035  else
6036  do ix2=ixfmin2,ixfmax2
6037  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
6038  ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
6039  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
6040  block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
6041  -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
6042  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
6043  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
6044  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
6045  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
6046  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
6047  -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
6048  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
6049  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
6050  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
6051  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
6052  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
6053  /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
6054  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
6055  end do
6056  end if
6057  }
6058  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
6059  {^ifthreed
6060  case(5)
6061  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
6062  ixfmin1=ixomin1+1
6063  ixfmax1=ixomax1-1
6064  ixfmin2=ixomin2+1
6065  ixfmax2=ixomax2-1
6066  ixfmin3=ixomin3+1
6067  ixfmax3=ixomax3+1
6068  if(slab_uniform) then
6069  dx3x1=dxlevel(3)/dxlevel(1)
6070  dx3x2=dxlevel(3)/dxlevel(2)
6071  do ix3=ixfmax3,ixfmin3,-1
6072  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
6073  ixfmin2:ixfmax2,ix3+1,mag(3)) &
6074  +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
6075  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
6076  +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
6077  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
6078  end do
6079  else
6080  do ix3=ixfmax3,ixfmin3,-1
6081  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
6082  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
6083  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
6084  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
6085  +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
6086  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
6087  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
6088  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
6089  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
6090  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
6091  +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
6092  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
6093  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
6094  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
6095  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
6096  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
6097  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
6098  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
6099  end do
6100  end if
6101  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
6102  case(6)
6103  if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
6104  ixfmin1=ixomin1+1
6105  ixfmax1=ixomax1-1
6106  ixfmin2=ixomin2+1
6107  ixfmax2=ixomax2-1
6108  ixfmin3=ixomin3-1
6109  ixfmax3=ixomax3-1
6110  if(slab_uniform) then
6111  dx3x1=dxlevel(3)/dxlevel(1)
6112  dx3x2=dxlevel(3)/dxlevel(2)
6113  do ix3=ixfmin3,ixfmax3
6114  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
6115  ixfmin2:ixfmax2,ix3-1,mag(3)) &
6116  -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
6117  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
6118  -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
6119  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
6120  end do
6121  else
6122  do ix3=ixfmin3,ixfmax3
6123  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
6124  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
6125  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
6126  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
6127  -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
6128  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
6129  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
6130  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
6131  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
6132  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
6133  -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
6134  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
6135  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
6136  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
6137  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
6138  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
6139  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
6140  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
6141  end do
6142  end if
6143  if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
6144  }
6145  case default
6146  call mpistop("Special boundary is not defined for this region")
6147  end select
6148 
6149  end subroutine fixdivb_boundary
6150 
6151  {^nooned
6152  subroutine mhd_clean_divb_multigrid(qdt, qt, active)
6153  use mod_forest
6156  use mod_geometry
6157 
6158  double precision, intent(in) :: qdt !< Current time step
6159  double precision, intent(in) :: qt !< Current time
6160  logical, intent(inout) :: active !< Output if the source is active
6161 
6162  double precision :: tmp(ixg^t), grad(ixg^t, ndim)
6163  double precision :: res
6164  double precision, parameter :: max_residual = 1d-3
6165  double precision, parameter :: residual_reduction = 1d-10
6166  integer :: iigrid, igrid, id
6167  integer :: n, nc, lvl, ix^l, ixc^l, idim
6168  integer, parameter :: max_its = 50
6169  double precision :: residual_it(max_its), max_divb
6170  type(tree_node), pointer :: pnode
6171 
6172  mg%operator_type = mg_laplacian
6173 
6174  ! Set boundary conditions
6175  do n = 1, 2*ndim
6176  idim = (n+1)/2
6177  select case (typeboundary(mag(idim), n))
6178  case (bc_symm)
6179  ! d/dx B = 0, take phi = 0
6180  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
6181  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
6182  case (bc_asymm)
6183  ! B = 0, so grad(phi) = 0
6184  mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
6185  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
6186  case (bc_cont)
6187  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
6188  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
6189  case (bc_special)
6190  ! Assume Dirichlet boundary conditions, derivative zero
6191  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
6192  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
6193  case (bc_periodic)
6194  ! Nothing to do here
6195  case default
6196  write(*,*) "mhd_clean_divb_multigrid warning: unknown boundary type"
6197  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
6198  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
6199  end select
6200  end do
6201 
6202  ix^l=ixm^ll^ladd1;
6203  max_divb = 0.0d0
6204 
6205  ! Store divergence of B as right-hand side
6206  do iigrid = 1, igridstail
6207  igrid = igrids(iigrid);
6208  pnode => igrid_to_node(igrid, mype)%node
6209  id = pnode%id
6210  lvl = mg%boxes(id)%lvl
6211  nc = mg%box_size_lvl(lvl)
6212 
6213  ! Geometry subroutines expect this to be set
6214  block => ps(igrid)
6215  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
6216 
6217  call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
6219  mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
6220  max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
6221  end do
6222 
6223  ! Solve laplacian(phi) = divB
6224  if(stagger_grid) then
6225  call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
6226  mpi_max, icomm, ierrmpi)
6227 
6228  if (mype == 0) print *, "Performing multigrid divB cleaning"
6229  if (mype == 0) print *, "iteration vs residual"
6230  ! Solve laplacian(phi) = divB
6231  do n = 1, max_its
6232  call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
6233  if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
6234  if (residual_it(n) < residual_reduction * max_divb) exit
6235  end do
6236  if (mype == 0 .and. n > max_its) then
6237  print *, "divb_multigrid warning: not fully converged"
6238  print *, "current amplitude of divb: ", residual_it(max_its)
6239  print *, "multigrid smallest grid: ", &
6240  mg%domain_size_lvl(:, mg%lowest_lvl)
6241  print *, "note: smallest grid ideally has <= 8 cells"
6242  print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
6243  print *, "note: dx/dy/dz should be similar"
6244  end if
6245  else
6246  do n = 1, max_its
6247  call mg_fas_vcycle(mg, max_res=res)
6248  if (res < max_residual) exit
6249  end do
6250  if (res > max_residual) call mpistop("divb_multigrid: no convergence")
6251  end if
6252 
6253 
6254  ! Correct the magnetic field
6255  do iigrid = 1, igridstail
6256  igrid = igrids(iigrid);
6257  pnode => igrid_to_node(igrid, mype)%node
6258  id = pnode%id
6259 
6260  ! Geometry subroutines expect this to be set
6261  block => ps(igrid)
6262  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
6263 
6264  ! Compute the gradient of phi
6265  tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
6266 
6267  if(stagger_grid) then
6268  do idim =1, ndim
6269  ixcmin^d=ixmlo^d-kr(idim,^d);
6270  ixcmax^d=ixmhi^d;
6271  call gradientx(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim),.false.)
6272  ! Apply the correction B* = B - gradient(phi)
6273  ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
6274  end do
6275  ! store cell-center magnetic energy
6276  tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
6277  ! change cell-center magnetic field
6278  call mhd_face_to_center(ixm^ll,ps(igrid))
6279  else
6280  do idim = 1, ndim
6281  call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
6282  end do
6283  ! store cell-center magnetic energy
6284  tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
6285  ! Apply the correction B* = B - gradient(phi)
6286  ps(igrid)%w(ixm^t, mag(1:ndim)) = &
6287  ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
6288  end if
6289 
6290  if(total_energy) then
6291  ! Determine magnetic energy difference
6292  tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
6293  mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
6294  ! Keep thermal pressure the same
6295  ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
6296  end if
6297  end do
6298 
6299  active = .true.
6300 
6301  end subroutine mhd_clean_divb_multigrid
6302  }
6303 
6304  subroutine mhd_update_faces(ixI^L,ixO^L,qt,qdt,wprim,fC,fE,sCT,s,vcts)
6306 
6307  integer, intent(in) :: ixI^L, ixO^L
6308  double precision, intent(in) :: qt,qdt
6309  ! cell-center primitive variables
6310  double precision, intent(in) :: wprim(ixI^S,1:nw)
6311  type(state) :: sCT, s
6312  type(ct_velocity) :: vcts
6313  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
6314  double precision, intent(inout) :: fE(ixI^S,sdim:3)
6315 
6316  select case(type_ct)
6317  case('average')
6318  call update_faces_average(ixi^l,ixo^l,qt,qdt,fc,fe,sct,s)
6319  case('uct_contact')
6320  call update_faces_contact(ixi^l,ixo^l,qt,qdt,wprim,fc,fe,sct,s,vcts)
6321  case('uct_hll')
6322  call update_faces_hll(ixi^l,ixo^l,qt,qdt,fe,sct,s,vcts)
6323  case default
6324  call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
6325  end select
6326 
6327  end subroutine mhd_update_faces
6328 
6329  !> get electric field though averaging neighors to update faces in CT
6330  subroutine update_faces_average(ixI^L,ixO^L,qt,qdt,fC,fE,sCT,s)
6332  use mod_usr_methods
6333 
6334  integer, intent(in) :: ixI^L, ixO^L
6335  double precision, intent(in) :: qt, qdt
6336  type(state) :: sCT, s
6337  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
6338  double precision, intent(inout) :: fE(ixI^S,sdim:3)
6339 
6340  double precision :: circ(ixI^S,1:ndim)
6341  ! non-ideal electric field on cell edges
6342  double precision, dimension(ixI^S,sdim:3) :: E_resi, E_ambi
6343  integer :: hxC^L,ixC^L,jxC^L,ixCm^L
6344  integer :: idim1,idim2,idir,iwdim1,iwdim2
6345 
6346  associate(bfaces=>s%ws,x=>s%x)
6347 
6348  ! Calculate contribution to FEM of each edge,
6349  ! that is, estimate value of line integral of
6350  ! electric field in the positive idir direction.
6351 
6352  ! if there is resistivity, get eta J
6353  if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,e_resi)
6354 
6355  ! if there is ambipolar diffusion, get E_ambi
6356  if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
6357 
6358  do idim1=1,ndim
6359  iwdim1 = mag(idim1)
6360  do idim2=1,ndim
6361  iwdim2 = mag(idim2)
6362  do idir=sdim,3! Direction of line integral
6363  ! Allow only even permutations
6364  if (lvc(idim1,idim2,idir)==1) then
6365  ixcmax^d=ixomax^d;
6366  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6367  ! Assemble indices
6368  jxc^l=ixc^l+kr(idim1,^d);
6369  hxc^l=ixc^l+kr(idim2,^d);
6370  ! Interpolate to edges
6371  fe(ixc^s,idir)=quarter*(fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
6372  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
6373 
6374  ! add resistive electric field at cell edges E=-vxB+eta J
6375  if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
6376  ! add ambipolar electric field
6377  if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
6378 
6379  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
6380 
6381  if (.not.slab) then
6382  where(abs(x(ixc^s,r_)+half*dxlevel(r_))<1.0d-9)
6383  fe(ixc^s,idir)=zero
6384  end where
6385  end if
6386  end if
6387  end do
6388  end do
6389  end do
6390 
6391  ! allow user to change inductive electric field, especially for boundary driven applications
6392  if(associated(usr_set_electric_field)) &
6393  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
6394 
6395  circ(ixi^s,1:ndim)=zero
6396 
6397  ! Calculate circulation on each face
6398  do idim1=1,ndim ! Coordinate perpendicular to face
6399  ixcmax^d=ixomax^d;
6400  ixcmin^d=ixomin^d-kr(idim1,^d);
6401  do idim2=1,ndim
6402  do idir=sdim,3 ! Direction of line integral
6403  ! Assemble indices
6404  if(lvc(idim1,idim2,idir)/=0) then
6405  hxc^l=ixc^l-kr(idim2,^d);
6406  ! Add line integrals in direction idir
6407  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
6408  +lvc(idim1,idim2,idir)&
6409  *(fe(ixc^s,idir)&
6410  -fe(hxc^s,idir))
6411  end if
6412  end do
6413  end do
6414  ! Divide by the area of the face to get dB/dt
6415  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
6416  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
6417  elsewhere
6418  circ(ixc^s,idim1)=zero
6419  end where
6420  ! Time update cell-face magnetic field component
6421  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
6422  end do
6423 
6424  end associate
6425 
6426  end subroutine update_faces_average
6427 
6428  !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
6429  subroutine update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
6431  use mod_usr_methods
6432  use mod_geometry
6433 
6434  integer, intent(in) :: ixI^L, ixO^L
6435  double precision, intent(in) :: qt, qdt
6436  ! cell-center primitive variables
6437  double precision, intent(in) :: wp(ixI^S,1:nw)
6438  type(state) :: sCT, s
6439  type(ct_velocity) :: vcts
6440  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
6441  double precision, intent(inout) :: fE(ixI^S,sdim:3)
6442 
6443  double precision :: circ(ixI^S,1:ndim)
6444  ! electric field at cell centers
6445  double precision :: ECC(ixI^S,sdim:3)
6446  double precision :: Ein(ixI^S,sdim:3)
6447  ! gradient of E at left and right side of a cell face
6448  double precision :: EL(ixI^S),ER(ixI^S)
6449  ! gradient of E at left and right side of a cell corner
6450  double precision :: ELC(ixI^S),ERC(ixI^S)
6451  ! non-ideal electric field on cell edges
6452  double precision, dimension(ixI^S,sdim:3) :: E_resi, E_ambi
6453  ! total magnetic field at cell centers
6454  double precision :: Btot(ixI^S,1:ndim)
6455  ! current on cell edges
6456  double precision :: jce(ixI^S,sdim:3)
6457  ! location at cell faces
6458  double precision :: xs(ixGs^T,1:ndim)
6459  double precision :: gradi(ixGs^T)
6460  integer :: hxC^L,ixC^L,jxC^L,ixA^L,ixB^L
6461  integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^D
6462 
6463  associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
6464 
6465  if(b0field) then
6466  btot(ixi^s,1:ndim)=wp(ixi^s,mag(1:ndim))+block%B0(ixi^s,1:ndim,0)
6467  else
6468  btot(ixi^s,1:ndim)=wp(ixi^s,mag(1:ndim))
6469  end if
6470  ecc=0.d0
6471  ! Calculate electric field at cell centers
6472  do idim1=1,ndim; do idim2=1,ndim; do idir=sdim,3
6473  if(lvc(idim1,idim2,idir)==1)then
6474  ecc(ixi^s,idir)=ecc(ixi^s,idir)+btot(ixi^s,idim1)*wp(ixi^s,mom(idim2))
6475  else if(lvc(idim1,idim2,idir)==-1) then
6476  ecc(ixi^s,idir)=ecc(ixi^s,idir)-btot(ixi^s,idim1)*wp(ixi^s,mom(idim2))
6477  endif
6478  enddo; enddo; enddo
6479 
6480  ! if there is resistivity, get eta J
6481  if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,e_resi)
6482 
6483  ! if there is ambipolar diffusion, get E_ambi
6484  if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
6485 
6486  ! Calculate contribution to FEM of each edge,
6487  ! that is, estimate value of line integral of
6488  ! electric field in the positive idir direction.
6489  ! evaluate electric field along cell edges according to equation (41)
6490  do idim1=1,ndim
6491  iwdim1 = mag(idim1)
6492  do idim2=1,ndim
6493  iwdim2 = mag(idim2)
6494  do idir=sdim,3 ! Direction of line integral
6495  ! Allow only even permutations
6496  if (lvc(idim1,idim2,idir)==1) then
6497  ixcmax^d=ixomax^d;
6498  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6499  ! Assemble indices
6500  jxc^l=ixc^l+kr(idim1,^d);
6501  hxc^l=ixc^l+kr(idim2,^d);
6502  ! average cell-face electric field to cell edges
6503  fe(ixc^s,idir)=quarter*&
6504  (fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
6505  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
6506  if(partial_energy) ein(ixc^s,idir)=fe(ixc^s,idir)
6507 
6508  ! add slope in idim2 direction from equation (50)
6509  ixamin^d=ixcmin^d;
6510  ixamax^d=ixcmax^d+kr(idim1,^d);
6511  el(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(ixa^s,idir)
6512  hxc^l=ixa^l+kr(idim2,^d);
6513  er(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(hxc^s,idir)
6514  where(vnorm(ixc^s,idim1)>0.d0)
6515  elc(ixc^s)=el(ixc^s)
6516  else where(vnorm(ixc^s,idim1)<0.d0)
6517  elc(ixc^s)=el(jxc^s)
6518  else where
6519  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
6520  end where
6521  hxc^l=ixc^l+kr(idim2,^d);
6522  where(vnorm(hxc^s,idim1)>0.d0)
6523  erc(ixc^s)=er(ixc^s)
6524  else where(vnorm(hxc^s,idim1)<0.d0)
6525  erc(ixc^s)=er(jxc^s)
6526  else where
6527  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
6528  end where
6529  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
6530 
6531  ! add slope in idim1 direction from equation (50)
6532  jxc^l=ixc^l+kr(idim2,^d);
6533  ixamin^d=ixcmin^d;
6534  ixamax^d=ixcmax^d+kr(idim2,^d);
6535  el(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(ixa^s,idir)
6536  hxc^l=ixa^l+kr(idim1,^d);
6537  er(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(hxc^s,idir)
6538  where(vnorm(ixc^s,idim2)>0.d0)
6539  elc(ixc^s)=el(ixc^s)
6540  else where(vnorm(ixc^s,idim2)<0.d0)
6541  elc(ixc^s)=el(jxc^s)
6542  else where
6543  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
6544  end where
6545  hxc^l=ixc^l+kr(idim1,^d);
6546  where(vnorm(hxc^s,idim2)>0.d0)
6547  erc(ixc^s)=er(ixc^s)
6548  else where(vnorm(hxc^s,idim2)<0.d0)
6549  erc(ixc^s)=er(jxc^s)
6550  else where
6551  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
6552  end where
6553  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
6554  ! difference between average and upwind interpolated E
6555  if(partial_energy) ein(ixc^s,idir)=fe(ixc^s,idir)-ein(ixc^s,idir)
6556  ! add resistive electric field at cell edges E=-vxB+eta J
6557  if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
6558  ! add ambipolar electric field
6559  if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
6560 
6561  ! times time step and edge length
6562  fe(ixc^s,idir)=fe(ixc^s,idir)*qdt*s%dsC(ixc^s,idir)
6563  end if
6564  end do
6565  end do
6566  end do
6567 
6568  if(partial_energy) then
6569  ! add upwind diffused magnetic energy back to energy
6570  ! calculate current density at cell edges
6571  jce=0.d0
6572  do idim1=1,ndim
6573  do idim2=1,ndim
6574  do idir=sdim,3
6575  if (lvc(idim1,idim2,idir)==0) cycle
6576  ixcmax^d=ixomax^d;
6577  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6578  ixbmax^d=ixcmax^d-kr(idir,^d)+1;
6579  ixbmin^d=ixcmin^d;
6580  ! current at transverse faces
6581  xs(ixb^s,:)=x(ixb^s,:)
6582  xs(ixb^s,idim2)=x(ixb^s,idim2)+half*s%dx(ixb^s,idim2)
6583  call gradientx(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,.false.)
6584  if (lvc(idim1,idim2,idir)==1) then
6585  jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
6586  else
6587  jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
6588  end if
6589  end do
6590  end do
6591  end do
6592  if(nwextra>0) block%w(ixo^s,nw)=0.d0
6593  do idir=sdim,3
6594  ixcmax^d=ixomax^d;
6595  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6596  ! E dot J on cell edges
6597  ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
6598  ! average from cell edge to cell center
6599  jce(ixi^s,idir)=0.d0
6600  {do ix^db=-1,0\}
6601  if({ ix^d==-1 .and. ^d==idir | .or.}) cycle
6602  ixamin^d=ixomin^d+ix^d;
6603  ixamax^d=ixomax^d+ix^d;
6604  jce(ixo^s,idir)=jce(ixo^s,idir)+ein(ixa^s,idir)
6605  {end do\}
6606  where(jce(ixo^s,idir)<0.d0)
6607  jce(ixo^s,idir)=0.d0
6608  end where
6609  ! save additional numerical resistive heating to an extra variable
6610  if(nwextra>0) block%w(ixo^s,nw)=block%w(ixo^s,nw)+0.25d0*jce(ixo^s,idir)
6611  w(ixo^s,e_)=w(ixo^s,e_)+qdt*0.25d0*jce(ixo^s,idir)
6612  end do
6613  end if
6614 
6615  ! allow user to change inductive electric field, especially for boundary driven applications
6616  if(associated(usr_set_electric_field)) &
6617  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
6618 
6619  circ(ixi^s,1:ndim)=zero
6620 
6621  ! Calculate circulation on each face
6622  do idim1=1,ndim ! Coordinate perpendicular to face
6623  ixcmax^d=ixomax^d;
6624  ixcmin^d=ixomin^d-kr(idim1,^d);
6625  do idim2=1,ndim
6626  do idir=sdim,3 ! Direction of line integral
6627  ! Assemble indices
6628  if(lvc(idim1,idim2,idir)/=0) then
6629  hxc^l=ixc^l-kr(idim2,^d);
6630  ! Add line integrals in direction idir
6631  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
6632  +lvc(idim1,idim2,idir)&
6633  *(fe(ixc^s,idir)&
6634  -fe(hxc^s,idir))
6635  end if
6636  end do
6637  end do
6638  ! Divide by the area of the face to get dB/dt
6639  where(s%surfaceC(ixc^s,idim1) > smalldouble)
6640  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
6641  elsewhere
6642  circ(ixc^s,idim1)=zero
6643  end where
6644  ! Time update cell-face magnetic field component
6645  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
6646  end do
6647 
6648  end associate
6649 
6650  end subroutine update_faces_contact
6651 
6652  !> update faces
6653  subroutine update_faces_hll(ixI^L,ixO^L,qt,qdt,fE,sCT,s,vcts)
6656  use mod_usr_methods
6657 
6658  integer, intent(in) :: ixI^L, ixO^L
6659  double precision, intent(in) :: qt, qdt
6660  double precision, intent(inout) :: fE(ixI^S,sdim:3)
6661  type(state) :: sCT, s
6662  type(ct_velocity) :: vcts
6663 
6664  double precision :: vtilL(ixI^S,2)
6665  double precision :: vtilR(ixI^S,2)
6666  double precision :: bfacetot(ixI^S,ndim)
6667  double precision :: btilL(ixI^S,ndim)
6668  double precision :: btilR(ixI^S,ndim)
6669  double precision :: cp(ixI^S,2)
6670  double precision :: cm(ixI^S,2)
6671  double precision :: circ(ixI^S,1:ndim)
6672  ! non-ideal electric field on cell edges
6673  double precision, dimension(ixI^S,sdim:3) :: E_resi, E_ambi
6674  integer :: hxC^L,ixC^L,ixCp^L,jxC^L,ixCm^L
6675  integer :: idim1,idim2,idir
6676 
6677  associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
6678  cbarmax=>vcts%cbarmax)
6679 
6680  ! Calculate contribution to FEM of each edge,
6681  ! that is, estimate value of line integral of
6682  ! electric field in the positive idir direction.
6683 
6684  ! Loop over components of electric field
6685 
6686  ! idir: electric field component we need to calculate
6687  ! idim1: directions in which we already performed the reconstruction
6688  ! idim2: directions in which we perform the reconstruction
6689 
6690  ! if there is resistivity, get eta J
6691  if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,e_resi)
6692 
6693  ! if there is ambipolar diffusion, get E_ambi
6694  if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
6695 
6696  do idir=sdim,3
6697  ! Indices
6698  ! idir: electric field component
6699  ! idim1: one surface
6700  ! idim2: the other surface
6701  ! cyclic permutation: idim1,idim2,idir=1,2,3
6702  ! Velocity components on the surface
6703  ! follow cyclic premutations:
6704  ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
6705 
6706  ixcmax^d=ixomax^d;
6707  ixcmin^d=ixomin^d-1+kr(idir,^d);
6708 
6709  ! Set indices and directions
6710  idim1=mod(idir,3)+1
6711  idim2=mod(idir+1,3)+1
6712 
6713  jxc^l=ixc^l+kr(idim1,^d);
6714  ixcp^l=ixc^l+kr(idim2,^d);
6715 
6716  ! Reconstruct transverse transport velocities
6717  call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
6718  vtill(ixi^s,2),vtilr(ixi^s,2))
6719 
6720  call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
6721  vtill(ixi^s,1),vtilr(ixi^s,1))
6722 
6723  ! Reconstruct magnetic fields
6724  ! Eventhough the arrays are larger, reconstruct works with
6725  ! the limits ixG.
6726  if(b0field) then
6727  bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
6728  bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
6729  else
6730  bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
6731  bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
6732  end if
6733  call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
6734  btill(ixi^s,idim1),btilr(ixi^s,idim1))
6735 
6736  call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
6737  btill(ixi^s,idim2),btilr(ixi^s,idim2))
6738 
6739  ! Take the maximum characteristic
6740 
6741  cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
6742  cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
6743 
6744  cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
6745  cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
6746 
6747 
6748  ! Calculate eletric field
6749  fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
6750  + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
6751  - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
6752  /(cp(ixc^s,1)+cm(ixc^s,1)) &
6753  +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
6754  + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
6755  - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
6756  /(cp(ixc^s,2)+cm(ixc^s,2))
6757 
6758  ! add resistive electric field at cell edges E=-vxB+eta J
6759  if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
6760  ! add ambipolar electric field
6761  if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
6762 
6763  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
6764 
6765  if (.not.slab) then
6766  where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
6767  fe(ixc^s,idir)=zero
6768  end where
6769  end if
6770 
6771  end do
6772 
6773  ! allow user to change inductive electric field, especially for boundary driven applications
6774  if(associated(usr_set_electric_field)) &
6775  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
6776 
6777  circ(ixi^s,1:ndim)=zero
6778 
6779  ! Calculate circulation on each face: interal(fE dot dl)
6780  do idim1=1,ndim ! Coordinate perpendicular to face
6781  ixcmax^d=ixomax^d;
6782  ixcmin^d=ixomin^d-kr(idim1,^d);
6783  do idim2=1,ndim
6784  do idir=sdim,3 ! Direction of line integral
6785  ! Assemble indices
6786  if(lvc(idim1,idim2,idir)/=0) then
6787  hxc^l=ixc^l-kr(idim2,^d);
6788  ! Add line integrals in direction idir
6789  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
6790  +lvc(idim1,idim2,idir)&
6791  *(fe(ixc^s,idir)&
6792  -fe(hxc^s,idir))
6793  end if
6794  end do
6795  end do
6796  ! Divide by the area of the face to get dB/dt
6797  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
6798  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
6799  elsewhere
6800  circ(ixc^s,idim1)=zero
6801  end where
6802  ! Time update cell-face magnetic field component
6803  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
6804  end do
6805 
6806  end associate
6807  end subroutine update_faces_hll
6808 
6809  !> calculate eta J at cell edges
6810  subroutine get_resistive_electric_field(ixI^L,ixO^L,sCT,s,jce)
6812  use mod_usr_methods
6813  use mod_geometry
6814 
6815  integer, intent(in) :: ixI^L, ixO^L
6816  type(state), intent(in) :: sCT, s
6817  ! current on cell edges
6818  double precision :: jce(ixI^S,sdim:3)
6819 
6820  ! current on cell centers
6821  double precision :: jcc(ixI^S,7-2*ndir:3)
6822  ! location at cell faces
6823  double precision :: xs(ixGs^T,1:ndim)
6824  ! resistivity
6825  double precision :: eta(ixI^S)
6826  double precision :: gradi(ixGs^T)
6827  integer :: ix^D,ixC^L,ixA^L,ixB^L,idir,idirmin,idim1,idim2
6828 
6829  associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
6830  ! calculate current density at cell edges
6831  jce=0.d0
6832  do idim1=1,ndim
6833  do idim2=1,ndim
6834  do idir=sdim,3
6835  if (lvc(idim1,idim2,idir)==0) cycle
6836  ixcmax^d=ixomax^d;
6837  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6838  ixbmax^d=ixcmax^d-kr(idir,^d)+1;
6839  ixbmin^d=ixcmin^d;
6840  ! current at transverse faces
6841  xs(ixb^s,:)=x(ixb^s,:)
6842  xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
6843  call gradientx(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,.true.)
6844  if (lvc(idim1,idim2,idir)==1) then
6845  jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
6846  else
6847  jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
6848  end if
6849  end do
6850  end do
6851  end do
6852  ! get resistivity
6853  if(mhd_eta>zero)then
6854  jce(ixi^s,:)=jce(ixi^s,:)*mhd_eta
6855  else
6856  ixa^l=ixo^l^ladd1;
6857  call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
6858  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,jcc,eta)
6859  ! calcuate eta on cell edges
6860  do idir=sdim,3
6861  ixcmax^d=ixomax^d;
6862  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6863  jcc(ixc^s,idir)=0.d0
6864  {do ix^db=0,1\}
6865  if({ ix^d==1 .and. ^d==idir | .or.}) cycle
6866  ixamin^d=ixcmin^d+ix^d;
6867  ixamax^d=ixcmax^d+ix^d;
6868  jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
6869  {end do\}
6870  jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
6871  jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
6872  end do
6873  end if
6874 
6875  end associate
6876  end subroutine get_resistive_electric_field
6877 
6878  !> get ambipolar electric field on cell edges
6879  subroutine get_ambipolar_electric_field(ixI^L,ixO^L,w,x,fE)
6881 
6882  integer, intent(in) :: ixI^L, ixO^L
6883  double precision, intent(in) :: w(ixI^S,1:nw)
6884  double precision, intent(in) :: x(ixI^S,1:ndim)
6885  double precision, intent(out) :: fE(ixI^S,sdim:3)
6886 
6887  double precision :: jxbxb(ixI^S,1:3)
6888  integer :: idir,ixA^L,ixC^L,ix^D
6889 
6890  ixa^l=ixo^l^ladd1;
6891  call mhd_get_jxbxb(w,x,ixi^l,ixa^l,jxbxb)
6892  ! calcuate electric field on cell edges from cell centers
6893  do idir=sdim,3
6894  !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
6895  !jxbxb(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
6896  call multiplyambicoef(ixi^l,ixa^l,jxbxb(ixi^s,idir),w,x)
6897  ixcmax^d=ixomax^d;
6898  ixcmin^d=ixomin^d+kr(idir,^d)-1;
6899  fe(ixc^s,idir)=0.d0
6900  {do ix^db=0,1\}
6901  if({ ix^d==1 .and. ^d==idir | .or.}) cycle
6902  ixamin^d=ixcmin^d+ix^d;
6903  ixamax^d=ixcmax^d+ix^d;
6904  fe(ixc^s,idir)=fe(ixc^s,idir)+jxbxb(ixa^s,idir)
6905  {end do\}
6906  fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0
6907  end do
6908 
6909  end subroutine get_ambipolar_electric_field
6910 
6911  !> calculate cell-center values from face-center values
6912  subroutine mhd_face_to_center(ixO^L,s)
6914  ! Non-staggered interpolation range
6915  integer, intent(in) :: ixo^l
6916  type(state) :: s
6917 
6918  integer :: fxo^l, gxo^l, hxo^l, jxo^l, kxo^l, idim
6919 
6920  associate(w=>s%w, ws=>s%ws)
6921 
6922  ! calculate cell-center values from face-center values in 2nd order
6923  do idim=1,ndim
6924  ! Displace index to the left
6925  ! Even if ixI^L is the full size of the w arrays, this is ok
6926  ! because the staggered arrays have an additional place to the left.
6927  hxo^l=ixo^l-kr(idim,^d);
6928  ! Interpolate to cell barycentre using arithmetic average
6929  ! This might be done better later, to make the method less diffusive.
6930  w(ixo^s,mag(idim))=half/s%surface(ixo^s,idim)*&
6931  (ws(ixo^s,idim)*s%surfaceC(ixo^s,idim)&
6932  +ws(hxo^s,idim)*s%surfaceC(hxo^s,idim))
6933  end do
6934 
6935  ! calculate cell-center values from face-center values in 4th order
6936  !do idim=1,ndim
6937  ! gxO^L=ixO^L-2*kr(idim,^D);
6938  ! hxO^L=ixO^L-kr(idim,^D);
6939  ! jxO^L=ixO^L+kr(idim,^D);
6940 
6941  ! ! Interpolate to cell barycentre using fourth order central formula
6942  ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
6943  ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
6944  ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
6945  ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
6946  ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
6947  !end do
6948 
6949  ! calculate cell-center values from face-center values in 6th order
6950  !do idim=1,ndim
6951  ! fxO^L=ixO^L-3*kr(idim,^D);
6952  ! gxO^L=ixO^L-2*kr(idim,^D);
6953  ! hxO^L=ixO^L-kr(idim,^D);
6954  ! jxO^L=ixO^L+kr(idim,^D);
6955  ! kxO^L=ixO^L+2*kr(idim,^D);
6956 
6957  ! ! Interpolate to cell barycentre using sixth order central formula
6958  ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
6959  ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
6960  ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
6961  ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
6962  ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
6963  ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
6964  ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
6965  !end do
6966 
6967  end associate
6968 
6969  end subroutine mhd_face_to_center
6970 
6971  !> calculate magnetic field from vector potential
6972  subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
6975 
6976  integer, intent(in) :: ixis^l, ixi^l, ixo^l
6977  double precision, intent(inout) :: ws(ixis^s,1:nws)
6978  double precision, intent(in) :: x(ixi^s,1:ndim)
6979 
6980  double precision :: adummy(ixis^s,1:3)
6981 
6982  call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
6983 
6984  end subroutine b_from_vector_potential
6985 
6986  subroutine rfactor_from_temperature_ionization(w,x,ixI^L,ixO^L,Rfactor)
6989  integer, intent(in) :: ixI^L, ixO^L
6990  double precision, intent(in) :: w(ixI^S,1:nw)
6991  double precision, intent(in) :: x(ixI^S,1:ndim)
6992  double precision, intent(out):: Rfactor(ixI^S)
6993 
6994  double precision :: iz_H(ixO^S),iz_He(ixO^S)
6995 
6996  call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,te_),iz_h,iz_he)
6997  ! assume the first and second ionization of Helium have the same degree
6998  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)
6999 
7001 
7002  subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
7004  integer, intent(in) :: ixI^L, ixO^L
7005  double precision, intent(in) :: w(ixI^S,1:nw)
7006  double precision, intent(in) :: x(ixI^S,1:ndim)
7007  double precision, intent(out):: Rfactor(ixI^S)
7008 
7009  rfactor(ixo^s)=rr
7010 
7011  end subroutine rfactor_from_constant_ionization
7012 end module mod_mhd_phys
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
Definition: mod_cak_force.t:27
subroutine cak_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
Check time step for total radiation contribution.
subroutine cak_init(phys_gamma)
Initialize the module.
Definition: mod_cak_force.t:98
subroutine cak_add_source(qdt, ixIL, ixOL, wCT, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
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 b_from_vector_potentiala(ixIsL, ixIL, ixOL, ws, x, A)
calculate magnetic field from vector potential A at cell edges
subroutine reconstruct(ixIL, ixCL, idir, q, qL, qR)
Reconstruct scalar q within ixO^L to 1/2 dx in direction idir Return both left and right reconstructe...
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition: mod_convert.t:64
Module for flux conservation near refinement boundaries.
subroutine, public store_edge(igrid, ixIL, fE, idimLIM)
subroutine, public store_flux(igrid, fC, idimLIM, nwfluxin)
Module with basic grid data structures.
Definition: mod_forest.t:2
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition: mod_forest.t:32
integer, dimension(:), allocatable, public mag
Indices of the magnetic field.
subroutine, public get_divb(w, ixIL, ixOL, divb, fourthorder)
Calculate div B within ixO.
Module with geometry-related routines (e.g., divergence, curl)
Definition: mod_geometry.t:2
integer coordinate
Definition: mod_geometry.t:7
integer, parameter spherical
Definition: mod_geometry.t:11
integer, parameter cylindrical
Definition: mod_geometry.t:10
subroutine gradient(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:321
subroutine curlvector(qvec, ixIL, ixOL, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
Definition: mod_geometry.t:663
subroutine gradients(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir first use limiter to go from cell cente...
Definition: mod_geometry.t:458
subroutine divvector(qvec, ixIL, ixOL, divq, fourthorder, sixthorder)
Calculate divergence of a vector qvec within ixL.
Definition: mod_geometry.t:516
subroutine gradientx(q, x, ixIL, ixOL, idir, gradq, fourth_order)
Calculate gradient of a scalar q in direction idir at cell interfaces.
Definition: mod_geometry.t:363
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 dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
double precision unit_charge
Physical scaling factor for charge.
double precision small_pressure
integer ixghi
Upper index of grid block arrays.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
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
integer, parameter bc_asymm
double precision global_time
The global simulation time.
double precision unit_mass
Physical scaling factor for mass.
integer, dimension(3, 3) kr
Kronecker delta tensor.
double precision phys_trac_mask
integer it
Number of time steps taken.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
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.
logical stagger_grid
True for using stagger grid.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
double precision bdip
amplitude of background dipolar, quadrupolar, octupolar, user's field
integer b0i
background magnetic field location indicator
integer mype
The rank of the current MPI task.
integer, dimension(:), allocatable, parameter d
logical local_timestep
each cell has its own timestep or not
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
double precision unit_velocity
Physical scaling factor for velocity.
double precision c_norm
Normalised speed of light.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
integer, parameter bc_cont
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
pure subroutine cross_product(ixIL, ixOL, a, b, axb)
Cross product of two vectors.
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter sdim
starting dimension for electric field
integer, parameter bc_symm
logical phys_trac
Use TRAC (Johnston 2019 ApJL, 873, L22) for MHD or 1D HD.
logical need_global_cmax
need global maximal wave speed
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
logical crash
Save a snapshot before crash a run met unphysical values.
logical use_multigrid
Use multigrid (only available in 2D and 3D)
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
double precision small_density
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
integer, parameter unitconvert
double precision, dimension(ndim) dxlevel
logical check_small_values
check and optionally fix unphysical small values (density, gas pressure)
integer, parameter ixglo
Lower index of grid block arrays (always 1)
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:86
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 mod_magnetofriction.t Purpose: use magnetofrictional method to relax 3D magnetic field to forc...
subroutine magnetofriction_init()
Initialize the module.
Magneto-hydrodynamics module.
Definition: mod_mhd_phys.t:2
subroutine mhd_get_pthermal_origin(w, x, ixIL, ixOL, pth)
Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L.
subroutine mhd_get_temperature_from_eint_with_equi(w, x, ixIL, ixOL, res)
subroutine mhd_get_cbounds(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
Estimating bounds for the minimum and maximum signal velocities without split.
procedure(sub_get_v), pointer, public mhd_get_v
Definition: mod_mhd_phys.t:226
logical, public, protected mhd_gravity
Whether gravity is added.
Definition: mod_mhd_phys.t:113
subroutine update_faces_hll(ixIL, ixOL, qt, qdt, fE, sCT, s, vcts)
update faces
subroutine add_source_res1(qdt, ixIL, ixOL, wCT, w, x)
Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in each direction,...
logical, public has_equi_rho0
whether split off equilibrium density
Definition: mod_mhd_phys.t:155
subroutine mhd_get_cmax_origin(w, x, ixIL, ixOL, idim, cmax)
Calculate cmax_idim=csound+abs(v_idim) within ixO^L.
subroutine add_source_semirelativistic(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176.
logical, public, protected mhd_internal_e
Whether internal energy is solved instead of total energy.
Definition: mod_mhd_phys.t:139
subroutine mhd_to_primitive_inte(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
logical, public, protected mhd_glm_extended
Whether extended GLM-MHD is used with additional sources.
Definition: mod_mhd_phys.t:131
character(len=std_len), public, protected type_ct
Method type of constrained transport.
Definition: mod_mhd_phys.t:188
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
Definition: mod_mhd_phys.t:69
subroutine mhd_to_conserved_semirelati(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
subroutine, public mhd_clean_divb_multigrid(qdt, qt, active)
subroutine mhd_te_images
Definition: mod_mhd_phys.t:919
subroutine set_equi_vars_grid(igrid)
sets the equilibrium variables
logical, public, protected mhd_hyperbolic_thermal_conduction
Whether thermal conduction is used.
Definition: mod_mhd_phys.t:109
subroutine add_source_powel(qdt, ixIL, ixOL, wCT, w, x)
Add divB related sources to w within ixO corresponding to Powel.
subroutine, public b_from_vector_potential(ixIsL, ixIL, ixOL, ws, x)
calculate magnetic field from vector potential
subroutine mhd_check_params
double precision function, dimension(ixo^s) mhd_gamma_alfven(w, ixIL, ixOL)
Compute 1/sqrt(1+v_A^2/c^2) for semirelativisitic MHD, where v_A is the Alfven velocity.
subroutine mhd_get_tcutoff(ixIL, ixOL, w, x, Tco_local, Tmax_local)
get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
subroutine update_faces_contact(ixIL, ixOL, qt, qdt, wp, fC, fE, sCT, s, vcts)
update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
subroutine mhd_get_jambi(w, x, ixIL, ixOL, res)
double precision function, dimension(ixo^s) mhd_mag_i_all(w, ixIL, ixOL, idir)
Compute full magnetic field by direction.
logical, public, protected mhd_radiative_cooling
Whether radiative cooling is added.
Definition: mod_mhd_phys.t:107
double precision, public mhd_adiab
The adiabatic constant.
Definition: mod_mhd_phys.t:20
logical, public, protected mhd_partial_ionization
Whether plasma is partially ionized.
Definition: mod_mhd_phys.t:149
double precision, public mhd_eta_hyper
The MHD hyper-resistivity.
Definition: mod_mhd_phys.t:24
subroutine mhd_to_conserved_hde(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
subroutine, public mhd_e_to_ei(ixIL, ixOL, w, x)
Transform total energy to internal energy.
subroutine mhd_to_conserved_origin(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
subroutine add_source_internal_e(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
Source terms for internal energy version of MHD.
subroutine, public get_current(w, ixIL, ixOL, idirmin, current)
Calculate idirmin and the idirmin:3 components of the common current array make sure that dxlevel(^D)...
double precision function mhd_get_tc_dt_mhd(w, ixIL, ixOL, dxD, x)
Definition: mod_mhd_phys.t:953
subroutine mhd_get_a2max(w, x, ixIL, ixOL, a2max)
subroutine, public mhd_get_rho(w, x, ixIL, ixOL, rho)
subroutine get_tau(ixIL, ixOL, w, Te, tau, sigT5)
subroutine mhd_get_temperature_from_etot(w, x, ixIL, ixOL, res)
Calculate temperature=p/rho when in e_ the total energy is stored.
subroutine mhd_tc_handle_small_e(w, x, ixIL, ixOL, step)
Definition: mod_mhd_phys.t:968
double precision, public, protected rr
Definition: mod_mhd_phys.t:56
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
Definition: mod_mhd_phys.t:46
subroutine mhd_e_to_ei_semirelati(ixIL, ixOL, w, x)
Transform total energy to internal energy and momentum to velocity.
logical, public, protected mhd_divb_4thorder
Whether divB is computed with a fourth order approximation.
Definition: mod_mhd_phys.t:162
double precision, public mhd_gamma
The adiabatic index.
Definition: mod_mhd_phys.t:18
integer, public, protected mhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
Definition: mod_mhd_phys.t:137
subroutine mhd_get_flux(wC, w, x, ixIL, ixOL, idim, f)
Calculate fluxes within ixO^L without any splitting.
subroutine tc_params_read_mhd(fl)
Definition: mod_mhd_phys.t:982
subroutine, public mhd_face_to_center(ixOL, s)
calculate cell-center values from face-center values
subroutine mhd_get_pthermal_eint(w, x, ixIL, ixOL, pth)
Calculate thermal pressure from internal energy.
subroutine, public mhd_ei_to_e(ixIL, ixOL, w, x)
Transform internal energy to total energy.
subroutine mhd_modify_wlr(ixIL, ixOL, qt, wLC, wRC, wLp, wRp, s, idir)
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
Definition: mod_mhd_phys.t:192
subroutine update_faces_ambipolar(ixIL, ixOL, w, x, ECC, fE, circ)
get ambipolar electric field and the integrals around cell faces
logical, public, protected mhd_rotating_frame
Whether rotating frame is activated.
Definition: mod_mhd_phys.t:115
logical, public, protected mhd_semirelativistic
Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved.
Definition: mod_mhd_phys.t:147
integer, public, protected q_
Index of the heat flux q.
Definition: mod_mhd_phys.t:75
subroutine mhd_get_csound(w, x, ixIL, ixOL, idim, csound)
Calculate fast magnetosonic wave speed.
subroutine add_source_glm(qdt, ixIL, ixOL, wCT, w, x)
integer, public, protected mhd_n_tracer
Number of tracer species.
Definition: mod_mhd_phys.t:65
integer, public, protected te_
Indices of temperature.
Definition: mod_mhd_phys.t:79
subroutine mhd_get_temperature_from_te(w, x, ixIL, ixOL, res)
copy temperature from stored Te variable
integer, public equi_rho0_
equi vars indices in the stateequi_vars array
Definition: mod_mhd_phys.t:62
integer, public, protected mhd_trac_type
Which TRAC method is used.
Definition: mod_mhd_phys.t:135
subroutine mhd_to_conserved_split_rho(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
subroutine add_source_ambipolar_internal_energy(qdt, ixIL, ixOL, wCT, w, x, ie)
Source terms J.E in internal energy. For the ambipolar term E = ambiCoef * JxBxB=ambiCoef * B^2(-J_pe...
subroutine mhd_handle_small_values_origin(primitive, w, x, ixIL, ixOL, subname)
subroutine mhd_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
If resistivity is not zero, check diffusion time limit for dt.
logical, public, protected mhd_cak_force
Whether CAK radiation line force is activated.
Definition: mod_mhd_phys.t:151
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
Definition: mod_mhd_phys.t:144
logical, public, protected mhd_hall
Whether Hall-MHD is used.
Definition: mod_mhd_phys.t:117
subroutine mhd_sts_set_source_tc_mhd(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux)
Definition: mod_mhd_phys.t:941
subroutine mhd_gamma2_alfven(ixIL, ixOL, w, gamma_A2)
Compute 1/(1+v_A^2/c^2) for semirelativistic MHD, where v_A is the Alfven velocity.
subroutine add_source_linde(qdt, ixIL, ixOL, wCT, w, x)
type(te_fluid), allocatable, public te_fl_mhd
type of fluid for thermal emission synthesis
Definition: mod_mhd_phys.t:194
logical, public, protected mhd_ambipolar
Whether Ambipolar term is used.
Definition: mod_mhd_phys.t:119
subroutine add_source_hydrodynamic_e(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
Source terms for hydrodynamic energy version of MHD.
subroutine mhd_get_ct_velocity(vcts, wLp, wRp, ixIL, ixOL, idim, cmax, cmin)
prepare velocities for ct methods
subroutine add_source_hyperres(qdt, ixIL, ixOL, wCT, w, x)
Add Hyper-resistive source to w within ixO Uses 9 point stencil (4 neighbours) in each direction.
subroutine mhd_get_pe_equi(w, x, ixIL, ixOL, res)
double precision function, dimension(ixo^s, 1:nwc) convert_vars_splitting(ixIL, ixOL, w, x, nwc)
double precision, public hypertc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
Definition: mod_mhd_phys.t:39
subroutine get_resistive_electric_field(ixIL, ixOL, sCT, s, jce)
calculate eta J at cell edges
subroutine mhd_check_w_semirelati(primitive, ixIL, ixOL, w, flag)
subroutine mhd_check_w_hde(primitive, ixIL, ixOL, w, flag)
double precision, public mhd_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
Definition: mod_mhd_phys.t:35
subroutine mhd_get_cmax_semirelati(w, x, ixIL, ixOL, idim, cmax)
Calculate cmax_idim for semirelativistic MHD.
subroutine mhd_get_jxbxb(w, x, ixIL, ixOL, res)
subroutine mhd_get_h_speed(wprim, x, ixIL, ixOL, idim, Hspeed)
get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
subroutine mhd_add_source(qdt, dtfactor, ixIL, ixOL, wCT, wCTprim, w, x, qsourcesplit, active)
w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixIL, ixOL, subname)
subroutine fixdivb_boundary(ixGL, ixOL, w, x, iB)
subroutine mhd_get_flux_hde(wC, w, x, ixIL, ixOL, idim, f)
Calculate fluxes with hydrodynamic energy equation.
subroutine, public get_normalized_divb(w, ixIL, ixOL, divb)
get dimensionless div B = |divB| * volume / area / |B|
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
Definition: mod_mhd_phys.t:49
subroutine get_flux_on_cell_face(ixIL, ixOL, ff, src)
use cell-center flux to get cell-face flux and get the source term as the divergence of the flux
logical, public, protected mhd_viscosity
Whether viscosity is added.
Definition: mod_mhd_phys.t:111
subroutine mhd_ei_to_e_hde(ixIL, ixOL, w, x)
Transform internal energy to hydrodynamic energy.
subroutine mhd_get_pthermal_semirelati(w, x, ixIL, ixOL, pth)
Calculate thermal pressure.
subroutine mhd_get_p_total(w, x, ixIL, ixOL, p)
Calculate total pressure within ixO^L including magnetic pressure.
double precision, public, protected mhd_reduced_c
Reduced speed of light for semirelativistic MHD: 2% of light speed.
Definition: mod_mhd_phys.t:37
logical, public, protected mhd_energy
Whether an energy equation is used.
Definition: mod_mhd_phys.t:103
subroutine mhd_to_conserved_inte(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
logical, public, protected mhd_ambipolar_exp
Whether Ambipolar term is implemented explicitly.
Definition: mod_mhd_phys.t:123
subroutine get_ambipolar_electric_field(ixIL, ixOL, w, x, fE)
get ambipolar electric field on cell edges
logical, public, protected mhd_glm
Whether GLM-MHD is used to control div B.
Definition: mod_mhd_phys.t:129
subroutine mhd_update_temperature(ixIL, ixOL, wCT, w, x)
subroutine mhd_get_pthermal_iso(w, x, ixIL, ixOL, pth)
Calculate isothermal thermal pressure.
subroutine mhd_to_primitive_semirelati(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
logical, public clean_initial_divb
clean initial divB
Definition: mod_mhd_phys.t:168
subroutine mhd_get_temperature_from_etot_with_equi(w, x, ixIL, ixOL, res)
subroutine mhd_to_primitive_hde(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
subroutine update_faces_average(ixIL, ixOL, qt, qdt, fC, fE, sCT, s)
get electric field though averaging neighors to update faces in CT
procedure(sub_convert), pointer, public mhd_to_conserved
Definition: mod_mhd_phys.t:221
subroutine mhd_update_faces(ixIL, ixOL, qt, qdt, wprim, fC, fE, sCT, s, vcts)
subroutine mhd_get_csound_prim(w, x, ixIL, ixOL, idim, csound)
Calculate fast magnetosonic wave speed.
double precision, public mhd_eta
The MHD resistivity.
Definition: mod_mhd_phys.t:22
logical, public divbwave
Add divB wave in Roe solver.
Definition: mod_mhd_phys.t:166
subroutine, public mhd_get_csound2(w, x, ixIL, ixOL, csound2)
Calculate the square of the thermal sound speed csound2 within ixO^L. csound2=gamma*p/rho.
double precision function, dimension(ixo^s) mhd_mag_en(w, ixIL, ixOL)
Compute evolving magnetic energy.
logical, public, protected mhd_magnetofriction
Whether magnetofriction is added.
Definition: mod_mhd_phys.t:127
subroutine mhd_get_v_origin(w, x, ixIL, ixOL, v)
Calculate v vector.
subroutine add_pe0_divv(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
double precision, public, protected mhd_trac_mask
Height of the mask used in the TRAC method.
Definition: mod_mhd_phys.t:32
procedure(mask_subroutine), pointer, public usr_mask_ambipolar
Definition: mod_mhd_phys.t:219
subroutine mhd_check_w_inte(primitive, ixIL, ixOL, w, flag)
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
Definition: mod_mhd_phys.t:186
subroutine sts_set_source_ambipolar(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux)
Sets the sources for the ambipolar this is used for the STS method.
logical, public, protected mhd_thermal_conduction
Whether thermal conduction is used.
Definition: mod_mhd_phys.t:105
procedure(sub_get_pthermal), pointer, public mhd_get_temperature
Definition: mod_mhd_phys.t:225
integer, public equi_pe0_
Definition: mod_mhd_phys.t:63
subroutine mhd_getv_hall(w, x, ixIL, ixOL, vHall)
double precision function get_ambipolar_dt(w, ixIL, ixOL, dxD, x)
Calculates the explicit dt for the ambipokar term This function is used by both explicit scheme and S...
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
Definition: mod_mhd_phys.t:73
subroutine add_source_janhunen(qdt, ixIL, ixOL, wCT, w, x)
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
Definition: mod_mhd_phys.t:52
subroutine mhd_get_temperature_from_eint(w, x, ixIL, ixOL, res)
Calculate temperature=p/rho when in e_ the internal energy is stored.
procedure(sub_convert), pointer, public mhd_to_primitive
Definition: mod_mhd_phys.t:220
logical, public has_equi_pe0
whether split off equilibrium thermal pressure
Definition: mod_mhd_phys.t:157
subroutine mhd_add_source_geom(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
logical, public, protected mhd_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
Definition: mod_mhd_phys.t:160
logical, public, protected mhd_particles
Whether particles module is added.
Definition: mod_mhd_phys.t:125
subroutine add_source_res2(qdt, ixIL, ixOL, wCT, w, x)
Add resistive source to w within ixO Uses 5 point stencil (2 neighbours) in each direction,...
subroutine mhd_get_pthermal_hde(w, x, ixIL, ixOL, pth)
Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho) within ixO^L.
subroutine mhd_get_flux_split(wC, w, x, ixIL, ixOL, idim, f)
Calculate fluxes within ixO^L with possible splitting.
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
Definition: mod_mhd_phys.t:174
double precision, public mhd_etah
Hall resistivity.
Definition: mod_mhd_phys.t:26
subroutine rfactor_from_constant_ionization(w, x, ixIL, ixOL, Rfactor)
subroutine add_hypertc_source(qdt, ixIL, ixOL, wCT, w, x, wCTprim)
subroutine mhd_get_rho_equi(w, x, ixIL, ixOL, res)
subroutine mhd_get_cbounds_semirelati(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
Estimating bounds for the minimum and maximum signal velocities without split.
subroutine mhd_ei_to_e_semirelati(ixIL, ixOL, w, x)
Transform internal energy to total energy and velocity to momentum.
double precision, public mhd_eta_ambi
The MHD ambipolar coefficient.
Definition: mod_mhd_phys.t:28
subroutine get_lorentz_force(ixIL, ixOL, w, JxB)
Compute the Lorentz force (JxB)
subroutine add_source_b0split(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
Source terms after split off time-independent magnetic field.
subroutine mhd_handle_small_ei(w, x, ixIL, ixOL, ie, subname)
handle small or negative internal energy
logical, public, protected mhd_hydrodynamic_e
Whether hydrodynamic energy is solved instead of total energy.
Definition: mod_mhd_phys.t:142
subroutine mhd_handle_small_values_hde(primitive, w, x, ixIL, ixOL, subname)
subroutine, public mhd_phys_init()
Definition: mod_mhd_phys.t:304
logical, public, protected mhd_trac
Whether TRAC method is used.
Definition: mod_mhd_phys.t:133
logical, public, protected eq_state_units
Definition: mod_mhd_phys.t:172
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
Definition: mod_mhd_phys.t:196
subroutine rc_params_read(fl)
subroutine mhd_handle_small_values_inte(primitive, w, x, ixIL, ixOL, subname)
subroutine mhd_get_flux_semirelati(wC, w, x, ixIL, ixOL, idim, f)
Calculate semirelativistic fluxes within ixO^L without any splitting.
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
Definition: mod_mhd_phys.t:84
subroutine mhd_check_w_origin(primitive, ixIL, ixOL, w, flag)
subroutine mhd_to_primitive_split_rho(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
subroutine mhd_to_primitive_origin(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
integer, public, protected rho_
Index of the density (in the w array)
Definition: mod_mhd_phys.t:67
subroutine, public mhd_get_v_idim(w, x, ixIL, ixOL, idim, v)
Calculate v component.
double precision function, dimension(ixo^s) mhd_kin_en_origin(w, ixIL, ixOL, inv_rho)
compute kinetic energy
procedure(fun_kin_en), pointer, public mhd_kin_en
Definition: mod_mhd_phys.t:227
subroutine, public multiplyambicoef(ixIL, ixOL, res, w, x)
multiply res by the ambipolar coefficient The ambipolar coefficient is calculated as -mhd_eta_ambi/rh...
logical, public, protected b0field_forcefree
B0 field is force-free.
Definition: mod_mhd_phys.t:176
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
Definition: mod_mhd_phys.t:90
subroutine mhd_write_info(fh)
Write this module's parameters to a snapsoht.
Definition: mod_mhd_phys.t:286
integer, public, protected tweight_
Definition: mod_mhd_phys.t:82
subroutine mhd_physical_units()
logical, public, protected mhd_ambipolar_sts
Whether Ambipolar term is implemented using supertimestepping.
Definition: mod_mhd_phys.t:121
procedure(sub_get_pthermal), pointer, public mhd_get_pthermal
Definition: mod_mhd_phys.t:223
subroutine mhd_get_cbounds_split_rho(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
Estimating bounds for the minimum and maximum signal velocities with rho split.
double precision function, dimension(ixo^s), public mhd_mag_en_all(w, ixIL, ixOL)
Compute 2 times total magnetic energy.
subroutine mhd_add_source_geom_split(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
integer, public, protected e_
Index of the energy density (-1 if not present)
Definition: mod_mhd_phys.t:71
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
Definition: mod_mhd_phys.t:43
logical, public, protected mhd_4th_order
MHD fourth order.
Definition: mod_mhd_phys.t:153
subroutine mhd_get_temperature_equi(w, x, ixIL, ixOL, res)
subroutine mhd_get_csound_semirelati(w, x, ixIL, ixOL, idim, csound, gamma2)
Calculate cmax_idim for semirelativistic MHD.
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
Definition: mod_mhd_phys.t:81
subroutine set_equi_vars_grid_faces(igrid, x, ixIL, ixOL)
sets the equilibrium variables
subroutine rfactor_from_temperature_ionization(w, x, ixIL, ixOL, Rfactor)
subroutine mhd_e_to_ei_hde(ixIL, ixOL, w, x)
Transform hydrodynamic energy to internal energy.
integer, public, protected psi_
Indices of the GLM psi.
Definition: mod_mhd_phys.t:77
subroutine mhd_boundary_adjust(igrid, psb)
logical, public mhd_equi_thermal
Definition: mod_mhd_phys.t:158
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
Module containing all the particle routines.
Definition: mod_particles.t:2
subroutine particles_init()
Initialize particle data and parameters.
Definition: mod_particles.t:15
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 including rotating frame in (magneto)hydrodynamics simulations The rotation vector is assu...
subroutine rotating_frame_add_source(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine rotating_frame_init()
Initialize the module.
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 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, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
double precision function, public get_tc_dt_mhd(w, ixIL, ixOL, dxD, x, fl)
Get the explicut timestep for the TC (mhd implementation)
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(special_resistivity), pointer usr_special_resistivity
procedure(phys_gravity), pointer usr_gravity
procedure(set_equi_vars), pointer usr_set_equi_vars
procedure(set_electric_field), pointer usr_set_electric_field
procedure(set_wlr), pointer usr_set_wlr
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:89
subroutine viscosity_init(phys_wider_stencil, phys_req_diagonal)
Initialize the module.
Definition: mod_viscosity.t:58
The data structure that contains information about a tree node/grid block.
Definition: mod_forest.t:11