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