MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
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_fld, only: fld_fluid
11 use mod_physics
12 use mod_eos
13 use mod_comm_lib, only: mpistop
15
16 implicit none
17 private
18
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 !> Height of the mask used in the TRAC method
30 double precision, public, protected :: mhd_trac_mask = 0.d0
31 !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
32 !> taking values within [0, 1]
33 double precision, public :: mhd_glm_alpha = 0.5d0
34 !> Reduced speed of light for semirelativistic MHD: 2% of light speed
35 double precision, public, protected :: mhd_reduced_c = 0.02d0*const_c
36 !> The thermal conductivity kappa in hyperbolic thermal conduction
37 double precision, public :: mhd_hyperbolic_tc_kappa = 0.d0
38 logical, public :: mhd_hyperbolic_tc_constant = .false.
39 !> Coefficient of diffusive divB cleaning
40 double precision, public :: divbdiff = 0.8d0
41 !> Ionization fraction of H
42 !> H_ion_fr = H+/(H+ + H)
43 double precision, public, protected :: h_ion_fr=1d0
44 !> Ionization fraction of He
45 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
46 double precision, public, protected :: he_ion_fr=1d0
47 !> Ratio of number He2+ / number He+ + He2+
48 !> He_ion_fr2 = He2+/(He2+ + He+)
49 double precision, public, protected :: he_ion_fr2=1d0
50 ! used for eq of state when it is not defined by units,
51 ! the units do not contain terms related to ionization fraction
52 ! and it is p = RR * rho * T
53 double precision, public, protected :: rr=1d0
54 !> inverse of squared speed of light c0 and reduced speed of light c
55 double precision :: inv_squared_c0=0.d0, inv_squared_c=0.d0
56 !> equi vars indices in the state%equi_vars array
57 integer, public :: equi_rho0_ = -1
58 integer, public :: equi_pe0_ = -1
59 !> Number of tracer species
60 integer, public, protected :: mhd_n_tracer = 0
61 !> Index of the density (in the w array)
62 integer, public, protected :: rho_
63 !> Indices of the momentum density
64 integer, allocatable, public, protected :: mom(:)
65 !> Indices of the momentum density for the form of better vectorization
66 integer, public, protected :: ^c&m^C_
67 !> Index of the energy density (-1 if not present)
68 integer, public, protected :: e_
69 !> Indices of the magnetic field for the form of better vectorization
70 integer, public, protected :: ^c&b^C_
71 !> Index of the gas pressure (-1 if not present) should equal e_
72 integer, public, protected :: p_
73 !> Index of the electron number density for LTE module
74 integer, public, protected :: ne_
75 !> Index of the field-aligned heat flux q_parallel
76 integer, public, protected :: qpar_
77 !> Index of the perpendicular heat flux q_perp
78 integer, public, protected :: qperp_
79 !> Indices of the GLM psi
80 integer, public, protected :: psi_
81 !> Index of the radiation energy
82 integer, public, protected :: r_e
83 !> Indices of temperature
84 integer, public, protected :: te_
85 !> Index of the FIP passive scalar rho*fip in conserved form, fip in primitive form
86 integer, public, protected :: fip_ = -1
87 !> Whether FIP passive scalar is enabled
88 logical, public, protected :: mhd_fip = .false.
89 !> Enable the Uniturbulence and Alfven Wave Solar Model extension
90 logical, public, protected :: mhd_uawsom = .false.
91 !> Enable conservative Alfvén reflection (one-dimensional or Cartesian gradient-vorticity)
92 logical, public, protected :: mhd_uawsom_reflection = .false.
93 !> Algebra used by the Alfven-wave reflection source. one_dimensional_gradient
94 !> retains the original one-dimensional source; cartesian_gradient_vorticity
95 !> is the multidimensional gradient/vorticity closure.
96 character(len=std_len), public, protected :: mhd_uawsom_reflection_mode = 'one_dimensional_gradient'
97 !> Enable conservative kink-wave reflection from the kink-speed gradient
98 logical, public, protected :: mhd_uawsom_kink_reflection = .false.
99 !> Dimensionless multiplier in the one_dimensional_gradient source only
100 double precision, public, protected :: mhd_uawsom_sigma = 0.d0
101 !> Cartesian direction used for the prescribed density contrast and reflection gradient
102 integer, public, protected :: mhd_uawsom_height_dim = -1
103 !> Base transverse density contrast and filling factor
104 double precision, public, protected :: mhd_uawsom_zeta0 = 5.d0
105 double precision, public, protected :: mhd_uawsom_filling_factor = 0.1d0
106 !> Physical input scales (lengths and magnetic field); converted to code units at init
107 double precision, public, protected :: mhd_uawsom_zeta_scale = -1.d0
108 double precision, public, protected :: mhd_uawsom_thread_radius0 = -1.d0
109 double precision, public, protected :: mhd_uawsom_bref = -1.d0
110 double precision, public, protected :: mhd_uawsom_alfven_corr_length0 = -1.d0
111 !> Conserved wave-energy indices. The plus variables propagate against B.
112 integer, public, protected :: waplus_=-1, waminus_=-1, wkplus_=-1, wkminus_=-1
113 !> Index of the cutoff temperature for the TRAC method
114 integer, public, protected :: tcoff_
115 integer, public, protected :: tweight_
116 !> Indices of the tracers
117 integer, allocatable, public, protected :: tracer(:)
118 !> The number of waves
119 integer :: nwwave=8
120 !> Method type of divb in a integer for good performance
121 integer :: type_divb
122 !> To skip * layer of ghost cells during divB=0 fix for boundary
123 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
124 ! DivB cleaning methods
125 integer, parameter :: divb_none = 0
126 integer, parameter :: divb_multigrid = -1
127 integer, parameter :: divb_glm = 1
128 integer, parameter :: divb_powel = 2
129 integer, parameter :: divb_janhunen = 3
130 integer, parameter :: divb_linde = 4
131 integer, parameter :: divb_lindejanhunen = 5
132 integer, parameter :: divb_lindepowel = 6
133 integer, parameter :: divb_lindeglm = 7
134 integer, parameter :: divb_ct = 8
135 !> Whether an energy equation is used
136 logical, public, protected :: mhd_energy = .true.
137 !> Whether thermal conduction is used
138 logical, public, protected :: mhd_thermal_conduction = .false.
139 !> Whether radiative cooling is added
140 logical, public, protected :: mhd_radiative_cooling = .false.
141 !> Whether thermal conduction is used
142 logical, public, protected :: mhd_hyperbolic_tc = .false.
143 !> Whether saturation is considered for hyperbolic TC. When the perpendicular
144 !> channel is active, the limiter uses sqrt(q_parallel^2+q_perp^2).
145 logical, public, protected :: mhd_hyperbolic_tc_sat = .false.
146 !> Whether the perpendicular hyperbolic-TC channel is enabled
147 logical, public, protected :: mhd_hyperbolic_tc_use_perp = .false.
148 !> Perpendicular hyperbolic-TC closure mode:
149 !> 'off' = disabled
150 !> 'fixed_reference' = fixed classical ratio at the reference normalisation
151 !> 'weak_field_isotropization' = empirical transition using a prescribed Bmin
152 !> 'electron_magnetization' = simplified ratio 1/(1+chi_e^2)
153 character(len=std_len), public, protected :: mhd_hyperbolic_tc_perp_mode = 'off'
154 !> Relative perpendicular hyperbolic-TC coefficient in fixed/strong-field limit:
155 !> kappa_perp0 = mhd_hyperbolic_tc_kappa_perp_factor * kappa_parallel
156 double precision, public, protected :: mhd_hyperbolic_tc_kappa_perp_factor = 0.d0
157 !> Field-strength transition scale for perpendicular closure
158 double precision, public, protected :: mhd_hyperbolic_tc_bmin = 0.d0
159 !> Constant Coulomb logarithm used by the simplified electron-magnetization
160 !> closure. It is a namelist parameter so changing it has no per-cell cost.
161 double precision, public, protected :: mhd_hyperbolic_tc_coulomb_log = 20.d0
162 !> Whether viscosity is added
163 logical, public, protected :: mhd_viscosity = .false.
164 !> Whether gravity is added
165 logical, public, protected :: mhd_gravity = .false.
166 !> Whether rotating frame is activated
167 logical, public, protected :: mhd_rotating_frame = .false.
168 !> Whether Hall-MHD is used
169 logical, public, protected :: mhd_hall = .false.
170 !> Whether Ambipolar term is used
171 logical, public, protected :: mhd_ambipolar = .false.
172 !> Whether Ambipolar term is implemented using supertimestepping
173 logical, public, protected :: mhd_ambipolar_sts = .false.
174 !> Whether Ambipolar term is implemented explicitly
175 logical, public, protected :: mhd_ambipolar_exp = .false.
176 !> Whether particles module is added
177 logical, public, protected :: mhd_particles = .false.
178 !> Whether magnetofriction is added
179 logical, public, protected :: mhd_magnetofriction = .false.
180 !> Whether GLM-MHD is used to control div B
181 logical, public, protected :: mhd_glm = .false.
182 !> Whether extended GLM-MHD is used with additional sources
183 logical, public, protected :: mhd_glm_extended = .true.
184 !> Whether TRAC method is used
185 logical, public, protected :: mhd_trac = .false.
186 !> Which TRAC method is used
187 integer, public, protected :: mhd_trac_type=1
188 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
189 integer, public, protected :: mhd_trac_finegrid=4
190 !> TRAC-7 (Johnston 2021, A&A 654 A2): target number of cells resolving the TR
191 double precision, public, protected :: mhd_trac_delta=0.5d0
192 !> Whether internal energy is solved instead of total energy
193 logical, public, protected :: mhd_internal_e = .false.
194 !> Whether hydrodynamic energy is solved instead of total energy
195 logical, public, protected :: mhd_hydrodynamic_e = .false.
196 !> Whether divB cleaning sources are added splitting from fluid solver
197 logical, public, protected :: source_split_divb = .false.
198 !> Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved
199 logical, public, protected :: mhd_semirelativistic = .false.
200 !> Whether plasma is partially ionized
201 !> Whether CAK radiation line force is activated
202 logical, public, protected :: mhd_cak_force = .false.
203 !> Whether radiation-gas interaction is handled using flux limited diffusion
204 logical, public, protected :: mhd_radiation_fld = .false.
205 logical, public, protected :: mhd_fld_pradtensor= .true.
206 !> Radiation fluid object (gas-EoS callbacks for FLD), wired in mhd_link_eos
207 type(fld_fluid), allocatable, public :: fld_fl
208 !> whether split off equilibrium density and pressure
209 logical, public :: has_equi_rho_and_p = .false.
210 logical, public :: mhd_equi_thermal = .false.
211 !> whether dump full variables (when splitting is used) in a separate dat file
212 logical, public, protected :: mhd_dump_full_vars = .false.
213 !> Whether divB is computed with a fourth order approximation
214 integer, public, protected :: mhd_divb_nth = 1
215 !> Add divB wave in Roe solver
216 logical, public :: divbwave = .true.
217 !> clean initial divB
218 logical, public :: clean_initial_divb = .false.
219 !> To control divB=0 fix for boundary
220 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
221 !> B0 field is force-free
222 logical, public, protected :: b0field_forcefree=.true.
223 !> Whether an total energy equation is used
224 logical :: total_energy = .true.
225 !> Whether numerical resistive heating is included when solving partial energy equation
226 logical, public :: numerical_resistive_heating = .false.
227 !> Whether gravity work is included in energy equation
228 logical :: gravity_energy
229 !> Method type to clean divergence of B
230 character(len=std_len), public, protected :: typedivbfix = 'linde'
231 !> Method type of constrained transport
232 character(len=std_len), public, protected :: type_ct = 'uct_contact'
233 !> Update all equations due to divB cleaning
234 character(len=std_len) :: typedivbdiff = 'all'
235 !> type of fluid for thermal conduction
236 type(tc_fluid), public, allocatable :: tc_fl
237 !> type of fluid for thermal emission synthesis
238 type(te_fluid), public, allocatable :: te_fl_mhd
239 !> type of fluid for radiative cooling
240 type(rc_fluid), public, allocatable :: rc_fl
241
242 !define the subroutine interface for the ambipolar mask
243 abstract interface
244
245 subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
247 integer, intent(in) :: ixi^l, ixo^l
248 double precision, intent(in) :: x(ixi^s,1:ndim)
249 double precision, intent(in) :: w(ixi^s,1:nw)
250 double precision, intent(inout) :: res(ixi^s)
251 end subroutine mask_subroutine
252
253 end interface
254
255 procedure(mask_subroutine), pointer :: usr_mask_ambipolar => null()
256 procedure(sub_small_values), pointer :: mhd_handle_small_values => null()
257 ! Public methods
258 public :: usr_mask_ambipolar
259 public :: mhd_phys_init
260 public :: mhd_get_v
261 public :: mhd_get_rho
262 public :: mhd_e_to_ei
263 public :: mhd_ei_to_e
264 public :: mhd_face_to_center
265 public :: get_divb
266 public :: get_current
267 !> needed public if we want to use the ambipolar coefficient in the user file
268 public :: multiplyambicoef
269 public :: get_normalized_divb
271 public :: mhd_mag_en_all
273 public :: mhd_uawsom_rho2_factor
276 {^nooned
278 }
279 ! Begin: following relevant for radiative MHD using FLD
280 ! first four are local and only of interest for mod_usr applications
281 ! where they can be used in diagnostics
282 ! NOTE those with _prim expect primitives on entry
284 public :: mhd_get_csrad2
285 public :: mhd_get_trad
287 ! as pointer phys_get_csrad2
288 public :: mhd_get_csrad2_prim
289 ! End: following relevant for radiative MHD using FLD
290 ! Removed orphan public declarations: mhd_get_Rfactor, mhd_get_temperature_from_prim,
291 ! mhd_get_temperature_from_etot. These functions live in mod_mhd_eos.t and are
292 ! reached via the eos% / phys_get_Rfactor / phys_get_tgas / phys_get_temperature
293 ! procedure pointers bound by mod_mhd_eos:bind_eos_to_source.
294
295contains
296
297 !> Read this module"s parameters from a file
298 subroutine mhd_read_params(files)
300 use mod_particles, only: particles_eta, particles_etah
301 character(len=*), intent(in) :: files(:)
302 integer :: n
303
304 namelist /mhd_list/ mhd_energy, mhd_n_tracer, mhd_adiab,&
308 typedivbdiff, type_ct, divbwave, &
311 particles_eta, particles_etah,has_equi_rho_and_p,mhd_equi_thermal,&
326
327 do n = 1, size(files)
328 open(unitpar, file=trim(files(n)), status="old")
329 read(unitpar, mhd_list, end=111)
330111 close(unitpar)
331 end do
332
333 ! He_abundance is set in eos_list and accessed via eos%He_abundance
334
335 end subroutine mhd_read_params
336
337 !> Write this module's parameters to a snapsoht
338 subroutine mhd_write_info(fh)
340 integer, intent(in) :: fh
341
342 integer :: er
343 integer, parameter :: n_par = 1
344 double precision :: values(n_par)
345 integer, dimension(MPI_STATUS_SIZE) :: st
346 character(len=name_len) :: names(n_par)
347
348 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
349
350 names(1) = "gamma"
351 values(1) = eos%gamma
352 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
353 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
354 end subroutine mhd_write_info
355
356 subroutine mhd_phys_init()
361 use mod_gravity, only: gravity_init
366 use mod_cak_force, only: cak_init
368 use mod_geometry
370 {^nooned
372 }
373 use mod_fld
374
375 integer :: itr, idir
376
377 call mhd_read_params(par_files)
379
380 if(mhd_internal_e) then
381 if(mhd_hydrodynamic_e) then
382 mhd_hydrodynamic_e=.false.
383 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_internal_e=T'
384 end if
385 if(has_equi_rho_and_p) then
386 has_equi_rho_and_p=.false.
387 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_internal_e=T'
388 end if
389 end if
390
391 if(mhd_hydrodynamic_e) then
392 if(mhd_internal_e) then
393 mhd_internal_e=.false.
394 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_hydrodynamic_e=T'
395 end if
396 if(b0field) then
397 b0field=.false.
398 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_hydrodynamic_e=T'
399 end if
400 if(has_equi_rho_and_p) then
401 has_equi_rho_and_p=.false.
402 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_hydrodynamic_e=T'
403 end if
404 end if
405
406 if(mhd_semirelativistic) then
407 if(b0field) then
408 b0field=.false.
409 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_semirelativistic=T'
410 endif
411 if(has_equi_rho_and_p) then
412 has_equi_rho_and_p=.false.
413 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_semirelativistic=T'
414 end if
415 if(mhd_hydrodynamic_e) then
416 mhd_hydrodynamic_e=.false.
417 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_semirelativistic=T'
418 end if
419 end if
420
421 if(.not. mhd_energy) then
422 if(mhd_internal_e) then
423 mhd_internal_e=.false.
424 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_energy=F'
425 end if
426 if(mhd_hydrodynamic_e) then
427 mhd_hydrodynamic_e=.false.
428 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_energy=F'
429 end if
432 if(mype==0) write(*,*) 'WARNING: set mhd_thermal_conduction=F when mhd_energy=F'
433 end if
434 if(mhd_hyperbolic_tc) then
435 mhd_hyperbolic_tc=.false.
436 if(mype==0) write(*,*) 'WARNING: set mhd_hyperbolic_tc=F when mhd_energy=F'
437 end if
438 if(mhd_radiative_cooling) then
440 if(mype==0) write(*,*) 'WARNING: set mhd_radiative_cooling=F when mhd_energy=F'
441 end if
442 if(mhd_trac) then
443 mhd_trac=.false.
444 if(mype==0) write(*,*) 'WARNING: set mhd_trac=F when mhd_energy=F'
445 end if
446 if(b0field) then
447 b0field=.false.
448 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_energy=F'
449 end if
450 if(has_equi_rho_and_p) then
451 has_equi_rho_and_p=.false.
452 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_energy=F'
453 end if
454 end if
455
458 if(mype==0) write(*,*) 'WARNING: set either parabolic TC or hyperbolic TC to F'
459 if(mype==0) write(*,*) 'WARNING: defaulting to only mhd_hyperbolic_tc=T'
460 end if
461 {^ifoned
463 call mpistop("mhd_hyperbolic_tc_use_perp is not supported in 1D")
464 end if
465 }
466
467 physics_type = "mhd"
468 phys_energy=mhd_energy
469 phys_internal_e=mhd_internal_e
472
473 phys_gamma = eos%gamma
475
476 if(mhd_energy) then
478 total_energy=.false.
479 else
481 total_energy=.true.
482 end if
483 else
484 total_energy=.false.
485 end if
486 phys_total_energy=total_energy
487 if(mhd_energy) then
488 if(mhd_internal_e) then
489 gravity_energy=.false.
490 else
491 gravity_energy=.true.
492 end if
493 else
494 gravity_energy=.false.
495 end if
496
497 {^ifoned
498 if(mhd_trac .and. mhd_trac_type .gt. 2) then
500 if(mype==0) write(*,*) 'WARNING: reset mhd_trac_type=1 for 1D simulation'
501 end if
502 }
503 if(mhd_trac .and. mhd_trac_type .le. 4) then
504 mhd_trac_mask=bigdouble
505 if(mype==0) write(*,*) 'WARNING: set mhd_trac_mask==bigdouble for global TRAC method'
506 end if
507 if(mhd_trac .and. mhd_trac_type==7) then
508 ! per-cell local TRAC (Johnston 2021) needs the background heating rate for the
509 ! steady-state balance; it is field-aligned and per-cell, so no global trac_mask is used.
510 if(.not. associated(usr_get_heating)) &
511 call mpistop("mhd_trac_type=7 requires usr_get_heating to be set in mod_usr.t")
512 end if
514
516 if(ndim==1) typedivbfix='none'
517 select case (typedivbfix)
518 case ('none')
519 type_divb = divb_none
520 {^nooned
521 case ('multigrid')
522 if(mhd_radiation_fld) call mpistop('To verify whether mg usage for FLD versus divB can be combined')
523 type_divb = divb_multigrid
524 use_multigrid = .true.
525 mg%operator_type = mg_laplacian
526 phys_global_source_after => mhd_clean_divb_multigrid
527 }
528 case ('glm')
529 mhd_glm = .true.
530 need_global_cmax = .true.
531 type_divb = divb_glm
532 case ('powel', 'powell')
533 type_divb = divb_powel
534 case ('janhunen')
535 type_divb = divb_janhunen
536 case ('linde')
537 type_divb = divb_linde
538 case ('lindejanhunen')
539 type_divb = divb_lindejanhunen
540 case ('lindepowel')
541 type_divb = divb_lindepowel
542 case ('lindeglm')
543 mhd_glm = .true.
544 need_global_cmax = .true.
545 type_divb = divb_lindeglm
546 case ('ct')
547 type_divb = divb_ct
548 stagger_grid = .true.
549 case default
550 call mpistop('Unknown divB fix')
551 end select
552
553 allocate(start_indices(number_species),stop_indices(number_species))
554 ! set the index of the first flux variable for species 1
555 start_indices(1)=1
556 ! Determine flux variables
557 rho_ = var_set_rho()
558
559 allocate(mom(ndir))
560 mom(:) = var_set_momentum(ndir)
561 m^c_=mom(^c);
562
563 ! Set index of energy variable
564 if (mhd_energy) then
565 nwwave = 8
566 e_ = var_set_energy() ! energy density
567 p_ = e_ ! gas pressure
568 else
569 nwwave = 7
570 e_ = -1
571 p_ = -1
572 end if
573
574 allocate(mag(ndir))
575 mag(:) = var_set_bfield(ndir)
576 b^c_=mag(^c);
577
578 if (mhd_glm) then
579 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
580 else
581 psi_ = -1
582 end if
583
584 if(mhd_hyperbolic_tc) then
585 qpar_ = var_set_fluxvar('q', 'q', need_bc=.false.)
587 qperp_ = var_set_fluxvar('qperp', 'qperp', need_bc=.false.)
588 else
589 qperp_ = -1
590 end if
591 need_global_cmax=.true.
592 else
593 qpar_ = -1
594 qperp_ = -1
595 end if
596
597 if (mhd_fip) then
598 fip_ = var_set_fluxvar('rho_fip', 'fip', need_bc=.false.)
599 else
600 fip_ = -1
601 end if
602
603 if (mhd_uawsom) then
604 waplus_ = var_set_fluxvar('wAplus', 'wAplus')
605 waminus_ = var_set_fluxvar('wAminus', 'wAminus')
606 wkplus_ = var_set_fluxvar('wkplus', 'wkplus')
607 wkminus_ = var_set_fluxvar('wkminus', 'wkminus')
608 else
609 waplus_=-1; waminus_=-1; wkplus_=-1; wkminus_=-1
610 end if
611
612 allocate(tracer(mhd_n_tracer))
613 ! Set starting index of tracers
614 do itr = 1, mhd_n_tracer
615 tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
616 end do
617
618 if(mhd_radiation_fld)then
619 if(mhd_cak_force)then
620 if(mype==0) then
621 write(*,*)'Warning: CAK force addition together with FLD radiation'
622 endif
623 endif
625 if(mype==0) then
626 write(*,*)'Warning: Optically thin cooling together with FLD radiation'
627 endif
628 endif
629 if(.not.mhd_energy)then
630 call mpistop('using FLD implies the use of an energy equation, set mhd_energy=T')
631 else
633 call mpistop('using FLD not yet with semirelativistic energy formalism')
634 endif
636 call mpistop('using FLD not yet with hydrodynamic or internal energy formalism')
637 endif
638 if(has_equi_rho_and_p)then
639 call mpistop('using FLD not yet with split off rho and p')
640 endif
641 ! Note: so far ok with total energy equation but allow both split or unsplit B0
642 !> set added variable and equation for radiation energy
643 r_e = var_set_radiation_energy()
644 phys_get_csrad2 => mhd_get_csrad2_prim
645 !> Radiation fluid object: its EoS callbacks are wired in mhd_link_eos
646 allocate(fld_fl)
647 !> Initiate radiation-closure module
648 call fld_init()
649 !> The implicit (MG diffusion) hooks need the fld_fl object, so they
650 !> are wired here to physics-module wrappers that inject it.
651 if(use_multigrid)then
652 phys_implicit_update => mhd_fld_implicit_update
653 phys_evaluate_implicit => mhd_fld_evaluate_implicit
654 endif
655 endif
656 else
657 r_e=-1
658 endif
659
660 ! LTE/PI electron-density and temperature aux variables. These must be registered
661 ! after every flux variable (including the FLD radiation energy r_e and any tracers):
662 ! var_set_radiation_energy indexes by nwflux, so if r_e is registered after these
663 ! nw-indexed aux vars its nwflux slot collides with Ne_ (iw_r_e==iw_ne) and overwrites
664 ! its name. Registering them here keeps the flux block contiguous.
665 if (eos%eos_type == 'LTE') then
666 ne_ = var_set_ne()
667 te_ = var_set_te()
668 else if (eos%eos_type == 'PI') then
669 ne_ = -1
670 te_ = var_set_te()
671 else
672 ne_ = -1
673 te_ = -1
674 end if
675
676 ! set number of variables which need update ghostcells
677 ! set number of variables which need update ghostcells.
678 ! The EoS-derived slots Ne/Te are derived state that must stay consistent with (rho,e)
679 ! wherever the conserved state is valid, so they have to travel with it. var_set_ne /
680 ! var_set_te bump nw but neither nwflux nor nwaux, so the historic nwflux+nwaux silently
681 ! excluded them: they were never communicated, only derived, and every ghost cell held
682 ! zero until something derived it. Extend the window to whichever of them exist (they are
683 ! registered contiguously just above); FI leaves both at -1 and the window is unchanged.
684 ! bc_phys is unaffected -- it iterates nwflux+nwaux independently.
685 nwgc=nwflux+nwaux
686 if (iw_ne > 0) nwgc = max(nwgc, iw_ne)
687 if (iw_te > 0) nwgc = max(nwgc, iw_te)
688
689 ! set the index of the last flux variable for species 1
690 stop_indices(1)=nwflux
691
692 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
693 tweight_ = -1
694 if(mhd_trac) then
695 tcoff_ = var_set_wextra()
696 iw_tcoff=tcoff_
697 if(mhd_trac_type .ge. 3) then
698 tweight_ = var_set_wextra()
699 endif
700 else
701 tcoff_ = -1
702 end if
703
704 ! set indices of equi vars and update number_equi_vars
706 if(has_equi_rho_and_p) then
709 iw_equi_rho = equi_rho0_
712 iw_equi_p = equi_pe0_
713 endif
714 ! determine number of stagger variables
715 nws=ndim
716
717 nvector = 2 ! No. vector vars
718 allocate(iw_vector(nvector))
719 iw_vector(1) = mom(1) - 1
720 iw_vector(2) = mag(1) - 1
721
722 ! Check whether custom flux types have been defined
723 if (.not. allocated(flux_type)) then
724 allocate(flux_type(ndir, nwflux))
725 flux_type = flux_default
726 else if (any(shape(flux_type) /= [ndir, nwflux])) then
727 call mpistop("phys_check error: flux_type has wrong shape")
728 end if
729
730 if(nwflux>mag(ndir)) then
731 ! for flux of tracers, using hll flux
732 flux_type(:,mag(ndir)+1:nwflux)=flux_hll
733 end if
734
735 if(ndim>1) then
736 if(mhd_glm) then
737 flux_type(:,psi_)=flux_special
738 do idir=1,ndir
739 flux_type(idir,mag(idir))=flux_special
740 end do
741 else
742 do idir=1,ndir
743 flux_type(idir,mag(idir))=flux_tvdlf
744 end do
745 end if
746 end if
747
748 phys_get_rho => mhd_get_rho
749 phys_get_dt => mhd_get_dt
750 if(mhd_semirelativistic) then
751 if(mhd_energy) then
752 phys_get_cmax => mhd_get_cmax_semirelati
753 else
754 phys_get_cmax => mhd_get_cmax_semirelati_noe
755 end if
756 else
757 if(mhd_energy) then
758 phys_get_cmax => mhd_get_cmax_origin
759 else
760 phys_get_cmax => mhd_get_cmax_origin_noe
761 end if
762 end if
763 phys_get_tcutoff => mhd_get_tcutoff
764 phys_get_h_speed => mhd_get_h_speed
765 if(has_equi_rho_and_p) then
766 phys_get_cbounds => mhd_get_cbounds_split_rho
767 else if(mhd_semirelativistic) then
768 phys_get_cbounds => mhd_get_cbounds_semirelati
769 else
770 phys_get_cbounds => mhd_get_cbounds
771 end if
772
773 !> EOS module: phys_to_primitive / phys_to_conserved are bound by
774 !> mod_mhd_eos:bind_eos_to_source to route through the EoS layer;
775 !> mhd_to_primitive / mhd_to_conserved pointers are NOT used - every
776 !> call to convert state goes through eos%to_primitive / eos%to_conserved.
777 !> eos%inv_squared_c{0,} are set in mhd_physical_units (called below)
778 !> after inv_squared_c{0,} are computed.
779 if(mhd_hydrodynamic_e) then
780 phys_get_flux => mhd_get_flux_hde
781 else if(mhd_semirelativistic) then
782 if(mhd_energy) then
783 phys_get_flux => mhd_get_flux_semirelati
784 else
785 phys_get_flux => mhd_get_flux_semirelati_noe
786 end if
787 else
788 if(b0field.or.has_equi_rho_and_p) then
789 phys_get_flux => mhd_get_flux_split
790 else if(mhd_energy) then
791 phys_get_flux => mhd_get_flux
792 else
793 phys_get_flux => mhd_get_flux_noe
794 end if
795 end if
796 phys_get_v => mhd_get_v
797 if(mhd_semirelativistic) then
798 phys_add_source_geom => mhd_add_source_geom_semirelati
799 else if(b0field.or.has_equi_rho_and_p) then
800 phys_add_source_geom => mhd_add_source_geom_split
801 else
802 phys_add_source_geom => mhd_add_source_geom
803 end if
804 phys_add_source => mhd_add_source
805 phys_check_params => mhd_check_params
806 phys_write_info => mhd_write_info
807
808 if(mhd_internal_e) then
809 phys_handle_small_values => mhd_handle_small_values_inte
810 mhd_handle_small_values => mhd_handle_small_values_inte
811 phys_check_w => mhd_check_w_inte
812 else if(mhd_hydrodynamic_e) then
813 phys_handle_small_values => mhd_handle_small_values_hde
814 mhd_handle_small_values => mhd_handle_small_values_hde
815 phys_check_w => mhd_check_w_hde
816 else if(mhd_semirelativistic) then
817 phys_handle_small_values => mhd_handle_small_values_semirelati
818 mhd_handle_small_values => mhd_handle_small_values_semirelati
819 phys_check_w => mhd_check_w_semirelati
820 else if(has_equi_rho_and_p) then
821 phys_handle_small_values => mhd_handle_small_values_split
822 mhd_handle_small_values => mhd_handle_small_values_split
823 phys_check_w => mhd_check_w_split
824 else if(mhd_energy) then
825 phys_handle_small_values => mhd_handle_small_values_origin
826 mhd_handle_small_values => mhd_handle_small_values_origin
827 phys_check_w => mhd_check_w_origin
828 else
829 phys_handle_small_values => mhd_handle_small_values_noe
830 mhd_handle_small_values => mhd_handle_small_values_noe
831 phys_check_w => mhd_check_w_noe
832 end if
833
834 ! phys_get_pthermal is set by mhd_link_eos
835
836 if(number_equi_vars>0) then
837 phys_set_equi_vars => set_equi_vars_grid
838 endif
839
840 if(type_divb==divb_glm) then
841 phys_modify_wlr => mhd_modify_wlr
842 end if
843
844 ! Rfactor / temperature / pthermal pointers are bound by
845 ! mod_mhd_eos:bind_eos_to_source (called by mhd_link_eos immediately
846 ! after mhd_phys_init). No EoS machinery in mod_mhd_phys.t.
847
848 ! if using ct stagger grid, boundary divb=0 is not done here
849 if(stagger_grid) then
850 select case(type_ct)
851 case('average')
852 transverse_ghost_cells = 1
853 phys_get_ct_velocity => mhd_get_ct_velocity_average
854 phys_update_faces => mhd_update_faces_average
855 case('uct_contact')
856 transverse_ghost_cells = 1
857 phys_get_ct_velocity => mhd_get_ct_velocity_contact
858 phys_update_faces => mhd_update_faces_contact
859 case('uct_hll')
860 transverse_ghost_cells = 2
861 phys_get_ct_velocity => mhd_get_ct_velocity_hll
862 phys_update_faces => mhd_update_faces_hll
863 case default
864 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
865 end select
866 phys_face_to_center => mhd_face_to_center
867 phys_modify_wlr => mhd_modify_wlr
868 else if(ndim>1) then
869 phys_boundary_adjust => mhd_boundary_adjust
870 end if
871
872 {^nooned
873 ! clean initial divb
875 call mpistop('To verify whether mg usage for FLD versus divB can be combined')
876 if(clean_initial_divb) phys_clean_divb => mhd_clean_divb_multigrid
877 }
878
879 ! derive units from basic units
880 call mhd_physical_units()
881
882 if(mhd_uawsom) then
883 ! Namelist inputs are physical quantities, following the normal AMRVAC
884 ! convention for this module (cm/G in cgs, m/T in SI).
885 if(mhd_uawsom_zeta_scale == -one) &
886 mhd_uawsom_zeta_scale=merge(3.4805d9,3.4805d11,si_unit)
887 if(mhd_uawsom_thread_radius0 == -one) &
888 mhd_uawsom_thread_radius0=merge(1.d5,1.d7,si_unit)
889 if(mhd_uawsom_bref == -one) &
890 mhd_uawsom_bref=merge(1.d-3,10.d0,si_unit)
892 mhd_uawsom_alfven_corr_length0=merge(1.5d7,1.5d9,si_unit)
898 end if
899
900 if(mhd_hyperbolic_tc) then
901 if(mhd_hyperbolic_tc_kappa==0.d0) then
902 if(si_unit) then
904 else
906 end if
907 else
909 end if
910
912 select case(trim(mhd_hyperbolic_tc_perp_mode))
913 case('fixed_reference')
915 if(si_unit) then
918 else
921 end if
922 end if
923 case('weak_field_isotropization')
924 if(mhd_hyperbolic_tc_bmin==0.d0) then
926 end if
927 case('electron_magnetization')
928 if(mhd_hyperbolic_tc_coulomb_log<=zero) then
929 call mpistop("mhd_hyperbolic_tc_coulomb_log must be positive")
930 end if
931 case default
932 call mpistop("invalid mhd_hyperbolic_tc_perp_mode: "// &
934 end select
935 end if
936 end if
937 if(.not. mhd_energy .and. mhd_thermal_conduction) then
938 call mpistop("thermal conduction needs mhd_energy=T")
939 end if
940 if(.not. mhd_energy .and. mhd_hyperbolic_tc) then
941 call mpistop("hyperbolic thermal conduction needs mhd_energy=T")
942 end if
943 if(.not. mhd_energy .and. mhd_radiative_cooling) then
944 call mpistop("radiative cooling needs mhd_energy=T")
945 end if
946
947 !> Cache log10(nH) in wextra for LTE+IonE TC (density invariant during STS)
948 if (eos%eos_type == 'LTE' .and. eos%ionE .and. mhd_thermal_conduction) then
949 iw_log_nh = var_set_wextra()
950 end if
951
952 if(mhd_equi_thermal)then
953 if((.not.has_equi_rho_and_p).or.(.not.total_energy))then
954 mhd_equi_thermal=.false.
955 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no splitting or total e in use'
956 else
958 if(mype==0) write(*,*) 'Will subtract thermal balance in TC or RC with mhd_equi_thermal=T'
959 else
960 mhd_equi_thermal=.false.
961 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no TC or RC in use'
962 endif
963 endif
964 endif
965
966 ! initialize thermal conduction module
967 if (mhd_thermal_conduction) then
968 call sts_init()
969 call tc_init_params(eos%gamma)
970
971 allocate(tc_fl)
972 call tc_get_mhd_params(tc_fl,tc_params_read_mhd)
973 if(ndim==1) then
974 call add_sts_method(mhd_get_tc_dt_hd,mhd_sts_set_source_tc_hd,e_,1,e_,1,.false.)
975 else
976 call add_sts_method(mhd_get_tc_dt_mhd,mhd_sts_set_source_tc_mhd,e_,1,e_,1,.false.)
977 endif
978 ! TC function pointers (get_temperature_from_conserved/eint, get_rho,
979 ! get_temperature_equi, get_rho_equi, subtract_equi) are bound by
980 ! bind_eos_to_source in mod_mhd_eos.t to the correct EoS-aware
981 ! implementations. No EoS machinery in mod_mhd_phys.t.
982 if(.not.mhd_internal_e) then
983 if(mhd_hydrodynamic_e) then
984 call set_conversion_methods_to_head(mhd_e_to_ei_hde, mhd_ei_to_e_hde)
985 phys_e_to_ei => mhd_e_to_ei_hde
986 phys_ei_to_e => mhd_ei_to_e_hde
987 else if(mhd_semirelativistic) then
988 call set_conversion_methods_to_head(mhd_e_to_ei_semirelati, mhd_ei_to_e_semirelati)
989 phys_e_to_ei => mhd_e_to_ei_semirelati
990 phys_ei_to_e => mhd_ei_to_e_semirelati
991 else
992 if (iw_log_nh > 0) then
993 call set_conversion_methods_to_head(mhd_e_to_ei_and_cache_log_nh, mhd_ei_to_e)
994 else
996 end if
997 phys_e_to_ei => mhd_e_to_ei
998 phys_ei_to_e => mhd_ei_to_e
999 end if
1000 end if
1001 call set_error_handling_to_head(mhd_tc_handle_small_e)
1002 tc_fl%e_ = e_
1003 tc_fl%Tcoff_ = tcoff_
1004 end if
1005
1006 ! Energy conversion pointers needed by EOS module regardless of TC method
1007 if(.not.mhd_internal_e .and. .not.associated(phys_e_to_ei)) then
1008 if(mhd_hydrodynamic_e) then
1009 phys_e_to_ei => mhd_e_to_ei_hde
1010 phys_ei_to_e => mhd_ei_to_e_hde
1011 else if(mhd_semirelativistic) then
1012 phys_e_to_ei => mhd_e_to_ei_semirelati
1013 phys_ei_to_e => mhd_ei_to_e_semirelati
1014 else
1015 phys_e_to_ei => mhd_e_to_ei
1016 phys_ei_to_e => mhd_ei_to_e
1017 end if
1018 end if
1019
1020 ! Initialize radiative cooling module
1021 if (mhd_radiative_cooling) then
1022 call radiative_cooling_init_params(eos%gamma,eos%He_abundance)
1023 allocate(rc_fl)
1024 rc_fl%fip_ = fip_
1025 call radiative_cooling_init(rc_fl,rc_params_read)
1026 rc_fl%e_ = e_
1027 rc_fl%Tcoff_ = tcoff_
1028 rc_fl%subtract_equi = has_equi_rho_and_p
1029 ! rc_fl EoS pointers (get_rho, get_pthermal, get_var_Rfactor,
1030 ! equi accessors, subtract_equi) are bound by bind_eos_to_source
1031 ! in mod_mhd_eos.t. No EoS machinery in mod_mhd_phys.t.
1032 end if
1033 allocate(te_fl_mhd)
1034 ! te_fl_mhd EoS pointers are bound by bind_eos_to_source in mod_mhd_eos.t
1035{^ifthreed
1036 phys_te_images => mhd_te_images
1037}
1038
1039 ! consistency check for hyperresistivity implementation
1040 if (mhd_eta_hyper>0.0d0) then
1041 if(mype==0) then
1042 write(*,*) '*****Using hyperresistivity: with mhd_eta_hyper :', mhd_eta_hyper
1043 endif
1044 if(b0field) then
1045 ! hyperresistivity not ok yet with splitting
1046 call mpistop("Must have B0field=F when using hyperresistivity")
1047 end if
1048 endif
1049 if (mhd_eta_hyper<0.0d0) then
1050 call mpistop("Must have mhd_eta_hyper positive when using hyperresistivity")
1051 endif
1052
1053 ! Initialize viscosity module
1054 if (mhd_viscosity) then
1055 call viscosity_init(phys_wider_stencil)
1056 end if
1057
1058 ! Initialize gravity module
1059 if(mhd_gravity) then
1060 call gravity_init()
1061 end if
1062
1063 ! Initialize rotating frame module
1064 if(mhd_rotating_frame) then
1065 if(has_equi_rho_and_p) then
1066 ! mod_rotating_frame does not handle splitting of density
1067 call mpistop("Must have has_equi_rho_and_p=F when mhd_rotating_frame=T")
1068 end if
1069 call rotating_frame_init()
1070 endif
1071
1072
1073 ! initialize magnetofriction module
1074 if(mhd_magnetofriction) then
1076 end if
1077
1078 if(mhd_hall) then
1079 if(mhd_semirelativistic) then
1080 ! semirelativistic does not incorporate hall terms
1081 call mpistop("Must have mhd_hall=F when mhd_semirelativistic=T")
1082 end if
1083 if(coordinate>1)then
1084 ! normal unsplit case or split cases do not have geometric sources for Hall included
1085 call mpistop("Must have Cartesian coordinates for Hall")
1086 endif
1087 ! For Hall, we need one more reconstructed layer since currents are computed
1088 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1089 phys_wider_stencil = 1
1090 end if
1091
1092 ! The perpendicular HTC geometry evaluates a fourth-order centred
1093 ! temperature gradient inside the reconstructed flux layer. It therefore
1094 ! needs one layer beyond the default two ghost cells.
1096 phys_wider_stencil=max(phys_wider_stencil,1)
1097 end if
1098
1099 if(mhd_ambipolar) then
1100 if(mhd_ambipolar_sts) then
1101 call sts_init()
1103 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mag(1),&
1104 ndir,mag(1),ndir,.true.)
1105 else
1106 ! any total energy or no energy at all case is handled here
1107 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mom(ndir)+1,&
1108 mag(ndir)-mom(ndir),mag(1),ndir,.true.)
1109 end if
1110 else
1111 mhd_ambipolar_exp=.true.
1112 ! For flux ambipolar term, we need one more reconstructed layer since currents are computed
1113 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1114 phys_wider_stencil = 1
1115 end if
1116 end if
1117
1118 ! ionization-degree table init now lives in eos_finalise (eos% owns
1119 ! thermodynamic-backend init, parallel to LTE tables); see mod_eos_PI.
1120
1121 ! Initialize CAK radiation force module
1122 if (mhd_cak_force) then
1124 call mpistop("CAK implementation not available in internal or semirelativistic variants")
1125 endif
1126 if(has_equi_rho_and_p) then
1127 call mpistop("CAK force implementation not available for split off pressure and density")
1128 endif
1129 call cak_init(eos%gamma)
1130 endif
1131
1132 end subroutine mhd_phys_init
1133
1134{^ifthreed
1135 subroutine mhd_te_images
1138
1139 select case(convert_type)
1140 case('EIvtiCCmpi','EIvtuCCmpi')
1142 case('ESvtiCCmpi','ESvtuCCmpi')
1144 case('SIvtiCCmpi','SIvtuCCmpi')
1146 case('WIvtiCCmpi','WIvtuCCmpi')
1148 case default
1149 call mpistop("Error in synthesize emission: Unknown convert_type")
1150 end select
1151 end subroutine mhd_te_images
1152}
1153
1154!!start th cond
1155 ! wrappers for STS functions in thermal_conductivity module
1156 ! which take as argument the tc_fluid (defined in the physics module)
1157 subroutine mhd_sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1161 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1162 double precision, intent(in) :: x(ixi^s,1:ndim)
1163 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1164 double precision, intent(in) :: my_dt
1165 logical, intent(in) :: fix_conserve_at_step
1166 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1167 end subroutine mhd_sts_set_source_tc_mhd
1168
1169 subroutine mhd_sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1173 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1174 double precision, intent(in) :: x(ixi^s,1:ndim)
1175 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1176 double precision, intent(in) :: my_dt
1177 logical, intent(in) :: fix_conserve_at_step
1178 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1179 end subroutine mhd_sts_set_source_tc_hd
1180
1181 function mhd_get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1182 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1183 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1184 !and T=p/rho
1187
1188 integer, intent(in) :: ixi^l, ixo^l
1189 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1190 double precision, intent(in) :: w(ixi^s,1:nw)
1191 double precision :: dtnew
1192
1193 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1194 end function mhd_get_tc_dt_mhd
1195
1196 function mhd_get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1197 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1198 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1199 !and T=p/rho
1202
1203 integer, intent(in) :: ixi^l, ixo^l
1204 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1205 double precision, intent(in) :: w(ixi^s,1:nw)
1206 double precision :: dtnew
1207
1208 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1209 end function mhd_get_tc_dt_hd
1210
1211 subroutine mhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
1213
1214 integer, intent(in) :: ixi^l,ixo^l
1215 double precision, intent(inout) :: w(ixi^s,1:nw)
1216 double precision, intent(in) :: x(ixi^s,1:ndim)
1217 integer, intent(in) :: step
1218 character(len=140) :: error_msg
1219
1220 ! tc_patch_eint repairs w(:, e_) in place during the source-term call,
1221 ! but the Chebyshev recurrence can still produce residual negative
1222 ! e_int in the updated state. Run mhd_handle_small_ei every substep
1223 ! (patch on or off) so STS does not propagate negative e through.
1224 write(error_msg,"(a,i3)") "Thermal conduction step ", step
1225 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
1226 end subroutine mhd_tc_handle_small_e
1227
1228 ! fill in tc_fluid fields from namelist
1229 subroutine tc_params_read_mhd(fl)
1231 type(tc_fluid), intent(inout) :: fl
1232
1233 double precision :: tc_k_para=0d0
1234 double precision :: tc_k_perp=0d0
1235 integer :: n
1236 ! list parameters
1237 logical :: tc_perpendicular=.false.
1238 logical :: tc_saturate=.false.
1239 logical :: tc_patch_eint=.false.
1240 double precision :: trac_t_floor=0.d0
1241 character(len=std_len) :: tc_slope_limiter="MC"
1242
1243 namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp, tc_patch_eint, trac_t_floor
1244
1245 do n = 1, size(par_files)
1246 open(unitpar, file=trim(par_files(n)), status="old")
1247 read(unitpar, tc_list, end=111)
1248111 close(unitpar)
1249 end do
1250
1251 fl%tc_perpendicular = tc_perpendicular
1252 fl%tc_saturate = tc_saturate
1253 fl%tc_patch_eint = tc_patch_eint
1254 fl%tc_k_para = tc_k_para
1255 fl%tc_k_perp = tc_k_perp
1256 fl%trac_T_floor = trac_t_floor / unit_temperature
1257 select case(tc_slope_limiter)
1258 case ('no','none')
1259 fl%tc_slope_limiter = 0
1260 case ('MC')
1261 ! monotonized central limiter Woodward and Collela limiter (eq.3.51h)
1262 fl%tc_slope_limiter = 1
1263 case('minmod')
1264 ! minmod limiter
1265 fl%tc_slope_limiter = 2
1266 case ('superbee')
1267 ! Roes superbee limiter (eq.3.51i)
1268 fl%tc_slope_limiter = 3
1269 case ('koren')
1270 ! Barry Koren Right variant
1271 fl%tc_slope_limiter = 4
1272 case ('vanleer')
1273 ! van Leer limiter
1274 fl%tc_slope_limiter = 5
1275 case default
1276 call mpistop("Unknown tc_slope_limiter, choose MC, minmod, superbee, koren, vanleer")
1277 end select
1278 end subroutine tc_params_read_mhd
1279!!end th cond
1280
1281!!rad cool
1282 subroutine rc_params_read(fl)
1284 use mod_constants, only: bigdouble
1285 type(rc_fluid), intent(inout) :: fl
1286
1287 !> Lower limit of temperature
1288 double precision :: tlow=bigdouble
1289 double precision :: rad_damp_height=0.5d0
1290 double precision :: rad_damp_scale=0.15d0
1291 integer :: n
1292 ! list parameters
1293 integer :: ncool = 4000
1294 !> Fixed temperature not lower than tlow
1295 logical :: tfix=.false.
1296 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1297 logical :: rc_split=.false.
1298 logical :: rad_damp=.false.
1299 !> Name of cooling curve
1300 character(len=std_len) :: coolcurve='JCcorona'
1301 logical :: rad_newton = .false.
1302 double precision :: rad_newton_trad = 0.006d0
1303 double precision :: rad_newton_rhosurf = 1.d4
1304 double precision :: rad_newton_pthick = 25.d0
1305 !> HEAD-side cooling parameters (missing from common content after merge)
1306 double precision :: cfrac=0.1d0
1307 double precision :: rad_cut_hgt=0.5d0
1308 double precision :: rad_cut_dey=0.15d0
1309 !> Variable-c_V Townsend extension (Y_mod): quadrature and sub-intervals
1310 character(len=8) :: rc_y_mod_quadrature='boole'
1311 integer :: rc_y_mod_n_sub=16
1312 !> Smooth SC<->thin blend (mirrors hd): thin cooling *= 0.5(1+tanh((T-T0)/dT))*0.5(1+tanh((y-y0)/dy))
1313
1314 namelist /rc_list/ coolcurve, ncool, cfrac, tlow, tfix, rc_split, &
1315 rad_cut_hgt, rad_cut_dey, &
1316 rc_y_mod_quadrature, rc_y_mod_n_sub, &
1317 rad_newton, rad_newton_trad, rad_newton_rhosurf, &
1318 rad_newton_pthick, rad_damp, rad_damp_height, rad_damp_scale
1319
1320 do n = 1, size(par_files)
1321 open(unitpar, file=trim(par_files(n)), status="old")
1322 read(unitpar, rc_list, end=111)
1323111 close(unitpar)
1324 end do
1325
1326 fl%ncool=ncool
1327 fl%coolcurve=coolcurve
1328 fl%tlow=tlow
1329 fl%Tfix=tfix
1330 fl%rc_split=rc_split
1331 fl%cfrac=cfrac
1332 fl%rad_cut_hgt=rad_cut_hgt
1333 fl%rad_cut_dey=rad_cut_dey
1334 fl%Y_mod_quadrature=rc_y_mod_quadrature
1335 fl%Y_mod_N_sub=rc_y_mod_n_sub
1336 fl%rad_damp=rad_damp
1337 fl%rad_damp_height=rad_damp_height
1338 fl%rad_damp_scale=rad_damp_scale
1339 fl%rad_newton=rad_newton
1340 fl%rad_newton_trad=rad_newton_trad
1341 fl%rad_newton_rhosurf=rad_newton_rhosurf
1342 fl%rad_newton_pthick=rad_newton_pthick
1343 end subroutine rc_params_read
1344
1345 !> sets the equilibrium variables
1346 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1348 use mod_usr_methods
1349 integer, intent(in) :: igrid, ixi^l, ixo^l
1350 double precision, intent(in) :: x(ixi^s,1:ndim)
1351
1352 double precision :: delx(ixi^s,1:ndim)
1353 double precision :: xc(ixi^s,1:ndim),xshift^d
1354 integer :: idims, ixc^l, hxo^l, ix, idims2
1355
1356 if(slab_uniform)then
1357 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1358 else
1359 ! for all non-cartesian and stretched cartesian coordinates
1360 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1361 endif
1362
1363 do idims=1,ndim
1364 hxo^l=ixo^l-kr(idims,^d);
1365 if(stagger_grid) then
1366 ! ct needs all transverse cells
1367 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1368 else
1369 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1370 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1371 end if
1372 ! always xshift=0 or 1/2
1373 xshift^d=half*(one-kr(^d,idims));
1374 do idims2=1,ndim
1375 select case(idims2)
1376 {case(^d)
1377 do ix = ixc^lim^d
1378 ! xshift=half: this is the cell center coordinate
1379 ! xshift=0: this is the cell edge i+1/2 coordinate
1380 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1381 end do\}
1382 end select
1383 end do
1384 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1385 end do
1386 end subroutine set_equi_vars_grid_faces
1387
1388 !> sets the equilibrium variables
1389 subroutine set_equi_vars_grid(igrid)
1391 use mod_usr_methods
1392
1393 integer, intent(in) :: igrid
1394
1395 !values at the center
1396 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1397
1398 !values at the interfaces
1399 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1400
1401 end subroutine set_equi_vars_grid
1402
1403 ! w, wnew conserved, add splitted variables back to wnew
1404 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1406 integer, intent(in) :: ixi^l,ixo^l, nwc
1407 double precision, intent(in) :: w(ixi^s, 1:nw)
1408 double precision, intent(in) :: x(ixi^s,1:ndim)
1409 double precision :: wnew(ixo^s, 1:nwc)
1410
1411 if(has_equi_rho_and_p) then
1412 wnew(ixo^s,rho_)=w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0)
1413 else
1414 wnew(ixo^s,rho_)=w(ixo^s,rho_)
1415 endif
1416 wnew(ixo^s,mom(:))=w(ixo^s,mom(:))
1417
1418 if (b0field) then
1419 ! add background magnetic field B0 to B
1420 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
1421 else
1422 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))
1423 end if
1424
1425 if(mhd_energy) then
1426 wnew(ixo^s,e_)=w(ixo^s,e_)
1427 if(has_equi_rho_and_p) then
1428 wnew(ixo^s,e_)=wnew(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1
1429 end if
1430 if(b0field .and. total_energy) then
1431 wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1432 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1433 end if
1434 end if
1435
1436 end function convert_vars_splitting
1437
1438 subroutine mhd_check_params
1440 use mod_usr_methods
1443 use mod_particles, only: particles_init, particles_eta, particles_etah
1444 use mod_particles, only: npayload,nusrpayload, &
1445 ngridvars,num_particles,physics_type_particles
1446 use mod_fld
1447
1448 double precision :: a,b,xfrac,yfrac
1449
1450 if(mhd_uawsom) then
1451 if(coordinate /= cartesian .or. .not.slab_uniform) &
1452 call mpistop('mhd_uawsom currently requires a uniform Cartesian grid')
1453 if(.not.mhd_energy .or. .not.total_energy) &
1454 call mpistop('mhd_uawsom requires the standard total-energy MHD formulation')
1457 call mpistop('mhd_uawsom: unsupported MHD option')
1458 if(trim(eos%eos_type) /= 'FI') &
1459 call mpistop("mhd_uawsom currently supports eos_type='FI' only")
1461 call mpistop('mhd_uawsom_height_dim must be between 1 and ndim')
1462 if(mhd_uawsom_zeta0 <= one .or. mhd_uawsom_filling_factor <= zero .or. &
1464 call mpistop('mhd_uawsom requires zeta0>1 and 0<filling_factor<1')
1465 if(mhd_uawsom_zeta_scale <= zero .or. &
1466 mhd_uawsom_thread_radius0 <= zero .or. &
1467 mhd_uawsom_alfven_corr_length0 <= zero .or. mhd_uawsom_bref <= zero) &
1468 call mpistop('mhd_uawsom: scales must be positive')
1469 if(mhd_uawsom_sigma < zero) &
1470 call mpistop('mhd_uawsom_sigma must be non-negative')
1471 select case(trim(mhd_uawsom_reflection_mode))
1472 case('one_dimensional_gradient','cartesian_gradient_vorticity')
1473 continue
1474 case default
1475 call mpistop('invalid mhd_uawsom_reflection_mode')
1476 end select
1477 end if
1478
1479 ! Initialize particles module here, so all extra and user vars are sample
1480 if(mhd_particles) then
1481 call particles_init()
1482 if (particles_eta < zero) particles_eta = mhd_eta
1483 if (particles_etah < zero) particles_eta = mhd_etah
1484 end if
1485
1486 ! gamma, gamma_minus_1, inv_gamma_minus_1 are set by eos_init
1487 if (.not. mhd_energy) then
1488 if (eos%gamma <= 0.0d0) call mpistop ("Error: gamma <= 0")
1489 if (mhd_adiab < 0.0d0) call mpistop ("Error: mhd_adiab < 0")
1491 else
1492 if (eos%gamma <= 0.0d0 .or. eos%gamma == 1.0d0) &
1493 call mpistop ("Error: gamma <= 0 or gamma == 1")
1494 small_e = small_pressure * eos%inv_gamma_minus_1
1495 small_r_e = small_pressure * eos%inv_gamma_minus_1
1496 end if
1497
1498 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1499 call mpistop("usr_set_equi_vars has to be implemented in the user file")
1500 endif
1501
1502 if(has_equi_rho_and_p) then
1503 ! The Roe and HLLC solvers read the rho slot as a physical density, which
1504 ! under splitting holds only the perturbation. Neither has a split variant,
1505 ! so refuse the combination rather than return a quietly wrong wave speed.
1506 if(any(flux_method(:)==fs_tvdmu) .or. any(flux_method(:)==fs_hllc) &
1507 .or. any(flux_method(:)==fs_hllcd)) then
1508 call mpistop("Must have has_equi_rho_and_p=F with the roe/hllc/hllcd flux schemes")
1509 end if
1510 ! mhd_get_tcutoff forms Te from the perturbation pressure and density.
1511 if(mhd_trac) then
1512 call mpistop("Must have has_equi_rho_and_p=F when mhd_trac=T")
1513 end if
1514 end if
1515 if(convert .or. autoconvert) then
1516 if(convert_type .eq. 'dat_generic_mpi') then
1517 if(mhd_dump_full_vars) then
1518 if(mype .eq. 0) print*, " add conversion method: split -> full "
1519 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1520 endif
1521 endif
1522 endif
1523
1524 if(mhd_radiation_fld) then
1525 if(.not.use_imex_scheme)then
1526 call mpistop('select IMEX scheme for FLD radiation use')
1527 endif
1528 if(use_multigrid)then
1529 call phys_set_mg_bounds()
1530 else
1531 if(.not.fld_no_mg)call mpistop('multigrid must have BCs for IMEX and FLD radiation use')
1532 endif
1533 if(mype==0)then
1534 write(*,*)'==FLD SETUP======================'
1535 write(*,*)'Using FLD with settings:'
1536 write(*,*)'Using FLD with settings: mhd_radiation_fld=',mhd_radiation_fld
1537 write(*,*)'Using FLD with settings: mhd_fld_pradtensor=',mhd_fld_pradtensor
1538 write(*,*)'Using FLD with settings: fld_fluxlimiter=',fld_fluxlimiter
1539 write(*,*)'Using FLD with settings: fld_bound_diff=',fld_bound_diff
1540 write(*,*)'Using FLD with settings: fld_interaction_method=',fld_interaction_method
1541 write(*,*)'Using FLD with settings: fld_opacity_law=',fld_opacity_law
1542 write(*,*)'Using FLD with settings: fld_kappa0=',fld_kappa0
1543 write(*,*)'Using FLD with settings: fld_opal_table=',fld_opal_table
1544 write(*,*)'Using FLD with settings: fld_Radforce_split=',fld_radforce_split
1545 write(*,*)'Using FLD with settings: fld_bisect_tol=',fld_bisect_tol
1546 write(*,*)'Using FLD with settings: fld_diff_tol=',fld_diff_tol
1547 write(*,*)'Using FLD with settings: nth_for_diff_mg=',nth_for_diff_mg
1548 write(*,*)' FLD has use_imex_scheme and use_multigrid=',use_imex_scheme,use_multigrid
1549 write(*,*)' FLD has fld_no_mg=',fld_no_mg
1550 if(fld_no_mg)then
1551 print *,'WARNING: cheating with FLD diffusion ***********************'
1552 print *,'WARNING: No MG-diffusion for radiative energy at all!!!!!!!'
1553 print *,'WARNING: cheating with FLD diffusion ***********************'
1554 endif
1555 print *,'const_rad_a =',const_rad_a
1556 print *,'NORMALIZED arad_norm=',arad_norm
1557 print *,'NORMALIZED c_norm=',c_norm
1558 if(fld_cnorm>0.0d0)then
1559 print *,'WARNING: cheating with c_norm ***********************'
1560 print *,'WARNING: c_norm reset to=',fld_cnorm
1562 print *,'WARNING: cheating with c_norm ***********************'
1563 endif
1564 print *,'const_kappae =',const_kappae
1565 if(trim(fld_opacity_law).eq.'const_norm')then
1566 print *,'NORMALIZED fld_kappa0 =',fld_kappa0
1567 print *,'physical value (in cgs or SI) =',fld_kappa0*unit_opacity
1568 endif
1569 if(trim(fld_opacity_law).eq.'const')then
1570 print *,'physical fld_kappa (in cgs or SI) =',fld_kappa0
1571 print *,'NORMALIZED value =',fld_kappa0/unit_opacity
1572 endif
1573 write(*,*)'===FLD SETUP====================='
1574 endif
1575 endif
1576
1577 if(mype==0)then
1578 write(*,*)'====MHD run with settings===================='
1579 write(*,*)'Using mod_mhd_phys with settings:'
1580 write(*,*)'SI_unit=',si_unit
1581 write(*,*)'Dimensionality :',ndim
1582 write(*,*)'vector components:',ndir
1583 write(*,*)'coordinate set to type,slab:',coordinate,slab
1584 write(*,*)'number of variables nw=',nw
1585 write(*,*)' start index iwstart=',iwstart
1586 write(*,*)'number of vector variables=',nvector
1587 write(*,*)'number of stagger variables nws=',nws
1588 write(*,*)'number of variables with BCs=',nwgc
1589 write(*,*)'number of vars with fluxes=',nwflux
1590 write(*,*)'number of vars with flux + BC=',nwfluxbc
1591 write(*,*)'number of auxiliary variables=',nwaux
1592 write(*,*)'number of extra vars without flux=',nwextra
1593 write(*,*)'number of extra vars for wextra=',nw_extra
1594 write(*,*)'number of auxiliary I/O variables=',nwauxio
1595 write(*,*)'number of mhd_n_tracer=',mhd_n_tracer
1596 write(*,*)' mhd_energy=',mhd_energy,' with total_energy=',total_energy
1597 write(*,*)' mhd_semirelativistic=',mhd_semirelativistic
1598 write(*,*)' mhd_internal_e=',mhd_internal_e
1599 write(*,*)' mhd_hydrodynamic_e=',mhd_hydrodynamic_e
1600 write(*,*)' mhd_gravity=',mhd_gravity
1601 write(*,*)' mhd_eta=',mhd_eta,' nonzero implies resistivity'
1602 write(*,*)' mhd_viscosity=',mhd_viscosity
1603 write(*,*)' mhd_radiative_cooling=',mhd_radiative_cooling
1604 write(*,*)' mhd_cak_force=',mhd_cak_force
1605 write(*,*)' mhd_radiation_fld=',mhd_radiation_fld
1606 write(*,*)' mhd_thermal_conduction=',mhd_thermal_conduction
1607 write(*,*)' mhd_hyperbolic_tc=',mhd_hyperbolic_tc
1608 write(*,*)' mhd_trac=',mhd_trac
1609 write(*,*)' mhd_hall=',mhd_hall
1610 write(*,*)' mhd_ambipolar=',mhd_ambipolar
1611 write(*,*)' mhd_eta_hyper=',mhd_eta_hyper
1612 write(*,*)' mhd_rotating_frame=',mhd_rotating_frame
1613 write(*,*)' mhd_particles=',mhd_particles
1614 if(mhd_particles) then
1615 write(*,*) '*****Using particles: with mhd_eta, mhd_etah :', mhd_eta, mhd_etah
1616 write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
1617 write(*,*) '*****Using particles: npayload,ngridvars :', npayload,ngridvars
1618 write(*,*) '*****Using particles: nusrpayload :', nusrpayload
1619 write(*,*) '*****Using particles: num_particles :', num_particles
1620 write(*,*) '*****Using particles: physics_type_particles=',physics_type_particles
1621 end if
1622 write(*,*)'number of ghostcells=',nghostcells
1623 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
1624 write(*,*)'==========================================='
1625 print *,'========EOS and UNITS==========='
1626 print *,'SI_unit =',si_unit
1627 print *,'gamma=',eos%gamma
1628 print *,'He_abundance =',eos%He_abundance
1629 print *,'RR =',rr
1630 print *,'========EOS and UNITS==========='
1631 print *,'unit_time =',unit_time
1632 print *,'unit_length =',unit_length
1633 print *,'unit_velocity =',unit_velocity
1634 print *,'unit_pressure =',unit_pressure
1635 print *,'unit_numberdensity =',unit_numberdensity
1636 print *,'unit_density =',unit_density
1637 print *,'unit_temperature =',unit_temperature
1638 print *,'unit_mass =',unit_mass
1639 print *,'unit_Erad =',unit_erad
1640 print *,'unit_radflux =',unit_radflux
1641 print *,'unit_magneticfield =',unit_magneticfield
1642 if(si_unit)then
1643 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/miu0_si
1644 else
1645 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/(4.0d0*dpi)
1646 endif
1647 print *, 'CHECK that p_u ',unit_pressure,' equals ',unit_density*unit_velocity**2
1648 print *, 'CHECK that L_u ',unit_length,' equals ',unit_velocity*unit_time
1649 print *, 'CHECK that M_u',unit_mass,' equals ',unit_density*unit_length**3
1650 print *, 'density to numberdensity has factor ',unit_density/unit_numberdensity
1651 if(si_unit)then
1652 print *, ' compare this to ',mp_si*(1.d0+4.d0*eos%He_abundance)
1653 else
1654 print *, ' compare this to ',mp_cgs*(1.d0+4.d0*eos%He_abundance)
1655 endif
1656 print *, 'pressure to n T has factor ',unit_pressure/(unit_numberdensity*unit_temperature)
1657 if(si_unit)then
1658 print *, ' compare this to ',kb_si*(2.d0+3.d0*eos%He_abundance)
1661 else
1662 print *, ' compare this to ',kb_cgs*(2.d0+3.d0*eos%He_abundance)
1665 endif
1666 if(eos%eos_type /= 'LTE')then
1667 print *, 'mean molecular weight mu is =',a/b,' = ', (1.d0+4.d0*eos%He_abundance)/(2.d0+3.d0*eos%He_abundance)
1668 xfrac=1.d0/a
1669 yfrac=4.d0*eos%He_abundance/(1.d0+4.d0*eos%He_abundance)
1670 print *, 'mass fraction hydrogen X is =',1/a,' and this equals ', 1.d0/(1.d0+4.d0*eos%He_abundance)
1671 print *, 'mass fraction helium Y is =',yfrac
1672 print *, ' check that 1/mu', b/a,' is equal to 2X+3Y/4=',2.d0*xfrac+3.d0*yfrac/4.d0
1673 print *, ' ratio n_e/n_p=',1.d0+2.0d0*eos%He_abundance
1674 endif
1675 print *,'========UNITS==========='
1676 endif
1677
1678 end subroutine mhd_check_params
1679
1680 subroutine mhd_physical_units()
1682 double precision :: mp,kb,miu0,c_lightspeed,xfrac,sigma_telectron
1683 double precision :: a,b
1684 ! Derive scaling units
1685 if(si_unit) then
1686 mp=mp_si
1687 kb=kb_si
1688 miu0=miu0_si
1689 const_sigmasb=sigma_sb_si
1690 c_lightspeed=c_si
1691 sigma_telectron=sigma_te_si
1692 else
1693 mp=mp_cgs
1694 kb=kb_cgs
1695 miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
1696 const_sigmasb=sigma_sb_cgs
1697 c_lightspeed=const_c
1698 sigma_telectron=sigma_te_cgs
1699 end if
1700 ! Normalisation dispatch keyed solely on eos%eos_type (FI is the default, so
1701 ! legacy parfiles land in the FI/PI absorbed-(a,b), RR=1 branch -- the former
1702 ! eq_state_units=.true. result).
1703 if (eos%eos_type == 'LTE') then
1704 !> Remove the assumed FI normalisation from the units and handle in EoS
1705 a=1d0
1706 b=1d0
1707 eos%nH2rhoFactor = 1d0+4d0*eos%He_abundance
1708 rr=(2d0+3d0*eos%He_abundance) / (1d0+4d0*eos%He_abundance)
1709 xfrac=1.d0/(1.d0+4.d0*eos%He_abundance)
1710 else
1711 !> FI / PI: absorbed-(a,b), RR=1 (a=b=1 with RR=1 would be wrong physics
1712 !> for He>0). PI shares FI's normalisation exactly; the partial b lives here.
1713 a=1d0+4d0*eos%He_abundance
1714 if(eos%eos_type=='PI') then
1715 b=1d0+h_ion_fr+eos%He_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0)
1716 else
1717 b=2d0+3d0*eos%He_abundance
1718 end if
1719 rr=1d0
1720 xfrac=1.d0/a
1721 end if
1722 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
1723 if(unit_density/=1.d0) then
1725 else if(unit_numberdensity/=1.d0) then
1727 end if
1728 if(unit_temperature/=1.d0) then
1732 if(unit_length/=1.d0) then
1734 else if(unit_time/=1.d0) then
1736 end if
1737 else if(unit_magneticfield/=1.d0) then
1741 if(unit_length/=1.d0) then
1743 else if(unit_time/=1.d0) then
1745 end if
1746 else if(unit_pressure/=1.d0) then
1750 if(unit_length/=1.d0) then
1752 else if(unit_time/=1.d0) then
1754 end if
1755 else if(unit_velocity/=1.d0) then
1759 if(unit_length/=1.d0) then
1761 else if(unit_time/=1.d0) then
1763 end if
1764 else if(unit_time/=1.d0) then
1769 end if
1770 else if(unit_temperature/=1.d0) then
1771 ! units of temperature and velocity are dependent
1772 if(unit_magneticfield/=1.d0) then
1777 if(unit_length/=1.d0) then
1779 else if(unit_time/=1.d0) then
1781 end if
1782 else if(unit_pressure/=1.d0) then
1787 if(unit_length/=1.d0) then
1789 else if(unit_time/=1.d0) then
1791 end if
1792 end if
1793 else if(unit_magneticfield/=1.d0) then
1794 ! units of magnetic field and pressure are dependent
1795 if(unit_velocity/=1.d0) then
1800 if(unit_length/=1.d0) then
1802 else if(unit_time/=1.d0) then
1804 end if
1805 else if(unit_time/=0.d0) then
1811 end if
1812 else if(unit_pressure/=1.d0) then
1813 if(unit_velocity/=1.d0) then
1818 if(unit_length/=1.d0) then
1820 else if(unit_time/=1.d0) then
1822 end if
1823 else if(unit_time/=0.d0) then
1829 end if
1830 end if
1831 ! Additional units needed for the particles
1832 c_norm=c_lightspeed/unit_velocity
1834 if (.not. si_unit) unit_charge = unit_charge*const_c
1836
1837 if(mhd_semirelativistic) then
1838 if(mhd_reduced_c<1.d0) then
1839 ! dimensionless speed
1840 inv_squared_c0=1.d0
1841 inv_squared_c=1.d0/mhd_reduced_c**2
1842 else
1843 inv_squared_c0=(unit_velocity/c_lightspeed)**2
1844 inv_squared_c=(unit_velocity/mhd_reduced_c)**2
1845 end if
1846 ! Propagate to the EoS container. Must happen AFTER inv_squared_c{0,}
1847 ! are set above; the assignment earlier in mhd_phys_init runs before
1848 ! mhd_physical_units and would store uninitialised values.
1849 eos%inv_squared_c0 = inv_squared_c0
1850 eos%inv_squared_c = inv_squared_c
1851 end if
1852
1853 !> Units for radiative flux and opacity as used in FLD
1854 ! this is the radiation constant in either cgs or SI units
1855 const_rad_a=4.d0*const_sigmasb/c_lightspeed
1856 ! this is the dimensionless conversion factor for Erad to Trad
1858 ! This is the Thomson scattering opacity in the correct units
1859 ! note that the hydrogen mass fraction X=1/a in eq_state_units
1860 const_kappae=sigma_telectron*(1.d0+xfrac)/(2.0d0*mp)
1861 ! these are the units
1865
1866 end subroutine mhd_physical_units
1867
1868 subroutine mhd_check_w_semirelati(primitive,ixI^L,ixO^L,w,flag)
1870
1871 logical, intent(in) :: primitive
1872 logical, intent(inout) :: flag(ixi^s,1:nw)
1873 integer, intent(in) :: ixi^l, ixo^l
1874 double precision, intent(in) :: w(ixi^s,nw)
1875
1876 double precision :: tmp,b(1:ndir),v(1:ndir),factor
1877 integer :: ix^d
1878
1879 flag=.false.
1880 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1881
1882 if(mhd_energy) then
1883 if(primitive) then
1884 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1885 else
1886 if(mhd_internal_e) then
1887 {do ix^db=ixomin^db,ixomax^db \}
1888 if(w(ix^d,e_) < small_e) flag(ix^d,e_) = .true.
1889 {end do\}
1890 else
1891 {do ix^db=ixomin^db,ixomax^db \}
1892 ! Convert momentum to velocity
1893 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
1894 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
1895 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
1896 ! E=Bxv
1897 {^ifthreec
1898 b(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
1899 b(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
1900 b(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1901 }
1902 {^iftwoc
1903 b(1)=zero
1904 ! switch 3 with 2 to allow ^C from 1 to 2
1905 b(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1906 }
1907 {^ifonec
1908 b(1)=zero
1909 }
1910 ! Calculate internal e = e-eK-eB-eE
1911 tmp=w(ix^d,e_)-half*((^c&v(^c)**2+)*w(ix^d,rho_)&
1912 +(^c&w(ix^d,b^c_)**2+)+(^c&b(^c)**2+)*inv_squared_c)
1913 if(tmp<small_e) flag(ix^d,e_)=.true.
1914 {end do\}
1915 end if
1916 end if
1917 end if
1918
1919 end subroutine mhd_check_w_semirelati
1920
1921 subroutine mhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1923
1924 logical, intent(in) :: primitive
1925 integer, intent(in) :: ixi^l, ixo^l
1926 double precision, intent(in) :: w(ixi^s,nw)
1927 logical, intent(inout) :: flag(ixi^s,1:nw)
1928
1929 integer :: ix^d, igrp
1930
1931 flag=.false.
1932 {do ix^db=ixomin^db,ixomax^db\}
1933 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1934 if(primitive) then
1935 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1936 else
1937 if(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+&
1938 (^c&w(ix^d,b^c_)**2+))-mhd_uawsom_wave_energy_cell(w(ix^d,:))&
1939 <small_e) flag(ix^d,e_) = .true.
1940 if(mhd_uawsom) then
1941 if(w(ix^d,waplus_)<zero) flag(ix^d,waplus_)=.true.
1942 if(w(ix^d,waminus_)<zero) flag(ix^d,waminus_)=.true.
1943 if(w(ix^d,wkplus_)<zero) flag(ix^d,wkplus_)=.true.
1944 if(w(ix^d,wkminus_)<zero) flag(ix^d,wkminus_)=.true.
1945 end if
1946 end if
1947 if(mhd_radiation_fld)then
1948 if(w(ix^d,r_e)<small_r_e) flag(ix^d,r_e) = .true.
1949 endif
1950 {end do\}
1951
1952 end subroutine mhd_check_w_origin
1953
1954 subroutine mhd_check_w_split(primitive,ixI^L,ixO^L,w,flag)
1956
1957 logical, intent(in) :: primitive
1958 integer, intent(in) :: ixi^l, ixo^l
1959 double precision, intent(in) :: w(ixi^s,nw)
1960 logical, intent(inout) :: flag(ixi^s,1:nw)
1961
1962 double precision :: tmp
1963 integer :: ix^d
1964
1965 flag=.false.
1966 {do ix^db=ixomin^db,ixomax^db\}
1967 tmp=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1968 if(tmp<small_density) flag(ix^d,rho_) = .true.
1969 if(primitive) then
1970 if(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)<small_pressure) flag(ix^d,e_) = .true.
1971 else
1972 tmp=w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/tmp+(^c&w(ix^d,b^c_)**2+))
1973 if(tmp+block%equi_vars(ix^d,equi_pe0_,0)*eos%inv_gamma_minus_1<small_e) flag(ix^d,e_) = .true.
1974 end if
1975 {end do\}
1976
1977 end subroutine mhd_check_w_split
1978
1979 subroutine mhd_check_w_noe(primitive,ixI^L,ixO^L,w,flag)
1981
1982 logical, intent(in) :: primitive
1983 integer, intent(in) :: ixi^l, ixo^l
1984 double precision, intent(in) :: w(ixi^s,nw)
1985 logical, intent(inout) :: flag(ixi^s,1:nw)
1986
1987 integer :: ix^d
1988
1989 flag=.false.
1990 {do ix^db=ixomin^db,ixomax^db\}
1991 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1992 {end do\}
1993
1994 end subroutine mhd_check_w_noe
1995
1996 subroutine mhd_check_w_inte(primitive,ixI^L,ixO^L,w,flag)
1998
1999 logical, intent(in) :: primitive
2000 integer, intent(in) :: ixi^l, ixo^l
2001 double precision, intent(in) :: w(ixi^s,nw)
2002 logical, intent(inout) :: flag(ixi^s,1:nw)
2003
2004 integer :: ix^d
2005
2006 flag=.false.
2007 {do ix^db=ixomin^db,ixomax^db\}
2008 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
2009 if(primitive) then
2010 if(w(ix^d,p_) < small_pressure) flag(ix^d,e_) = .true.
2011 else
2012 if(w(ix^d,e_)<small_e) flag(ix^d,e_) = .true.
2013 end if
2014 {end do\}
2015
2016 end subroutine mhd_check_w_inte
2017
2018 subroutine mhd_check_w_hde(primitive,ixI^L,ixO^L,w,flag)
2020
2021 logical, intent(in) :: primitive
2022 integer, intent(in) :: ixi^l, ixo^l
2023 double precision, intent(in) :: w(ixi^s,nw)
2024 logical, intent(inout) :: flag(ixi^s,1:nw)
2025
2026 integer :: ix^d
2027
2028 flag=.false.
2029 {do ix^db=ixomin^db,ixomax^db\}
2030 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
2031 if(primitive) then
2032 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
2033 else
2034 if(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)<small_e) flag(ix^d,e_) = .true.
2035 end if
2036 {end do\}
2037
2038 end subroutine mhd_check_w_hde
2039
2040 subroutine mhd_bound_fip(primitive, ixI^L, ixO^L, w)
2042 logical, intent(in) :: primitive
2043 integer, intent(in) :: ixi^l, ixo^l
2044 double precision, intent(inout) :: w(ixi^s,1:nw)
2045
2046 double precision :: rho_safe(ixi^s), fip_prim(ixi^s)
2047
2048 if (.not. mhd_fip) return
2049
2050 if (primitive) then
2051 w(ixo^s,fip_) = min(maxfip, max(minfip, w(ixo^s,fip_)))
2052 else
2053 if (has_equi_rho_and_p) then
2054 rho_safe(ixo^s) = max(w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i), small_density)
2055 else
2056 rho_safe(ixo^s) = max(w(ixo^s,rho_), small_density)
2057 end if
2058 fip_prim(ixo^s) = w(ixo^s,fip_) / rho_safe(ixo^s)
2059 fip_prim(ixo^s) = min(maxfip, max(minfip, fip_prim(ixo^s)))
2060 w(ixo^s,fip_) = rho_safe(ixo^s) * fip_prim(ixo^s)
2061 end if
2062 end subroutine mhd_bound_fip
2063
2064 !> Return local UAWSoM closure coefficients in code units. User cases may
2065 !> replace all three profiles through usr_uawsom_coefficients.
2066 subroutine mhd_uawsom_get_coefficients(w,x,ixI^L,ixO^L,primitive,zeta,radius,lperp_A)
2069 integer, intent(in) :: ixi^l, ixo^l
2070 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
2071 logical, intent(in) :: primitive
2072 double precision, intent(out) :: zeta(ixi^s), radius(ixi^s), lperp_a(ixi^s)
2073 double precision :: bmag(ixi^s), btotal(ixi^s,1:ndir), height_base
2074 integer :: idir
2075
2076 if(associated(usr_uawsom_coefficients)) then
2077 call usr_uawsom_coefficients(w,x,ixi^l,ixo^l,primitive,zeta,radius,lperp_a)
2078 else
2079 do idir=1,ndir
2080 if(b0field) then
2081 btotal(ixo^s,idir)=w(ixo^s,mag(idir))+block%B0(ixo^s,idir,b0i)
2082 else
2083 btotal(ixo^s,idir)=w(ixo^s,mag(idir))
2084 end if
2085 end do
2086 bmag(ixo^s)=dsqrt(sum(btotal(ixo^s,1:ndir)**2,dim=ndim+1))
2087 select case(mhd_uawsom_height_dim)
2088 case(1)
2089 height_base=xprobmin1
2090 {^nooned
2091 case(2)
2092 height_base=xprobmin2
2093 }
2094 {^ifthreed
2095 case(3)
2096 height_base=xprobmin3
2097 }
2098 end select
2099 zeta(ixo^s)=one+(mhd_uawsom_zeta0-one)*dexp(&
2100 -max(x(ixo^s,mhd_uawsom_height_dim)-height_base,zero)/&
2102 radius(ixo^s)=mhd_uawsom_thread_radius0*dsqrt(&
2103 mhd_uawsom_bref/max(bmag(ixo^s),smalldouble))
2104 lperp_a(ixo^s)=mhd_uawsom_alfven_corr_length0*dsqrt(&
2105 mhd_uawsom_bref/max(bmag(ixo^s),smalldouble))
2106 end if
2107 if(any(zeta(ixo^s)<=one) .or. any(radius(ixo^s)<=zero) .or. &
2108 any(lperp_a(ixo^s)<=zero)) &
2109 call mpistop('mhd_uawsom coefficients require zeta>1 and positive lengths')
2110 end subroutine mhd_uawsom_get_coefficients
2111
2112 subroutine mhd_uawsom_rho2_factor(ixI^L,ixO^L,w,x,factor)
2114 integer, intent(in) :: ixi^l, ixo^l
2115 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
2116 double precision, intent(out) :: factor(ixi^s)
2117 double precision :: zeta(ixi^s), radius(ixi^s), lperp_a(ixi^s)
2118 call mhd_uawsom_get_coefficients(w,x,ixi^l,ixo^l,.false.,zeta,radius,lperp_a)
2119 factor(ixo^s)=mhd_uawsom_rho2_factor_cell(zeta(ixo^s))
2120 end subroutine mhd_uawsom_rho2_factor
2121
2122 elemental pure double precision function mhd_uawsom_rho2_factor_cell(zeta)
2123 double precision, intent(in) :: zeta
2124 double precision :: f
2126 mhd_uawsom_rho2_factor_cell=1.d0+f*(1.d0-f)*(zeta-1.d0)**2/&
2127 (1.d0+f*zeta-f)**2
2128 end function mhd_uawsom_rho2_factor_cell
2129
2130 pure double precision function mhd_uawsom_wave_pressure_cell(wcell,zeta)
2131 double precision, intent(in) :: wcell(:),zeta
2132 mhd_uawsom_wave_pressure_cell=0.5d0*(wcell(waplus_)+wcell(waminus_))+&
2133 0.25d0*(zeta+1.d0)*(wcell(wkplus_)+wcell(wkminus_))
2135
2136 pure double precision function mhd_uawsom_wave_energy_cell(wcell)
2137 use mod_constants, only: zero
2138 double precision, intent(in) :: wcell(:)
2139 if(mhd_uawsom) then
2141 wcell(wkplus_)+wcell(wkminus_)
2142 else
2144 end if
2145 end function mhd_uawsom_wave_energy_cell
2146
2147 !> Signed population imbalance used by the Cartesian gradient-vorticity reflection model.
2148 !> A positive value transfers W_A^+ (or W_k^+) to the minus population;
2149 !> a negative value transfers the minus population to the plus population.
2150 !> The factor is zero for a balanced state and remains bounded in [-1,1]
2151 !> for an arbitrarily imbalanced state.
2152 elemental pure double precision function mhd_uawsom_imbalance_factor(wplus,wminus)
2153 double precision, intent(in) :: wplus,wminus
2154
2155 if(wplus<=0.d0 .or. wminus<=0.d0) then
2156 mhd_uawsom_imbalance_factor=0.d0
2157 else if(4.d0*wminus<=wplus) then
2158 mhd_uawsom_imbalance_factor=1.d0-2.d0*dsqrt(wminus/wplus)
2159 else if(4.d0*wplus<=wminus) then
2160 mhd_uawsom_imbalance_factor=-(1.d0-2.d0*dsqrt(wplus/wminus))
2161 else
2162 mhd_uawsom_imbalance_factor=0.d0
2163 end if
2164 end function mhd_uawsom_imbalance_factor
2165
2166 !> UAWSoM compression, nonlinear damping, and optional Alfven reflection.
2167 !> Total energy is intentionally unchanged by damping: because it contains
2168 !> the four W variables, their loss is recovered as gas internal energy.
2169 subroutine mhd_add_source_uawsom(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x)
2172 integer, intent(in) :: ixi^l, ixo^l
2173 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), &
2174 wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
2175 double precision, intent(inout) :: w(ixi^s,1:nw)
2176 double precision :: v(ixi^s,1:ndir), divv(ixi^s)
2177 double precision :: zeta(ixi^s), radius(ixi^s), lperp_a(ixi^s)
2178 double precision :: lperp_k(ixi^s), rho_e(ixi^s)
2179 double precision :: gamma_plus(ixi^s), gamma_minus(ixi^s)
2180 double precision :: gamma_kplus(ixi^s), gamma_kminus(ixi^s)
2181 double precision :: dampap(ixi^s), dampam(ixi^s), dampkp(ixi^s), dampkm(ixi^s)
2182 double precision :: btotal(ixi^s,1:ndir), bunit(ixi^s,1:ndir), bmag(ixi^s)
2183 double precision :: va(ixi^s), vk(ixi^s), lnva(ixi^s), lnvk(ixi^s)
2184 double precision :: grad_component(ixi^s), grad_a(ixi^s), grad_k(ixi^s)
2185 double precision :: curlv(ixi^s,1:3), vorticity(ixi^s)
2186 double precision :: rimb_a(ixi^s), rlim_a(ixi^s), rlim_k(ixi^s)
2187 double precision :: refl_rate(ixi^s), donor_reflection(ixi^s)
2188 double precision :: transfer_a(ixi^s), transfer_k(ixi^s), donor(ixi^s)
2189 double precision :: imbalance_a(ixi^s), imbalance_k(ixi^s)
2190 double precision :: wave_plus(ixi^s), wave_minus(ixi^s)
2191 double precision :: wave_kplus(ixi^s), wave_kminus(ixi^s)
2192 double precision :: f, kink_pressure(ixi^s)
2193 integer :: idir, idirmin
2194 logical :: have_reflection, have_alfven_reflection, have_kink_reflection
2195
2196 call mhd_get_v(wct,x,ixi^l,ixi^l,v)
2197 call divvector(v,ixi^l,ixo^l,divv)
2198 ! Reflection gradients need one-cell ghost values, so obtain the closure
2199 ! profiles on ixI rather than only on the source update region.
2200 call mhd_uawsom_get_coefficients(wct,x,ixi^l,ixi^l,.false.,zeta,radius,lperp_a)
2202 rho_e(ixi^s)=max(wct(ixi^s,rho_),small_density)/&
2203 max(one+f*zeta(ixi^s)-f,smalldouble)
2204 lperp_k(ixi^s)=dsqrt(10.d0)*dsqrt(f*dpi)*radius(ixi^s)*&
2205 (zeta(ixi^s)+one-f)**1.5d0/&
2206 ((zeta(ixi^s)-one)*(one-f**2.5d0))
2207 gamma_plus(ixo^s)=two/lperp_a(ixo^s)*dsqrt(&
2208 max(wct(ixo^s,waminus_),zero)/max(wct(ixo^s,rho_),small_density))
2209 gamma_minus(ixo^s)=two/lperp_a(ixo^s)*dsqrt(&
2210 max(wct(ixo^s,waplus_),zero)/max(wct(ixo^s,rho_),small_density))
2211 dampap(ixo^s)=gamma_plus(ixo^s)*max(wct(ixo^s,waplus_),zero)
2212 dampam(ixo^s)=gamma_minus(ixo^s)*max(wct(ixo^s,waminus_),zero)
2213 dampkp(ixo^s)=max(wct(ixo^s,wkplus_),zero)**1.5d0/&
2214 (dsqrt(rho_e(ixo^s))*lperp_k(ixo^s))
2215 dampkm(ixo^s)=max(wct(ixo^s,wkminus_),zero)**1.5d0/&
2216 (dsqrt(rho_e(ixo^s))*lperp_k(ixo^s))
2217 gamma_kplus(ixo^s)=dsqrt(max(wct(ixo^s,wkplus_),zero)/&
2218 max(rho_e(ixo^s),small_density))/max(lperp_k(ixo^s),smalldouble)
2219 gamma_kminus(ixo^s)=dsqrt(max(wct(ixo^s,wkminus_),zero)/&
2220 max(rho_e(ixo^s),small_density))/max(lperp_k(ixo^s),smalldouble)
2221
2222 w(ixo^s,waplus_)=w(ixo^s,waplus_)-qdt*(&
2223 half*divv(ixo^s)*wct(ixo^s,waplus_)+dampap(ixo^s))
2224 w(ixo^s,waminus_)=w(ixo^s,waminus_)-qdt*(&
2225 half*divv(ixo^s)*wct(ixo^s,waminus_)+dampam(ixo^s))
2226 w(ixo^s,wkplus_)=w(ixo^s,wkplus_)-qdt*(&
2227 half*divv(ixo^s)*wct(ixo^s,wkplus_)+dampkp(ixo^s))
2228 w(ixo^s,wkminus_)=w(ixo^s,wkminus_)-qdt*(&
2229 half*divv(ixo^s)*wct(ixo^s,wkminus_)+dampkm(ixo^s))
2230
2231 kink_pressure(ixo^s)=quarter*(zeta(ixo^s)+one)*&
2232 (wct(ixo^s,wkplus_)+wct(ixo^s,wkminus_))
2233 w(ixo^s,e_)=w(ixo^s,e_)+qdt*(zeta(ixo^s)-one)/&
2234 (zeta(ixo^s)+one)*kink_pressure(ixo^s)*divv(ixo^s)
2235
2236 have_alfven_reflection=.false.
2237 if(mhd_uawsom_reflection) then
2238 select case(trim(mhd_uawsom_reflection_mode))
2239 case('one_dimensional_gradient')
2240 have_alfven_reflection=(mhd_uawsom_sigma>zero)
2241 case('cartesian_gradient_vorticity')
2242 have_alfven_reflection=.true.
2243 end select
2244 end if
2245 have_kink_reflection=mhd_uawsom_kink_reflection
2246 have_reflection=have_alfven_reflection .or. have_kink_reflection
2247 if(have_reflection) then
2248 do idir=1,ndir
2249 if(b0field) then
2250 btotal(ixi^s,idir)=wct(ixi^s,mag(idir))+block%B0(ixi^s,idir,b0i)
2251 else
2252 btotal(ixi^s,idir)=wct(ixi^s,mag(idir))
2253 end if
2254 end do
2255 bmag(ixi^s)=dsqrt(sum(btotal(ixi^s,1:ndir)**2,dim=ndim+1))
2256 do idir=1,ndir
2257 bunit(ixi^s,idir)=btotal(ixi^s,idir)/max(bmag(ixi^s),smalldouble)
2258 end do
2259 va(ixi^s)=bmag(ixi^s)/dsqrt(max(wct(ixi^s,rho_),small_density))
2260 vk(ixi^s)=bmag(ixi^s)/dsqrt(max(rho_e(ixi^s)*&
2261 (zeta(ixi^s)+one)/two,smalldouble))
2262 lnva(ixi^s)=dlog(max(va(ixi^s),smalldouble))
2263 lnvk(ixi^s)=dlog(max(vk(ixi^s),smalldouble))
2264
2265 ! Apply exchange after the ordinary source update. The donor cap below
2266 ! uses that actual post-damping state; it does not silently repair a
2267 ! negative state produced by compression or damping. The standard
2268 ! small-value handling remains responsible for such a state.
2269 if(have_alfven_reflection) then
2270 wave_plus(ixo^s)=max(wct(ixo^s,waplus_),zero)
2271 wave_minus(ixo^s)=max(wct(ixo^s,waminus_),zero)
2272
2273 select case(trim(mhd_uawsom_reflection_mode))
2274 case('one_dimensional_gradient')
2275 ! Retain the original one-dimensional source and sign convention:
2276 ! a positive transfer removes W_A^+ and adds W_A^-.
2277 call gradient(va,ixi^l,ixo^l,mhd_uawsom_height_dim,grad_component)
2278 refl_rate(ixo^s)=mhd_uawsom_sigma*&
2279 (wctprim(ixo^s,mom(mhd_uawsom_height_dim))+va(ixo^s))/&
2280 max(va(ixo^s),smalldouble)*grad_component(ixo^s)
2281 donor_reflection(ixo^s)=merge(max(wct(ixo^s,waplus_),zero),&
2282 max(wct(ixo^s,waminus_),zero),refl_rate(ixo^s)>=zero)
2283 transfer_a(ixo^s)=refl_rate(ixo^s)*donor_reflection(ixo^s)
2284 case('cartesian_gradient_vorticity')
2285 grad_a(ixo^s)=zero
2286 do idir=1,ndim
2287 call gradient(lnva,ixi^l,ixo^l,idir,grad_component)
2288 grad_a(ixo^s)=grad_a(ixo^s)+va(ixo^s)*bunit(ixo^s,idir)*&
2289 grad_component(ixo^s)
2290 end do
2291 call curlvector(v,ixi^l,ixo^l,curlv,idirmin,1,ndir)
2292 vorticity(ixo^s)=zero
2293 do idir=1,ndir
2294 vorticity(ixo^s)=vorticity(ixo^s)+bunit(ixo^s,idir)*&
2295 curlv(ixo^s,idir)
2296 end do
2297 ! Sigma belongs to the one-dimensional gradient source only; it is
2298 ! absent from the Cartesian gradient-vorticity R_imb/R_lim closure.
2299 rimb_a(ixo^s)=dsqrt(grad_a(ixo^s)**2+vorticity(ixo^s)**2)
2300 rlim_a(ixo^s)=min(rimb_a(ixo^s),&
2301 max(gamma_plus(ixo^s),gamma_minus(ixo^s)))
2302 imbalance_a(ixo^s)=mhd_uawsom_imbalance_factor(&
2303 wave_plus(ixo^s),wave_minus(ixo^s))
2304 transfer_a(ixo^s)=rlim_a(ixo^s)*imbalance_a(ixo^s)*&
2305 dsqrt(wave_plus(ixo^s)*wave_minus(ixo^s))
2306 end select
2307
2308 if(qdt>zero) then
2309 donor(ixo^s)=merge(max(w(ixo^s,waplus_),zero),&
2310 max(w(ixo^s,waminus_),zero),transfer_a(ixo^s)>=zero)
2311 transfer_a(ixo^s)=sign(min(abs(transfer_a(ixo^s)),&
2312 donor(ixo^s)/qdt),transfer_a(ixo^s))
2313 else
2314 transfer_a(ixo^s)=zero
2315 end if
2316 w(ixo^s,waplus_)=w(ixo^s,waplus_)-qdt*transfer_a(ixo^s)
2317 w(ixo^s,waminus_)=w(ixo^s,waminus_)+qdt*transfer_a(ixo^s)
2318 end if
2319
2320 if(have_kink_reflection) then
2321 wave_kplus(ixo^s)=max(wct(ixo^s,wkplus_),zero)
2322 wave_kminus(ixo^s)=max(wct(ixo^s,wkminus_),zero)
2323 grad_k(ixo^s)=zero
2324 do idir=1,ndim
2325 call gradient(lnvk,ixi^l,ixo^l,idir,grad_component)
2326 grad_k(ixo^s)=grad_k(ixo^s)+vk(ixo^s)*bunit(ixo^s,idir)*&
2327 grad_component(ixo^s)
2328 end do
2329 ! Kink reflection deliberately uses only the kink-speed gradient;
2330 ! the field-aligned velocity-vorticity term belongs to Alfvén waves,
2331 ! and sigma is not part of this limiter.
2332 rlim_k(ixo^s)=min(abs(grad_k(ixo^s)),&
2333 max(gamma_kplus(ixo^s),gamma_kminus(ixo^s)))
2334 imbalance_k(ixo^s)=mhd_uawsom_imbalance_factor(&
2335 wave_kplus(ixo^s),wave_kminus(ixo^s))
2336 transfer_k(ixo^s)=rlim_k(ixo^s)*imbalance_k(ixo^s)*&
2337 dsqrt(wave_kplus(ixo^s)*wave_kminus(ixo^s))
2338 if(qdt>zero) then
2339 donor(ixo^s)=merge(max(w(ixo^s,wkplus_),zero),&
2340 max(w(ixo^s,wkminus_),zero),transfer_k(ixo^s)>=zero)
2341 transfer_k(ixo^s)=sign(min(abs(transfer_k(ixo^s)),&
2342 donor(ixo^s)/qdt),transfer_k(ixo^s))
2343 else
2344 transfer_k(ixo^s)=zero
2345 end if
2346 w(ixo^s,wkplus_)=w(ixo^s,wkplus_)-qdt*transfer_k(ixo^s)
2347 w(ixo^s,wkminus_)=w(ixo^s,wkminus_)+qdt*transfer_k(ixo^s)
2348 end if
2349 end if
2350 end subroutine mhd_add_source_uawsom
2351
2352 !> Transform internal energy to total energy
2353 subroutine mhd_ei_to_e(ixI^L,ixO^L,w,x)
2355 integer, intent(in) :: ixi^l, ixo^l
2356 double precision, intent(inout) :: w(ixi^s, nw)
2357 double precision, intent(in) :: x(ixi^s, 1:ndim)
2358
2359 integer :: ix^d
2360
2361 if(has_equi_rho_and_p) then
2362 {do ix^db=ixomin^db,ixomax^db\}
2363 ! Calculate e = ei + ek + eb
2364 w(ix^d,e_)=w(ix^d,e_)&
2365 +half*((^c&w(ix^d,m^c_)**2+)/&
2366 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2367 +(^c&w(ix^d,b^c_)**2+))
2368 {end do\}
2369 else
2370 {do ix^db=ixomin^db,ixomax^db\}
2371 ! Calculate e = ei + ek + eb
2372 w(ix^d,e_)=w(ix^d,e_)&
2373 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2374 +(^c&w(ix^d,b^c_)**2+))&
2375 +mhd_uawsom_wave_energy_cell(w(ix^d,:))
2376 {end do\}
2377 end if
2378 end subroutine mhd_ei_to_e
2379
2380 !> Transform internal energy to hydrodynamic energy
2381 subroutine mhd_ei_to_e_hde(ixI^L,ixO^L,w,x)
2383 integer, intent(in) :: ixi^l, ixo^l
2384 double precision, intent(inout) :: w(ixi^s, nw)
2385 double precision, intent(in) :: x(ixi^s, 1:ndim)
2386
2387 integer :: ix^d
2388
2389 {do ix^db=ixomin^db,ixomax^db\}
2390 ! Calculate e = ei + ek
2391 w(ix^d,e_)=w(ix^d,e_)&
2392 +half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2393 {end do\}
2394
2395 end subroutine mhd_ei_to_e_hde
2396
2397 !> Transform internal energy to total energy and velocity to momentum
2398 subroutine mhd_ei_to_e_semirelati(ixI^L,ixO^L,w,x)
2400 integer, intent(in) :: ixi^l, ixo^l
2401 double precision, intent(inout) :: w(ixi^s, nw)
2402 double precision, intent(in) :: x(ixi^s, 1:ndim)
2403
2404 w(ixo^s,p_)=w(ixo^s,e_)*eos%gamma_minus_1
2405 ! call eos%to_conserved(ixI^L,ixO^L,w,x)
2406 call eos%to_conserved(ixi^l,ixo^l,w,x)
2407
2408 end subroutine mhd_ei_to_e_semirelati
2409
2410 !> Transform total energy to internal energy
2411 subroutine mhd_e_to_ei(ixI^L,ixO^L,w,x)
2413 integer, intent(in) :: ixi^l, ixo^l
2414 double precision, intent(inout) :: w(ixi^s, nw)
2415 double precision, intent(in) :: x(ixi^s, 1:ndim)
2416
2417 integer :: ix^d
2418
2419 if(has_equi_rho_and_p) then
2420 {do ix^db=ixomin^db,ixomax^db\}
2421 ! Calculate ei = e - ek - eb
2422 w(ix^d,e_)=w(ix^d,e_)&
2423 -half*((^c&w(ix^d,m^c_)**2+)/&
2424 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2425 +(^c&w(ix^d,b^c_)**2+))
2426 {end do\}
2427 else
2428 {do ix^db=ixomin^db,ixomax^db\}
2429 ! Calculate ei = e - ek - eb
2430 w(ix^d,e_)=w(ix^d,e_)&
2431 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2432 +(^c&w(ix^d,b^c_)**2+))&
2433 -mhd_uawsom_wave_energy_cell(w(ix^d,:))
2434 {end do\}
2435 end if
2436
2437 if(fix_small_values) then
2438 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei')
2439 end if
2440
2441 end subroutine mhd_e_to_ei
2442
2443 !> Wrapper: e_to_ei + cache log10(nH) in wextra for LTE TC fast path.
2444 !> During STS substeps density is invariant, so log10(nH) is computed once
2445 !> per STS cycle (in sts_before_first_cycle hook) and reused across all substeps.
2446 subroutine mhd_e_to_ei_and_cache_log_nh(ixI^L,ixO^L,w,x)
2448 integer, intent(in) :: ixi^l, ixo^l
2449 double precision, intent(inout) :: w(ixi^s, nw)
2450 double precision, intent(in) :: x(ixi^s, 1:ndim)
2451
2452 call mhd_e_to_ei(ixi^l,ixo^l,w,x)
2453 block%wextra(ixo^s, iw_log_nh) = dlog10(w(ixo^s, rho_) / eos%nH2rhoFactor)
2454 end subroutine mhd_e_to_ei_and_cache_log_nh
2455
2456 !> Transform hydrodynamic energy to internal energy
2457 subroutine mhd_e_to_ei_hde(ixI^L,ixO^L,w,x)
2459 integer, intent(in) :: ixi^l, ixo^l
2460 double precision, intent(inout) :: w(ixi^s, nw)
2461 double precision, intent(in) :: x(ixi^s, 1:ndim)
2462
2463 integer :: ix^d
2464
2465 {do ix^db=ixomin^db,ixomax^db\}
2466 ! Calculate ei = e - ek
2467 w(ix^d,e_)=w(ix^d,e_)&
2468 -half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2469 {end do\}
2470
2471 if(fix_small_values) then
2472 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei_hde')
2473 end if
2474
2475 end subroutine mhd_e_to_ei_hde
2476
2477 !> Transform total energy to internal energy and momentum to velocity
2478 subroutine mhd_e_to_ei_semirelati(ixI^L,ixO^L,w,x)
2480 integer, intent(in) :: ixi^l, ixo^l
2481 double precision, intent(inout) :: w(ixi^s, nw)
2482 double precision, intent(in) :: x(ixi^s, 1:ndim)
2483
2484 call eos%to_primitive(ixi^l,ixo^l,w,x)
2485 w(ixo^s,e_)=w(ixo^s,p_)*eos%inv_gamma_minus_1
2486
2487 end subroutine mhd_e_to_ei_semirelati
2488
2489 subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixI^L, ixO^L, subname)
2492 logical, intent(in) :: primitive
2493 integer, intent(in) :: ixi^l,ixo^l
2494 double precision, intent(inout) :: w(ixi^s,1:nw)
2495 double precision, intent(in) :: x(ixi^s,1:ndim)
2496 character(len=*), intent(in) :: subname
2497
2498 double precision :: e(ixi^s,1:ndir), pressure(ixi^s), v(ixi^s,1:ndir)
2499 double precision :: tmp, factor
2500 integer :: ix^d
2501 logical :: flag(ixi^s,1:nw)
2502
2503 flag=.false.
2504 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
2505
2506 if(mhd_energy) then
2507 if(primitive) then
2508 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
2509 else
2510 {do ix^db=ixomin^db,ixomax^db\}
2511 ! Convert momentum to velocity
2512 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2513 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2514 ^c&v(ix^d,^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2515 ! E=Bxv
2516 {^ifthreec
2517 e(ix^d,1)=w(ix^d,b2_)*v(ix^d,3)-w(ix^d,b3_)*v(ix^d,2)
2518 e(ix^d,2)=w(ix^d,b3_)*v(ix^d,1)-w(ix^d,b1_)*v(ix^d,3)
2519 e(ix^d,3)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2520 }
2521 {^iftwoc
2522 e(ix^d,1)=zero
2523 e(ix^d,2)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2524 }
2525 {^ifonec
2526 e(ix^d,1)=zero
2527 }
2528 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2529 pressure(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)&
2530 -half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2531 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c))
2532 if(pressure(ix^d) < small_pressure) flag(ix^d,p_) = .true.
2533 {end do\}
2534 end if
2535 end if
2536
2537 if(any(flag)) then
2538 select case (small_values_method)
2539 case ("replace")
2540 {do ix^db=ixomin^db,ixomax^db\}
2541 if(flag(ix^d,rho_)) then
2542 w(ix^d,rho_) = small_density
2543 ^c&w(ix^d,m^c_)=0.d0\
2544 end if
2545 if(mhd_energy) then
2546 if(primitive) then
2547 if(flag(ix^d,e_)) w(ix^d,p_) = small_pressure
2548 else
2549 if(flag(ix^d,e_)) then
2550 w(ix^d,e_)=small_pressure*eos%inv_gamma_minus_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2551 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2552 end if
2553 end if
2554 end if
2555 {end do\}
2556 case ("average")
2557 ! do averaging of density
2558 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2559 if(mhd_energy) then
2560 if(primitive) then
2561 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2562 else
2563 w(ixo^s,e_)=pressure(ixo^s)
2564 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2565 {do ix^db=ixomin^db,ixomax^db\}
2566 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2567 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2568 {end do\}
2569 end if
2570 end if
2571 case default
2572 if(.not.primitive) then
2573 ! change to primitive variables
2574 w(ixo^s,mom(1:ndir))=v(ixo^s,1:ndir)
2575 if(mhd_energy) w(ixo^s,e_)=pressure(ixo^s)
2576 end if
2577 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2578 end select
2579 end if
2580 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2581 end subroutine mhd_handle_small_values_semirelati
2582
2583 subroutine mhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
2586 logical, intent(in) :: primitive
2587 integer, intent(in) :: ixi^l,ixo^l
2588 double precision, intent(inout) :: w(ixi^s,1:nw)
2589 double precision, intent(in) :: x(ixi^s,1:ndim)
2590 character(len=*), intent(in) :: subname
2591
2592 integer :: ix^d, igrp
2593 logical :: flag(ixi^s,1:nw)
2594
2595 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2596
2597 if(any(flag)) then
2598 select case (small_values_method)
2599 case ("replace")
2600 {do ix^db=ixomin^db,ixomax^db\}
2601 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2602 {
2603 if(small_values_fix_iw(m^c_)) then
2604 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2605 end if
2606 \}
2607 if(primitive) then
2608 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2609 else
2610 if(mhd_uawsom) then
2611 if(flag(ix^d,waplus_)) w(ix^d,waplus_)=zero
2612 if(flag(ix^d,waminus_)) w(ix^d,waminus_)=zero
2613 if(flag(ix^d,wkplus_)) w(ix^d,wkplus_)=zero
2614 if(flag(ix^d,wkminus_)) w(ix^d,wkminus_)=zero
2615 end if
2616 if(flag(ix^d,e_)) &
2617 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))&
2619 end if
2620 if(mhd_radiation_fld)then
2621 if(small_values_fix_iw(r_e)) then
2622 if(flag(ix^d,r_e)) w(ix^d,r_e)=small_r_e
2623 endif
2624 endif
2625 {end do\}
2626 case ("average")
2627 ! do averaging of density
2628 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2629 if(primitive)then
2630 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2631 else
2632 if(mhd_uawsom) then
2633 call small_values_average(ixi^l,ixo^l,w,x,flag,waplus_)
2634 call small_values_average(ixi^l,ixo^l,w,x,flag,waminus_)
2635 call small_values_average(ixi^l,ixo^l,w,x,flag,wkplus_)
2636 call small_values_average(ixi^l,ixo^l,w,x,flag,wkminus_)
2637 end if
2638 ! do averaging of internal energy
2639 {do ix^db=iximin^db,iximax^db\}
2640 w(ix^d,e_)=w(ix^d,e_)&
2641 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))&
2642 -mhd_uawsom_wave_energy_cell(w(ix^d,:))
2643 {end do\}
2644 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2645 ! convert back
2646 {do ix^db=iximin^db,iximax^db\}
2647 w(ix^d,e_)=w(ix^d,e_)&
2648 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))&
2649 +mhd_uawsom_wave_energy_cell(w(ix^d,:))
2650 {end do\}
2651 end if
2652 if(mhd_radiation_fld) then
2653 call small_values_average(ixi^l, ixo^l, w, x, flag, r_e)
2654 endif
2655 case default
2656 if(.not.primitive) then
2657 !convert w to primitive
2658 {do ix^db=ixomin^db,ixomax^db\}
2659 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2660 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
2661 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))&
2662 -mhd_uawsom_wave_energy_cell(w(ix^d,:)))
2663 {end do\}
2664 end if
2665 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2666 end select
2667 end if
2668 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2669 end subroutine mhd_handle_small_values_origin
2670
2671 subroutine mhd_handle_small_values_split(primitive, w, x, ixI^L, ixO^L, subname)
2674 logical, intent(in) :: primitive
2675 integer, intent(in) :: ixi^l,ixo^l
2676 double precision, intent(inout) :: w(ixi^s,1:nw)
2677 double precision, intent(in) :: x(ixi^s,1:ndim)
2678 character(len=*), intent(in) :: subname
2679
2680 double precision :: rho
2681 integer :: ix^d, igrp
2682 logical :: flag(ixi^s,1:nw)
2683
2684 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2685
2686 if(any(flag)) then
2687 select case (small_values_method)
2688 case ("replace")
2689 {do ix^db=ixomin^db,ixomax^db\}
2690 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2691 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density-block%equi_vars(ix^d,equi_rho0_,0)
2692 {
2693 if(small_values_fix_iw(m^c_)) then
2694 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2695 end if
2696 \}
2697 if(primitive) then
2698 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure-block%equi_vars(ix^d,equi_pe0_,0)
2699 else
2700 if(flag(ix^d,e_)) &
2701 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))&
2702 -block%equi_vars(ix^d,equi_pe0_,0)*eos%inv_gamma_minus_1
2703 end if
2704 {end do\}
2705 case ("average")
2706 ! do averaging of density
2707 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2708 if(primitive)then
2709 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2710 else
2711 ! do averaging of internal energy
2712 {do ix^db=iximin^db,iximax^db\}
2713 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2714 w(ix^d,e_)=w(ix^d,e_)&
2715 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2716 {end do\}
2717 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2718 ! convert back
2719 {do ix^db=iximin^db,iximax^db\}
2720 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2721 w(ix^d,e_)=w(ix^d,e_)&
2722 +half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2723 {end do\}
2724 end if
2725 case default
2726 if(.not.primitive) then
2727 !convert w to primitive
2728 {do ix^db=ixomin^db,ixomax^db\}
2729 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2730 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/rho\
2731 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
2732 -half*((^c&w(ix^d,m^c_)**2+)*rho+(^c&w(ix^d,b^c_)**2+)))
2733 {end do\}
2734 end if
2735 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2736 end select
2737 end if
2738 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2739 end subroutine mhd_handle_small_values_split
2740
2741 subroutine mhd_handle_small_values_inte(primitive, w, x, ixI^L, ixO^L, subname)
2744 logical, intent(in) :: primitive
2745 integer, intent(in) :: ixi^l,ixo^l
2746 double precision, intent(inout) :: w(ixi^s,1:nw)
2747 double precision, intent(in) :: x(ixi^s,1:ndim)
2748 character(len=*), intent(in) :: subname
2749
2750 integer :: ix^d, igrp
2751 logical :: flag(ixi^s,1:nw)
2752
2753 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2754
2755 if(any(flag)) then
2756 select case (small_values_method)
2757 case ("replace")
2758 {do ix^db=ixomin^db,ixomax^db\}
2759 if(flag(ix^d,rho_)) then
2760 w(ix^d,rho_)=small_density
2761 ^c&w(ix^d,m^c_)=0.d0\
2762 end if
2763 if(primitive) then
2764 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2765 else
2766 if(flag(ix^d,e_)) w(ix^d,e_)=small_e
2767 end if
2768 {end do\}
2769 case ("average")
2770 ! do averaging of density
2771 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2772 ! do averaging of internal energy
2773 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2774 case default
2775 if(.not.primitive) then
2776 !convert w to primitive
2777 {do ix^db=ixomin^db,ixomax^db\}
2778 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2779 w(ix^d,p_)=eos%gamma_minus_1*w(ix^d,e_)
2780 {end do\}
2781 end if
2782 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2783 end select
2784 end if
2785 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2786 end subroutine mhd_handle_small_values_inte
2787
2788 subroutine mhd_handle_small_values_noe(primitive, w, x, ixI^L, ixO^L, subname)
2791 logical, intent(in) :: primitive
2792 integer, intent(in) :: ixi^l,ixo^l
2793 double precision, intent(inout) :: w(ixi^s,1:nw)
2794 double precision, intent(in) :: x(ixi^s,1:ndim)
2795 character(len=*), intent(in) :: subname
2796
2797 integer :: ix^d, igrp
2798 logical :: flag(ixi^s,1:nw)
2799
2800 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2801
2802 if(any(flag)) then
2803 select case (small_values_method)
2804 case ("replace")
2805 {do ix^db=ixomin^db,ixomax^db\}
2806 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2807 {
2808 if(small_values_fix_iw(m^c_)) then
2809 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2810 end if
2811 \}
2812 {end do\}
2813 case ("average")
2814 ! do averaging of density
2815 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2816 case default
2817 if(.not.primitive) then
2818 !convert w to primitive
2819 {do ix^db=ixomin^db,ixomax^db\}
2820 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2821 {end do\}
2822 end if
2823 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2824 end select
2825 end if
2826 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2827 end subroutine mhd_handle_small_values_noe
2828
2829 subroutine mhd_handle_small_values_hde(primitive, w, x, ixI^L, ixO^L, subname)
2832 logical, intent(in) :: primitive
2833 integer, intent(in) :: ixi^l,ixo^l
2834 double precision, intent(inout) :: w(ixi^s,1:nw)
2835 double precision, intent(in) :: x(ixi^s,1:ndim)
2836 character(len=*), intent(in) :: subname
2837
2838 integer :: ix^d, igrp
2839 logical :: flag(ixi^s,1:nw)
2840
2841 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2842
2843 if(any(flag)) then
2844 select case (small_values_method)
2845 case ("replace")
2846 {do ix^db=ixomin^db,ixomax^db\}
2847 if(flag(ix^d,rho_)) then
2848 w(ix^d,rho_)=small_density
2849 ^c&w(ix^d,m^c_)=0.d0\
2850 end if
2851 if(primitive) then
2852 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2853 else
2854 if(flag(ix^d,e_)) w(ix^d,e_)=small_e+half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2855 end if
2856 {end do\}
2857 case ("average")
2858 ! do averaging of density
2859 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2860 ! do averaging of energy
2861 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2862 case default
2863 if(.not.primitive) then
2864 !convert w to primitive
2865 {do ix^db=ixomin^db,ixomax^db\}
2866 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2867 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_))
2868 {end do\}
2869 end if
2870 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2871 end select
2872 end if
2873 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2874 end subroutine mhd_handle_small_values_hde
2875
2876 !> Calculate v vector
2877 subroutine mhd_get_v(w,x,ixI^L,ixO^L,v)
2879
2880 integer, intent(in) :: ixi^l, ixo^l
2881 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
2882 double precision, intent(out) :: v(ixi^s,ndir)
2883
2884 double precision :: rho(ixi^s)
2885 integer :: idir
2886
2887 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2888
2889 rho(ixo^s)=1.d0/rho(ixo^s)
2890 ! Convert momentum to velocity
2891 do idir = 1, ndir
2892 v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
2893 end do
2894
2895 end subroutine mhd_get_v
2896
2897 !> Calculate csound**2 within ixO^L
2898 subroutine mhd_get_csound2(w,x,ixI^L,ixO^L,cs2)
2900
2901 integer, intent(in) :: ixi^l, ixo^l
2902 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2903 double precision, intent(inout) :: cs2(ixi^s)
2904
2905 double precision :: rho, inv_rho, ploc
2906 integer :: ix^d
2907
2908 {do ix^db=ixomin^db,ixomax^db \}
2909 if(has_equi_rho_and_p) then
2910 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))
2911 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0))
2912 else
2913 rho=w(ix^d,rho_)
2914 ploc=w(ix^d,p_)
2915 end if
2916 inv_rho=1.d0/rho
2917 ! sound speed**2
2918 cs2(ix^d)=eos%gamma*ploc*inv_rho
2919 {end do\}
2920 end subroutine mhd_get_csound2
2921
2922 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2923 subroutine mhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
2925
2926 integer, intent(in) :: ixi^l, ixo^l, idim
2927 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2928 double precision, intent(inout) :: cmax(ixi^s)
2929
2930 double precision :: rho, inv_rho, ploc, cfast2, avmincs2, b2, kmax
2931 double precision :: cs2(ixi^s)
2932 double precision :: uawsom_zeta(ixi^s), uawsom_radius(ixi^s), uawsom_lperp(ixi^s)
2933 integer :: ix^d
2934
2935 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2936 if(mhd_uawsom) call mhd_uawsom_get_coefficients(w,x,ixi^l,ixo^l,.true.,&
2937 uawsom_zeta,uawsom_radius,uawsom_lperp)
2938
2939 ! Sound speed squared via EoS dispatch (LTE+ionE -> Gamma_1 table; FI -> const gamma).
2940 call eos%get_csound2(w, x, ixi^l, ixo^l, cs2)
2941
2942 if(b0field) then
2943 {do ix^db=ixomin^db,ixomax^db \}
2944 if(has_equi_rho_and_p) then
2945 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2946 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2947 else
2948 rho=w(ix^d,rho_)
2949 ploc=w(ix^d,p_)
2950 end if
2951 inv_rho=1.d0/rho
2952 cmax(ix^d)=cs2(ix^d)
2953 ! store |B|^2 in v
2954 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
2955 cfast2=b2*inv_rho+cmax(ix^d)
2956 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2957 if(avmincs2<zero) avmincs2=zero
2958 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2959 if(mhd_hall) then
2960 ! take the Hall velocity into account: most simple estimate, high k limit:
2961 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2962 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2963 end if
2964 if(mhd_uawsom) then
2965 cmax(ix^d)=max(cmax(ix^d),abs(w(ix^d,mag(idim))+&
2966 block%B0(ix^d,idim,b0i))*dsqrt(inv_rho))
2967 cmax(ix^d)=max(cmax(ix^d),abs(w(ix^d,mag(idim))+&
2968 block%B0(ix^d,idim,b0i))/dsqrt(rho*&
2969 ((uawsom_zeta(ix^d)+one)/(two*(one+mhd_uawsom_filling_factor*&
2970 uawsom_zeta(ix^d)-mhd_uawsom_filling_factor)))))
2971 end if
2972 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2973 {end do\}
2974 else
2975 {do ix^db=ixomin^db,ixomax^db \}
2976 if(has_equi_rho_and_p) then
2977 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2978 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2979 else
2980 rho=w(ix^d,rho_)
2981 ploc=w(ix^d,p_)
2982 end if
2983 inv_rho=1.d0/rho
2984 cmax(ix^d)=cs2(ix^d)
2985 ! store |B|^2 in v
2986 b2=(^c&w(ix^d,b^c_)**2+)
2987 cfast2=b2*inv_rho+cmax(ix^d)
2988 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2989 if(avmincs2<zero) avmincs2=zero
2990 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2991 if(mhd_hall) then
2992 ! take the Hall velocity into account: most simple estimate, high k limit:
2993 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2994 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2995 end if
2996 if(mhd_uawsom) then
2997 cmax(ix^d)=max(cmax(ix^d),abs(w(ix^d,mag(idim)))*dsqrt(inv_rho))
2998 cmax(ix^d)=max(cmax(ix^d),abs(w(ix^d,mag(idim)))/dsqrt(rho*&
2999 ((uawsom_zeta(ix^d)+one)/(two*(one+mhd_uawsom_filling_factor*&
3000 uawsom_zeta(ix^d)-mhd_uawsom_filling_factor)))))
3001 end if
3002 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
3003 {end do\}
3004 end if
3005
3006 end subroutine mhd_get_cmax_origin
3007
3008 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
3009 subroutine mhd_get_cmax_origin_noe(w,x,ixI^L,ixO^L,idim,cmax)
3012
3013 integer, intent(in) :: ixi^l, ixo^l, idim
3014 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3015 double precision, intent(inout) :: cmax(ixi^s)
3016
3017 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
3018 double precision :: adiabs(ixi^s), gammas(ixi^s)
3019 integer :: ix^d
3020
3021 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3022
3023 if(associated(usr_set_adiab)) then
3024 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3025 else
3026 adiabs=mhd_adiab
3027 end if
3028 if(associated(usr_set_gamma)) then
3029 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3030 else
3031 gammas=eos%gamma
3032 end if
3033 {do ix^db=ixomin^db,ixomax^db \}
3034 rho=w(ix^d,rho_)
3035 inv_rho=1.d0/rho
3036 ! sound speed**2
3037 cmax(ix^d)=gammas(ix^d)*adiabs(ix^d)*rho**(gammas(ix^d)-1.d0)
3038 ! store |B|^2 in v
3039 b2=(^c&w(ix^d,b^c_)**2+)
3040 cfast2=b2*inv_rho+cmax(ix^d)
3041 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3042 if(avmincs2<zero) avmincs2=zero
3043 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3044 if(mhd_hall) then
3045 ! take the Hall velocity into account: most simple estimate, high k limit:
3046 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
3047 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3048 end if
3049 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
3050 {end do\}
3051
3052 end subroutine mhd_get_cmax_origin_noe
3053
3054 !> Calculate cmax_idim for semirelativistic MHD
3055 subroutine mhd_get_cmax_semirelati(w,x,ixI^L,ixO^L,idim,cmax)
3057
3058 integer, intent(in) :: ixi^l, ixo^l, idim
3059 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3060 double precision, intent(inout):: cmax(ixi^s)
3061
3062 double precision :: csound, avmincs2, idim_alfven_speed2
3063 double precision :: inv_rho, alfven_speed2, gamma2
3064 integer :: ix^d
3065
3066 {do ix^db=ixomin^db,ixomax^db \}
3067 inv_rho=1.d0/w(ix^d,rho_)
3068 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3069 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3070 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
3071 ! squared sound speed
3072 csound=eos%gamma*w(ix^d,p_)*inv_rho
3073 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3074 ! Va_hat^2+a_hat^2 equation (57)
3075 ! equation (69)
3076 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
3077 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
3078 if(avmincs2<zero) avmincs2=zero
3079 ! equation (68) fast magnetosonic wave speed
3080 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
3081 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
3082 {end do\}
3083
3084 end subroutine mhd_get_cmax_semirelati
3085
3086 !> Calculate cmax_idim for semirelativistic MHD
3087 subroutine mhd_get_cmax_semirelati_noe(w,x,ixI^L,ixO^L,idim,cmax)
3090
3091 integer, intent(in) :: ixi^l, ixo^l, idim
3092 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3093 double precision, intent(inout):: cmax(ixi^s)
3094
3095 double precision :: adiabs(ixi^s), gammas(ixi^s)
3096 double precision :: csound, avmincs2, idim_alfven_speed2
3097 double precision :: inv_rho, alfven_speed2, gamma2
3098 integer :: ix^d
3099
3100 if(associated(usr_set_adiab)) then
3101 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3102 else
3103 adiabs=mhd_adiab
3104 end if
3105 if(associated(usr_set_gamma)) then
3106 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3107 else
3108 gammas=eos%gamma
3109 end if
3110
3111 {do ix^db=ixomin^db,ixomax^db \}
3112 inv_rho=1.d0/w(ix^d,rho_)
3113 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3114 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3115 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
3116 csound=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3117 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3118 ! Va_hat^2+a_hat^2 equation (57)
3119 ! equation (69)
3120 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
3121 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
3122 if(avmincs2<zero) avmincs2=zero
3123 ! equation (68) fast magnetosonic wave speed
3124 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
3125 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
3126 {end do\}
3127
3128 end subroutine mhd_get_cmax_semirelati_noe
3129
3130 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
3131 subroutine mhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
3133 use mod_geometry
3136 integer, intent(in) :: ixi^l,ixo^l
3137 double precision, intent(in) :: x(ixi^s,1:ndim)
3138 ! in primitive form
3139 double precision, intent(inout) :: w(ixi^s,1:nw)
3140 double precision, intent(out) :: tco_local,tmax_local
3141
3142 double precision, parameter :: trac_delta=0.25d0
3143 double precision :: te(ixi^s),lts(ixi^s)
3144 double precision, dimension(1:ndim) :: bdir, bunitvec
3145 double precision, dimension(ixI^S,1:ndim) :: gradt
3146 double precision :: ltrc,ltrp,altr
3147 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
3148 integer :: jxp^l,hxp^l,ixp^l,ixq^l
3149 ! TRAC-7 (Johnston et al. 2021, A&A 654 A2) field-aligned local method
3150 double precision :: q_heat(ixi^s), ne(ixi^s), nh_arr(ixi^s)
3151 double precision :: bvec(1:ndir)
3152 double precision :: bmin_c, bmag, gnorm, bgtd, l_t, dl_eff, vmag, bdotv, binp2
3153 double precision :: v_n, a_coeff, l1, cooling, net_cool
3154 double precision :: kappa_par, disc, dx_over_delta, kappa_trac, kappa_eff, tcoff_eff
3155
3156 if (eos%eos_type == 'LTE' .or. eos%eos_type == 'PI') then
3157 te(ixi^s) = w(ixi^s, te_)
3158 else
3159 call eos%get_Rfactor(w,x,ixi^l,ixi^l,te)
3160 te(ixi^s)=w(ixi^s,p_)/(te(ixi^s)*w(ixi^s,rho_))
3161 end if
3162 tco_local=zero
3163 tmax_local=maxval(te(ixo^s))
3164
3165 {^ifoned
3166 select case(mhd_trac_type)
3167 case(0)
3168 !> test case, fixed cutoff temperature
3169 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
3170 case(1)
3171 do ix1=ixomin1,ixomax1
3172 lts(ix1)=0.5d0*abs(te(ix1+1)-te(ix1-1))/te(ix1)
3173 if(lts(ix1)>trac_delta) then
3174 tco_local=max(tco_local,te(ix1))
3175 end if
3176 end do
3177 case(2)
3178 !> iijima et al. 2021, LTRAC method
3179 ltrc=1.5d0
3180 ltrp=4.d0
3181 ixp^l=ixo^l^ladd1;
3182 hxo^l=ixo^l-1;
3183 jxo^l=ixo^l+1;
3184 hxp^l=ixp^l-1;
3185 jxp^l=ixp^l+1;
3186 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
3187 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
3188 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
3189 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
3190 case default
3191 call mpistop("mhd_trac_type not allowed for 1D simulation")
3192 end select
3193 }
3194 {^nooned
3195 select case(mhd_trac_type)
3196 case(0)
3197 !> test case, fixed cutoff temperature
3198 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
3199 case(1,4,6)
3200 ! temperature gradient at cell centers
3201 do idims=1,ndim
3202 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
3203 end do
3204 if(mhd_trac_type .gt. 1) then
3205 ! B direction at block center
3206 bdir=zero
3207 if(b0field) then
3208 {do ixa^d=0,1\}
3209 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3210 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))+block%B0(ixb^d,1:ndim,0)
3211 {end do\}
3212 else
3213 {do ixa^d=0,1\}
3214 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3215 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))
3216 {end do\}
3217 end if
3218 {^iftwod
3219 if(bdir(1)/=0.d0) then
3220 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3221 else
3222 block%special_values(3)=0.d0
3223 end if
3224 if(bdir(2)/=0.d0) then
3225 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3226 else
3227 block%special_values(4)=0.d0
3228 end if
3229 }
3230 {^ifthreed
3231 if(bdir(1)/=0.d0) then
3232 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+&
3233 (bdir(3)/bdir(1))**2)
3234 else
3235 block%special_values(3)=0.d0
3236 end if
3237 if(bdir(2)/=0.d0) then
3238 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+&
3239 (bdir(3)/bdir(2))**2)
3240 else
3241 block%special_values(4)=0.d0
3242 end if
3243 if(bdir(3)/=0.d0) then
3244 block%special_values(5)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+&
3245 (bdir(2)/bdir(3))**2)
3246 else
3247 block%special_values(5)=0.d0
3248 end if
3249 }
3250 end if
3251 ! b unit vector: magnetic field direction vector
3252 block%special_values(1)=zero
3253 {do ix^db=ixomin^db,ixomax^db\}
3254 if(b0field) then
3255 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3256 else
3257 ^d&bdir(^d)=w({ix^d},iw_mag(^d))\
3258 end if
3259 {^iftwod
3260 if(bdir(1)/=0.d0) then
3261 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3262 else
3263 bunitvec(1)=0.d0
3264 end if
3265 if(bdir(2)/=0.d0) then
3266 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3267 else
3268 bunitvec(2)=0.d0
3269 end if
3270 ! temperature length scale inversed
3271 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
3272 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3273 }
3274 {^ifthreed
3275 if(bdir(1)/=0.d0) then
3276 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3277 else
3278 bunitvec(1)=0.d0
3279 end if
3280 if(bdir(2)/=0.d0) then
3281 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3282 else
3283 bunitvec(2)=0.d0
3284 end if
3285 if(bdir(3)/=0.d0) then
3286 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3287 else
3288 bunitvec(3)=0.d0
3289 end if
3290 ! temperature length scale inversed
3291 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
3292 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3293 }
3294 if(lts(ix^d)>trac_delta) then
3295 block%special_values(1)=max(block%special_values(1),te(ix^d))
3296 end if
3297 {end do\}
3298 block%special_values(2)=tmax_local
3299 case(2)
3300 !> iijima et al. 2021, LTRAC method
3301 ltrc=1.5d0
3302 ltrp=4.d0
3303 ixp^l=ixo^l^ladd2;
3304 ! temperature gradient at cell centers
3305 do idims=1,ndim
3306 ixq^l=ixp^l;
3307 hxp^l=ixp^l;
3308 jxp^l=ixp^l;
3309 select case(idims)
3310 {case(^d)
3311 ixqmin^d=ixqmin^d+1
3312 ixqmax^d=ixqmax^d-1
3313 hxpmax^d=ixpmin^d
3314 jxpmin^d=ixpmax^d
3315 \}
3316 end select
3317 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
3318 ! The outermost ghost cell has no room for a fourth-order one-sided
3319 ! stencil. A first-order one-sided gradient keeps the two-ghost-layer
3320 ! LTRAC coverage without reading outside ixI.
3321 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),1,.true.)
3322 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),1,.false.)
3323 end do
3324 ! b unit vector: magnetic field direction vector
3325 if(b0field) then
3326 {do ix^db=ixpmin^db,ixpmax^db\}
3327 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3328 {^iftwod
3329 if(bdir(1)/=0.d0) then
3330 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3331 else
3332 bunitvec(1)=0.d0
3333 end if
3334 if(bdir(2)/=0.d0) then
3335 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3336 else
3337 bunitvec(2)=0.d0
3338 end if
3339 }
3340 {^ifthreed
3341 if(bdir(1)/=0.d0) then
3342 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3343 else
3344 bunitvec(1)=0.d0
3345 end if
3346 if(bdir(2)/=0.d0) then
3347 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3348 else
3349 bunitvec(2)=0.d0
3350 end if
3351 if(bdir(3)/=0.d0) then
3352 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3353 else
3354 bunitvec(3)=0.d0
3355 end if
3356 }
3357 ! temperature length scale inversed
3358 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3359 ! fraction of cells size to temperature length scale
3360 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3361 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3362 {end do\}
3363 else
3364 {do ix^db=ixpmin^db,ixpmax^db\}
3365 {^iftwod
3366 if(w(ix^d,iw_mag(1))/=0.d0) then
3367 bunitvec(1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2)
3368 else
3369 bunitvec(1)=0.d0
3370 end if
3371 if(w(ix^d,iw_mag(2))/=0.d0) then
3372 bunitvec(2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2)
3373 else
3374 bunitvec(2)=0.d0
3375 end if
3376 }
3377 {^ifthreed
3378 if(w(ix^d,iw_mag(1))/=0.d0) then
3379 bunitvec(1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2+&
3380 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
3381 else
3382 bunitvec(1)=0.d0
3383 end if
3384 if(w(ix^d,iw_mag(2))/=0.d0) then
3385 bunitvec(2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2+&
3386 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
3387 else
3388 bunitvec(2)=0.d0
3389 end if
3390 if(w(ix^d,iw_mag(3))/=0.d0) then
3391 bunitvec(3)=sign(1.d0,w(ix^d,iw_mag(3)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(3)))**2+&
3392 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
3393 else
3394 bunitvec(3)=0.d0
3395 end if
3396 }
3397 ! temperature length scale inversed
3398 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3399 ! fraction of cells size to temperature length scale
3400 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3401 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3402 {end do\}
3403 end if
3404
3405 ! need one ghost layer for thermal conductivity
3406 ixp^l=ixo^l^ladd1;
3407 {do ix^db=ixpmin^db,ixpmax^db\}
3408 {^iftwod
3409 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*bunitvec(1)**2+&
3410 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*bunitvec(2)**2)
3411 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3412 }
3413 {^ifthreed
3414 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*bunitvec(1)**2+&
3415 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*bunitvec(2)**2+&
3416 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*bunitvec(3)**2)
3417 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3418 }
3419 {end do\}
3420 case(7)
3421 ! Johnston et al. 2021 (A&A 654, A2) local field-aligned TRAC for MHD.
3422 ! Anisotropic conduction broadens the TR along B, so the length scale (Eq.18) and the
3423 ! enthalpy flux (Eq.16) are projected on the field, regularized by b_min=0.1 G (paper
3424 ! value) as B->0 or B perpendicular to grad T. Per-cell adaptive parallel conductivity from the
3425 ! steady-state balance (Eq.11/12) with the Eq.13 selection; general-EoS cooling n_e n_H L.
3426 ! (HD isotropic version used the grad-T direction; here it is the magnetic field.)
3427 call usr_get_heating(q_heat, ixi^l, ixo^l, w, x)
3428 call eos%get_ne_nH(ixi^l, ixo^l, w, x, ne, nh_arr)
3429 block%wextra(ixi^s,tcoff_) = te(ixi^s) ! default (incl. ghost layer): no broadening
3430 do idims=1,ndim
3431 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
3432 end do
3433 bmin_c = 0.1d0/unit_magneticfield ! 0.1 G in code units
3434 {do ix^db=ixomin^db,ixomax^db\}
3435 ! full field B-magnitude (Eq.18 numerator, regularized), and B.v, v-magnitude over ndir
3436 bmag=bmin_c**2; bdotv=0.d0; vmag=0.d0
3437 do idims=1,ndir
3438 bvec(idims)=w(ix^d,iw_mag(idims))
3439 if(b0field) bvec(idims)=bvec(idims)+block%B0(ix^d,idims,0)
3440 bmag =bmag +bvec(idims)**2
3441 bdotv=bdotv+bvec(idims)*w(ix^d,mom(idims))
3442 vmag =vmag +w(ix^d,mom(idims))**2
3443 end do
3444 bmag=dsqrt(bmag); vmag=dsqrt(vmag)
3445 ! in-plane grad-T norm, in-plane field^2, and in-plane B.grad T (grad T has no z-part in 2D)
3446 gnorm=0.d0; binp2=0.d0; bgtd=0.d0
3447 do idims=1,ndim
3448 gnorm=gnorm+gradt(ix^d,idims)**2
3449 binp2=binp2+bvec(idims)**2
3450 bgtd =bgtd +bvec(idims)*gradt(ix^d,idims)
3451 end do
3452 gnorm=dsqrt(gnorm)
3453 if(gnorm<smalldouble .or. binp2<smalldouble) then
3454 block%wextra(ix^d,tcoff_)=te(ix^d) ! uniform T or no in-plane field: no TR
3455 else
3456 ! Eq.18 field-aligned length scale (dabs: conduction is bidirectional along B)
3457 l_t=te(ix^d)*bmag/(dabs(bgtd)+bmin_c*gnorm)
3458 ! grid spacing along the (in-plane) field direction b = Bvec/Bmag
3459 dl_eff=0.d0
3460 do idims=1,ndim
3461 dl_eff=dl_eff+(bvec(idims)/block%ds(ix^d,idims))**2
3462 end do
3463 dl_eff=bmag/dsqrt(dl_eff)
3464 ! Eq.16 field-aligned enthalpy (mass) flux
3465 v_n=(dabs(bdotv)+bmin_c*vmag)/bmag
3466 a_coeff=2.5d0*w(ix^d,p_)*v_n/te(ix^d)
3467 ! optically-thin cooling n_e n_H Lambda(T), guarded to the table range (positive
3468 ! in-range test so a non-finite Te falls to zero rather than indexing findL with NaN)
3469 if(te(ix^d)>rc_fl%tcoolmin .and. te(ix^d)<rc_fl%tcoolmax) then
3470 call findl(te(ix^d),l1,rc_fl); cooling=l1*ne(ix^d)*nh_arr(ix^d)
3471 else if(te(ix^d)>=rc_fl%tcoolmax) then
3472 call calc_l_extended(te(ix^d),l1,rc_fl); cooling=l1*ne(ix^d)*nh_arr(ix^d)
3473 else
3474 cooling=0.d0
3475 end if
3476 net_cool=dabs(cooling-q_heat(ix^d))
3477 kappa_par=tc_fl%tc_k_para*te(ix^d)**2.5d0
3478 disc=a_coeff**2+4.d0*tc_fl%tc_k_para*te(ix^d)**1.5d0*net_cool
3479 dx_over_delta=dl_eff/mhd_trac_delta
3480 ! Eq.13 selection: under-resolved (Eq.11, keep mass flux) vs over-resolved (Eq.12, limiter)
3481 if(l_t<=2.d0*dx_over_delta) then
3482 kappa_trac=(a_coeff+dsqrt(disc))/(2.d0/dx_over_delta)
3483 else
3484 kappa_trac=dsqrt(4.d0*tc_fl%tc_k_para*te(ix^d)**1.5d0*net_cool)/(2.d0/dx_over_delta)
3485 end if
3486 kappa_eff=max(kappa_trac,kappa_par)
3487 tcoff_eff=(kappa_eff/tc_fl%tc_k_para)**0.4d0
3488 block%wextra(ix^d,tcoff_)=max(te(ix^d),tcoff_eff)
3489 end if
3490 {end do\}
3491 case(3,5)
3492 !> do nothing here
3493 case default
3494 call mpistop("unknown mhd_trac_type")
3495 end select
3496 }
3497 end subroutine mhd_get_tcutoff
3498
3499 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
3500 subroutine mhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
3502
3503 integer, intent(in) :: ixi^l, ixo^l, idim
3504 double precision, intent(in) :: wprim(ixi^s, nw)
3505 double precision, intent(in) :: x(ixi^s,1:ndim)
3506 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
3507
3508 double precision :: csound(ixi^s,ndim)
3509 double precision, allocatable :: tmp(:^d&)
3510 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
3511
3512 hspeed=0.d0
3513 ixa^l=ixo^l^ladd1;
3514 allocate(tmp(ixa^s))
3515 do id=1,ndim
3516 if(has_equi_rho_and_p) then
3517 call mhd_get_csound_prim_split(wprim,x,ixi^l,ixa^l,id,tmp)
3518 else
3519 call mhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
3520 endif
3521 csound(ixa^s,id)=tmp(ixa^s)
3522 end do
3523 ixcmax^d=ixomax^d;
3524 ixcmin^d=ixomin^d+kr(idim,^d)-1;
3525 jxcmax^d=ixcmax^d+kr(idim,^d);
3526 jxcmin^d=ixcmin^d+kr(idim,^d);
3527 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))
3528
3529 do id=1,ndim
3530 if(id==idim) cycle
3531 ixamax^d=ixcmax^d+kr(id,^d);
3532 ixamin^d=ixcmin^d+kr(id,^d);
3533 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)))
3534 ixamax^d=ixcmax^d-kr(id,^d);
3535 ixamin^d=ixcmin^d-kr(id,^d);
3536 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)))
3537 end do
3538
3539 do id=1,ndim
3540 if(id==idim) cycle
3541 ixamax^d=jxcmax^d+kr(id,^d);
3542 ixamin^d=jxcmin^d+kr(id,^d);
3543 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)))
3544 ixamax^d=jxcmax^d-kr(id,^d);
3545 ixamin^d=jxcmin^d-kr(id,^d);
3546 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)))
3547 end do
3548 deallocate(tmp)
3549
3550 end subroutine mhd_get_h_speed
3551
3552 !> Estimating bounds for the minimum and maximum signal velocities without split
3553 subroutine mhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3555 !!use mod_fld, only: fld_bound_diff, fld_get_local_invtauc
3556
3557 integer, intent(in) :: ixi^l, ixo^l, idim
3558 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3559 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3560 double precision, intent(in) :: x(ixi^s,1:ndim)
3561 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3562 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3563 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3564
3565 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3566 !!double precision :: invtaucL(ixI^S),invtaucR(ixI^S),invtauc
3567 double precision :: umean, dmean, tmp1, tmp2, tmp3
3568 integer :: ix^d
3569
3570 select case (boundspeed)
3571 case (1)
3572 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3573 ! Methods for Fluid Dynamics" by Toro.
3574 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3575 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3576 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3577 !! call fld_get_local_invtauc(wLp,ixI^L,ixO^L,{dxlevel(^D)},x,invtaucL,fld_fl)
3578 !! call fld_get_local_invtauc(wRp,ixI^L,ixO^L,{dxlevel(^D)},x,invtaucR,fld_fl)
3579 !!endif
3580 if(present(cmin)) then
3581 {do ix^db=ixomin^db,ixomax^db\}
3582 tmp1=sqrt(wlp(ix^d,rho_))
3583 tmp2=sqrt(wrp(ix^d,rho_))
3584 tmp3=1.d0/(tmp1+tmp2)
3585 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3586 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3587 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3588 cmin(ix^d,1)=umean-dmean
3589 cmax(ix^d,1)=umean+dmean
3590 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3591 !! invtauc=min(invtaucL(ix^D),invtaucR(ix^D))
3592 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3593 !! cmin(ix^D,1)=max(cmin(ix^D,1),-invtauc)
3594 !!endif
3595 {end do\}
3596 if(h_correction) then
3597 {do ix^db=ixomin^db,ixomax^db\}
3598 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3599 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3600 {end do\}
3601 end if
3602 else
3603 {do ix^db=ixomin^db,ixomax^db\}
3604 tmp1=sqrt(wlp(ix^d,rho_))
3605 tmp2=sqrt(wrp(ix^d,rho_))
3606 tmp3=1.d0/(tmp1+tmp2)
3607 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3608 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3609 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3610 cmax(ix^d,1)=abs(umean)+dmean
3611 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3612 !! invtauc=min(invtaucL(ix^D),invtaucR(ix^D))
3613 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3614 !!endif
3615 {end do\}
3616 end if
3617 case (2)
3618 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3619 call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
3620 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3621 !! call fld_get_local_invtauc(wmean,ixI^L,ixO^L,{dxlevel(^D)},x,invtaucL,fld_fl)
3622 !!endif
3623 if(present(cmin)) then
3624 {do ix^db=ixomin^db,ixomax^db\}
3625 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3626 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3627 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3628 !! invtauc=invtaucL(ix^D)
3629 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3630 !! cmin(ix^D,1)=max(cmin(ix^D,1),-invtauc)
3631 !!endif
3632 {end do\}
3633 if(h_correction) then
3634 {do ix^db=ixomin^db,ixomax^db\}
3635 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3636 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3637 {end do\}
3638 end if
3639 else
3640 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3641 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3642 !! invtauc=invtaucL(ix^D)
3643 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3644 !!endif
3645 end if
3646 case (3)
3647 ! Miyoshi 2005 JCP 208, 315 equation (67)
3648 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3649 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3650 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3651 !! call fld_get_local_invtauc(wLp,ixI^L,ixO^L,{dxlevel(^D)},x,invtaucL,fld_fl)
3652 !! call fld_get_local_invtauc(wRp,ixI^L,ixO^L,{dxlevel(^D)},x,invtaucR,fld_fl)
3653 !!endif
3654 if(present(cmin)) then
3655 {do ix^db=ixomin^db,ixomax^db\}
3656 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3657 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3658 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3659 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3660 !! invtauc=min(invtaucL(ix^D),invtaucR(ix^D))
3661 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3662 !! cmin(ix^D,1)=max(cmin(ix^D,1),-invtauc)
3663 !!endif
3664 {end do\}
3665 if(h_correction) then
3666 {do ix^db=ixomin^db,ixomax^db\}
3667 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3668 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3669 {end do\}
3670 end if
3671 else
3672 {do ix^db=ixomin^db,ixomax^db\}
3673 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3674 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3675 !!if(mhd_radiation_fld.and.fld_bound_diff)then
3676 !! invtauc=min(invtaucL(ix^D),invtaucR(ix^D))
3677 !! cmax(ix^D,1)=min(cmax(ix^D,1),+invtauc)
3678 !!endif
3679 {end do\}
3680 end if
3681 end select
3682
3683 end subroutine mhd_get_cbounds
3684
3685 !> Estimating bounds for the minimum and maximum signal velocities without split
3686 subroutine mhd_get_cbounds_semirelati(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3688
3689 integer, intent(in) :: ixi^l, ixo^l, idim
3690 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3691 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3692 double precision, intent(in) :: x(ixi^s,1:ndim)
3693 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3694 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3695 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3696
3697 double precision, dimension(ixO^S) :: csoundl, csoundr, gamma2l, gamma2r
3698 integer :: ix^d
3699
3700 ! Miyoshi 2005 JCP 208, 315 equation (67)
3701 if(mhd_energy) then
3702 call mhd_get_csound_semirelati(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3703 call mhd_get_csound_semirelati(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3704 else
3705 call mhd_get_csound_semirelati_noe(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3706 call mhd_get_csound_semirelati_noe(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3707 end if
3708 if(present(cmin)) then
3709 {do ix^db=ixomin^db,ixomax^db\}
3710 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3711 cmin(ix^d,1)=min(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))-csoundl(ix^d)
3712 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3713 {end do\}
3714 else
3715 {do ix^db=ixomin^db,ixomax^db\}
3716 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3717 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3718 {end do\}
3719 end if
3720
3721 end subroutine mhd_get_cbounds_semirelati
3722
3723 !> Estimating bounds for the minimum and maximum signal velocities with rho split
3724 subroutine mhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3726
3727 integer, intent(in) :: ixi^l, ixo^l, idim
3728 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3729 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3730 double precision, intent(in) :: x(ixi^s,1:ndim)
3731 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3732 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3733 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3734
3735 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3736 double precision :: umean, dmean, tmp1, tmp2, tmp3
3737 integer :: ix^d
3738
3739 select case (boundspeed)
3740 case (1)
3741 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3742 ! Methods for Fluid Dynamics" by Toro.
3743 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3744 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3745 if(present(cmin)) then
3746 {do ix^db=ixomin^db,ixomax^db\}
3747 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3748 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3749 tmp3=1.d0/(tmp1+tmp2)
3750 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3751 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3752 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3753 cmin(ix^d,1)=umean-dmean
3754 cmax(ix^d,1)=umean+dmean
3755 {end do\}
3756 if(h_correction) then
3757 {do ix^db=ixomin^db,ixomax^db\}
3758 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3759 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3760 {end do\}
3761 end if
3762 else
3763 {do ix^db=ixomin^db,ixomax^db\}
3764 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3765 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3766 tmp3=1.d0/(tmp1+tmp2)
3767 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3768 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3769 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3770 cmax(ix^d,1)=abs(umean)+dmean
3771 {end do\}
3772 end if
3773 case (2)
3774 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3775 call mhd_get_csound_prim_split(wmean,x,ixi^l,ixo^l,idim,csoundr)
3776 if(present(cmin)) then
3777 {do ix^db=ixomin^db,ixomax^db\}
3778 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3779 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3780 {end do\}
3781 if(h_correction) then
3782 {do ix^db=ixomin^db,ixomax^db\}
3783 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3784 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3785 {end do\}
3786 end if
3787 else
3788 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3789 end if
3790 case (3)
3791 ! Miyoshi 2005 JCP 208, 315 equation (67)
3792 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3793 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3794 if(present(cmin)) then
3795 {do ix^db=ixomin^db,ixomax^db\}
3796 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3797 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3798 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3799 {end do\}
3800 if(h_correction) then
3801 {do ix^db=ixomin^db,ixomax^db\}
3802 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3803 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3804 {end do\}
3805 end if
3806 else
3807 {do ix^db=ixomin^db,ixomax^db\}
3808 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3809 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3810 {end do\}
3811 end if
3812 end select
3813
3814 end subroutine mhd_get_cbounds_split_rho
3815
3816 !> prepare velocities for ct methods
3817 subroutine mhd_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3819
3820 integer, intent(in) :: ixi^l, ixo^l, idim
3821 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3822 double precision, intent(in) :: cmax(ixi^s)
3823 double precision, intent(in), optional :: cmin(ixi^s)
3824 type(ct_velocity), intent(inout):: vcts
3825
3826 end subroutine mhd_get_ct_velocity_average
3827
3828 subroutine mhd_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3830
3831 integer, intent(in) :: ixi^l, ixo^l, idim
3832 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3833 double precision, intent(in) :: cmax(ixi^s)
3834 double precision, intent(in), optional :: cmin(ixi^s)
3835 type(ct_velocity), intent(inout):: vcts
3836
3837 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
3838 ! get average normal velocity at cell faces
3839 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
3840
3841 end subroutine mhd_get_ct_velocity_contact
3842
3843 subroutine mhd_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3845
3846 integer, intent(in) :: ixi^l, ixo^l, idim
3847 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3848 double precision, intent(in) :: cmax(ixi^s)
3849 double precision, intent(in), optional :: cmin(ixi^s)
3850 type(ct_velocity), intent(inout):: vcts
3851
3852 integer :: idime,idimn
3853
3854 if(.not.allocated(vcts%vbarC)) then
3855 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
3856 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
3857 end if
3858 ! Store magnitude of characteristics
3859 if(present(cmin)) then
3860 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
3861 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3862 else
3863 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3864 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
3865 end if
3866
3867 idimn=mod(idim,ndir)+1 ! 'Next' direction
3868 idime=mod(idim+1,ndir)+1 ! Electric field direction
3869 ! Store velocities
3870 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
3871 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
3872 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
3873 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3874 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3875
3876 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
3877 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
3878 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
3879 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,2))&
3880 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3881
3882 end subroutine mhd_get_ct_velocity_hll
3883
3884 !> Calculate modified squared sound speed for FLD
3885 !> NOTE: only for diagnostic purposes, unused subroutine
3886 subroutine mhd_get_csrad2(w,x,ixI^L,ixO^L,csound)
3888
3889 integer, intent(in) :: ixi^l, ixo^l
3890 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3891 double precision, intent(out):: csound(ixi^s)
3892
3893 double precision :: wprim(ixi^s, nw)
3894
3895 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
3896 call eos%to_primitive(ixi^l,ixo^l,wprim,x)
3897 call mhd_get_csrad2_prim(wprim,x,ixi^l,ixo^l,csound)
3898
3899 end subroutine mhd_get_csrad2
3900
3901
3902 !> Calculate modified squared fast wave speed for FLD
3903 !> NOTE: w is primitive on entry here!
3904 !> NOTE: used in FLD module as phys_get_csrad2
3905 subroutine mhd_get_csrad2_prim(w,x,ixI^L,ixO^L,csound)
3907
3908 integer, intent(in) :: ixi^l, ixo^l
3909 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3910 double precision, intent(out):: csound(ixi^s)
3911
3912 double precision :: inv_rho, b2
3913 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
3914 double precision :: prad_max(ixi^s)
3915 integer :: ix^d,idim
3916
3917 if(mhd_fld_pradtensor) then
3918 call mhd_get_pradiation_from_prim(w, x, ixi^l, ixo^l, prad_tensor)
3919 else
3920 prad_tensor=zero
3921 do idim=1,ndim
3922 prad_tensor(ixo^s,idim,idim)=w(ixo^s,r_e)/3.0d0
3923 enddo
3924 endif
3925
3926 if(b0field) then
3927 {do ix^db=ixomin^db,ixomax^db \}
3928 inv_rho=1.d0/w(ix^d,rho_)
3929 prad_max(ix^d) = (4.0d0/3.0d0)*maxval(prad_tensor(ix^d,:,:))
3930 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3931 csound(ix^d)=(eos%gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3932 {end do\}
3933 else
3934 {do ix^db=ixomin^db,ixomax^db \}
3935 inv_rho=1.d0/w(ix^d,rho_)
3936 prad_max(ix^d) = (4.0d0/3.0d0)*maxval(prad_tensor(ix^d,:,:))
3937 b2=(^c&w(ix^d,b^c_)**2+)
3938 csound(ix^d)=(eos%gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3939 {end do\}
3940 end if
3941
3942 if(minval(csound(ixo^s))<smalldouble)then
3943 print *,'issue with squared speed and rad pressure'
3944 print *,minval(csound(ixo^s))
3945 print *,minval(prad_max(ixo^s))
3946 call mpistop("negative squared speed in get_csrad2 for dt")
3947 endif
3948
3949 end subroutine mhd_get_csrad2_prim
3950
3951 !> Calculate fast magnetosonic wave speed
3952 subroutine mhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
3955 use mod_fld, only: fld_bound_diff
3956
3957 integer, intent(in) :: ixi^l, ixo^l, idim
3958 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3959 double precision, intent(out):: csound(ixo^s)
3960
3961 double precision :: adiabs(ixi^s), gammas(ixi^s)
3962 double precision :: inv_rho, cfast2, avmincs2, b2, kmax
3963 double precision :: cs2(ixi^s)
3964 integer :: ix^d
3965
3966 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3967
3968 if(.not.mhd_energy) then
3969 if(associated(usr_set_adiab)) then
3970 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3971 else
3972 adiabs=mhd_adiab
3973 end if
3974 if(associated(usr_set_gamma)) then
3975 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3976 else
3977 gammas=eos%gamma
3978 end if
3979 end if
3980
3981 ! Sound speed squared via EoS dispatch (honours LTE+ionE Gamma_1 table).
3982 if(mhd_energy) then
3983 call eos%get_csound2(w, x, ixi^l, ixo^l, cs2)
3984 end if
3985
3986 ! store |B|^2 in v
3987 if(b0field) then
3988 {do ix^db=ixomin^db,ixomax^db \}
3989 inv_rho=1.d0/w(ix^d,rho_)
3990 if(mhd_energy) then
3991 csound(ix^d)=cs2(ix^d)
3992 if(mhd_radiation_fld.and.fld_bound_diff)csound(ix^d)=cs2(ix^d)+4.0d0*w(ix^d,r_e)*inv_rho/9.0d0
3993 else
3994 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3995 end if
3996 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3997 cfast2=b2*inv_rho+csound(ix^d)
3998 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3999 block%B0(ix^d,idim,b0i))**2*inv_rho
4000 if(avmincs2<zero) avmincs2=zero
4001 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
4002 if(mhd_hall) then
4003 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
4004 end if
4005 {end do\}
4006 else
4007 {do ix^db=ixomin^db,ixomax^db \}
4008 inv_rho=1.d0/w(ix^d,rho_)
4009 if(mhd_energy) then
4010 csound(ix^d)=cs2(ix^d)
4011 if(mhd_radiation_fld.and.fld_bound_diff)csound(ix^d)=cs2(ix^d)+4.0d0*w(ix^d,r_e)*inv_rho/9.0d0
4012 else
4013 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
4014 end if
4015 b2=(^c&w(ix^d,b^c_)**2+)
4016 cfast2=b2*inv_rho+csound(ix^d)
4017 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
4018 if(avmincs2<zero) avmincs2=zero
4019 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
4020 if(mhd_hall) then
4021 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
4022 end if
4023 {end do\}
4024 end if
4025
4026 end subroutine mhd_get_csound_prim
4027
4028 !> Calculate fast magnetosonic wave speed when rho and p are split
4029 !> hence has_equi_rho_and_p=T
4030 subroutine mhd_get_csound_prim_split(w,x,ixI^L,ixO^L,idim,csound)
4032
4033 integer, intent(in) :: ixi^l, ixo^l, idim
4034 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
4035 double precision, intent(out):: csound(ixo^s)
4036
4037 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
4038 integer :: ix^d
4039
4040 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
4041
4042 ! store |B|^2 in v
4043 if(b0field) then
4044 {do ix^db=ixomin^db,ixomax^db \}
4045 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
4046 inv_rho=1.d0/rho
4047 csound(ix^d)=eos%gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
4048 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
4049 cfast2=b2*inv_rho+csound(ix^d)
4050 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
4051 block%B0(ix^d,idim,b0i))**2*inv_rho
4052 if(avmincs2<zero) avmincs2=zero
4053 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
4054 if(mhd_hall) then
4055 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
4056 end if
4057 {end do\}
4058 else
4059 {do ix^db=ixomin^db,ixomax^db \}
4060 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
4061 inv_rho=1.d0/rho
4062 csound(ix^d)=eos%gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
4063 b2=(^c&w(ix^d,b^c_)**2+)
4064 cfast2=b2*inv_rho+csound(ix^d)
4065 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
4066 if(avmincs2<zero) avmincs2=zero
4067 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
4068 if(mhd_hall) then
4069 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
4070 end if
4071 {end do\}
4072 end if
4073
4074 end subroutine mhd_get_csound_prim_split
4075
4076 !> Calculate cmax_idim for semirelativistic MHD
4077 subroutine mhd_get_csound_semirelati(w,x,ixI^L,ixO^L,idim,csound,gamma2)
4079
4080 integer, intent(in) :: ixi^l, ixo^l, idim
4081 ! here w is primitive variables
4082 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
4083 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
4084
4085 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
4086 integer :: ix^d
4087
4088 {do ix^db=ixomin^db,ixomax^db\}
4089 inv_rho = 1.d0/w(ix^d,rho_)
4090 ! squared sound speed
4091 csound(ix^d)=eos%gamma*w(ix^d,p_)*inv_rho
4092 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
4093 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
4094 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
4095 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
4096 ! Va_hat^2+a_hat^2 equation (57)
4097 ! equation (69)
4098 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
4099 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
4100 if(avmincs2<zero) avmincs2=zero
4101 ! equation (68) fast magnetosonic speed
4102 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
4103 {end do\}
4104
4105 end subroutine mhd_get_csound_semirelati
4106
4107 !> Calculate cmax_idim for semirelativistic MHD
4108 subroutine mhd_get_csound_semirelati_noe(w,x,ixI^L,ixO^L,idim,csound,gamma2)
4111
4112 integer, intent(in) :: ixi^l, ixo^l, idim
4113 ! here w is primitive variables
4114 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
4115 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
4116
4117 double precision :: adiabs(ixi^s), gammas(ixi^s)
4118 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
4119 integer :: ix^d
4120
4121 if(associated(usr_set_adiab)) then
4122 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4123 else
4124 adiabs=mhd_adiab
4125 end if
4126 if(associated(usr_set_gamma)) then
4127 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4128 else
4129 gammas=eos%gamma
4130 end if
4131 {do ix^db=ixomin^db,ixomax^db\}
4132 inv_rho = 1.d0/w(ix^d,rho_)
4133 ! squared sound speed
4134 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
4135 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
4136 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
4137 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
4138 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
4139 ! Va_hat^2+a_hat^2 equation (57)
4140 ! equation (69)
4141 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
4142 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
4143 if(avmincs2<zero) avmincs2=zero
4144 ! equation (68) fast magnetosonic speed
4145 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
4146 {end do\}
4147
4148 end subroutine mhd_get_csound_semirelati_noe
4149
4150 ! Thermal pressure and temperature subroutines (mhd_get_pthermal_noe,
4151 ! _inte, _origin, _semirelati, _hde, _LTE, mhd_get_temperature_from_eint,
4152 ! _from_etot, _from_etot_LTE, _with_equi, _equi, mhd_get_rho_equi,
4153 ! mhd_get_pe_equi) are defined in mod_mhd_eos.t. eos%get_temperature_from_{etot,eint}
4154 ! and tc_fl / rc_fl / te_fl_mhd hooks are bound by bind_eos_to_source.
4155
4156
4157 !> Calculate radiation pressure within ixO^L
4158 subroutine mhd_get_pradiation_from_prim(w, x, ixI^L, ixO^L, prad)
4160 use mod_fld
4161 integer, intent(in) :: ixi^l, ixo^l
4162 double precision, intent(in) :: w(ixi^s, 1:nw)
4163 double precision, intent(in) :: x(ixi^s, 1:ndim)
4164 double precision, intent(out):: prad(ixi^s, 1:ndim, 1:ndim)
4165
4166 call fld_get_radpress(w, x, ixi^l, ixo^l, prad, fld_fl)
4167
4168 end subroutine mhd_get_pradiation_from_prim
4169
4170 !> Calculates the sum of the gas pressure and the max Prad tensor element
4171 subroutine mhd_get_pthermal_plus_pradiation(w, x, ixI^L, ixO^L, pth_plus_prad)
4173 integer, intent(in) :: ixi^l, ixo^l
4174 double precision, intent(in) :: w(ixi^s, 1:nw)
4175 double precision, intent(in) :: x(ixi^s, 1:ndim)
4176 double precision, intent(out) :: pth_plus_prad(ixi^s)
4177
4178 double precision :: wprim(ixi^s, 1:nw)
4179 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
4180 double precision :: prad_max(ixi^s)
4181 integer :: ix^d
4182
4183 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
4184 call eos%to_primitive(ixi^l,ixo^l,wprim,x)
4185 call mhd_get_pradiation_from_prim(wprim, x, ixi^l, ixo^l, prad_tensor)
4186 {do ix^d = ixomin^d,ixomax^d\}
4187 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
4188 {enddo\}
4189 pth_plus_prad(ixo^s) = wprim(ixo^s,p_) + prad_max(ixo^s)
4191
4192 !> Calculates radiation temperature
4193 subroutine mhd_get_trad(w, x, ixI^L, ixO^L, trad)
4195 use mod_constants
4196
4197 integer, intent(in) :: ixi^l, ixo^l
4198 double precision, intent(in) :: w(ixi^s, 1:nw)
4199 double precision, intent(in) :: x(ixi^s, 1:ndim)
4200 double precision, intent(out):: trad(ixi^s)
4201
4202 trad(ixi^s) = (w(ixi^s,r_e)/arad_norm)**(1.d0/4.d0)
4203
4204 end subroutine mhd_get_trad
4205
4206 !> Calculate fluxes within ixO^L without any splitting
4207 subroutine mhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
4209 use mod_geometry
4210
4211 integer, intent(in) :: ixi^l, ixo^l, idim
4212 ! conservative w
4213 double precision, intent(in) :: wc(ixi^s,nw)
4214 ! primitive w
4215 double precision, intent(in) :: w(ixi^s,nw)
4216 double precision, intent(in) :: x(ixi^s,1:ndim)
4217 double precision,intent(out) :: f(ixi^s,nwflux)
4218
4219 double precision :: vhall(ixi^s,1:ndir)
4220 double precision :: ptotal
4221 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4222 double precision :: bvec(ixi^s,1:ndir)
4223 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4224 double precision :: nperp(ixi^s,1:ndir)
4225 double precision :: uawsom_zeta(ixi^s), uawsom_radius(ixi^s)
4226 double precision :: uawsom_lperp(ixi^s), uawsom_denom
4227 double precision :: uawsom_pwave, uawsom_bi
4228 logical :: use_perp_flux
4229 integer :: iw, ix^d, idir
4230
4231 if(mhd_uawsom) call mhd_uawsom_get_coefficients(w,x,ixi^l,ixo^l,.true.,&
4232 uawsom_zeta,uawsom_radius,uawsom_lperp)
4233
4234 if(mhd_internal_e) then
4235 {do ix^db=ixomin^db,ixomax^db\}
4236 ! Get flux of density
4237 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4238 ! f_i[m_k]=v_i*m_k-b_k*b_i
4239 ^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_)\
4240 ! normal one includes total pressure
4241 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4242 ! Get flux of internal energy
4243 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4244 ! f_i[b_k]=v_i*b_k-v_k*b_i
4245 ^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_)\
4246 {end do\}
4247 else
4248 {do ix^db=ixomin^db,ixomax^db\}
4249 ! Get flux of density
4250 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4251 ! f_i[m_k]=v_i*m_k-b_k*b_i
4252 ^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_)\
4253 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4254 if(mhd_uawsom) then
4255 uawsom_pwave=mhd_uawsom_wave_pressure_cell(w(ix^d,:),uawsom_zeta(ix^d))
4256 ptotal=ptotal+uawsom_pwave
4257 end if
4258 ! normal one includes total pressure
4259 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4260 ! Get flux of total energy
4261 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4262 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4263 -w(ix^d,mag(idim))*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4264 if(mhd_uawsom) then
4265 uawsom_denom=dsqrt(w(ix^d,rho_)*(uawsom_zeta(ix^d)+one)/&
4266 (two*(one+mhd_uawsom_filling_factor*uawsom_zeta(ix^d)-&
4268 uawsom_bi=w(ix^d,mag(idim))
4269 f(ix^d,e_)=f(ix^d,e_)+uawsom_bi*(&
4270 (w(ix^d,waminus_)-w(ix^d,waplus_))/dsqrt(w(ix^d,rho_))+&
4271 (w(ix^d,wkminus_)-w(ix^d,wkplus_))/uawsom_denom)
4272 end if
4273 ! f_i[b_k]=v_i*b_k-v_k*b_i
4274 ^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_)\
4275 {end do\}
4276 end if
4277 if(mhd_hall) then
4278 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4279 {do ix^db=ixomin^db,ixomax^db\}
4280 if(total_energy) then
4281 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4282 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)**2+)&
4283 -w(ix^d,mag(idim))*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4284 end if
4285 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4286 ^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))\
4287 {end do\}
4288 end if
4289
4290 if(mhd_glm) then
4291 {do ix^db=ixomin^db,ixomax^db\}
4292 f(ix^d,mag(idim))=w(ix^d,psi_)
4293 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4294 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4295 {end do\}
4296 end if
4297
4298 if(mhd_radiation_fld) then
4299 {do ix^db=ixomin^db,ixomax^db\}
4300 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4301 {end do\}
4302 endif
4303
4304 if (mhd_fip) then
4305 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4306 end if
4307 if(mhd_uawsom) then
4308 {do ix^db=ixomin^db,ixomax^db\}
4309 uawsom_denom=dsqrt(w(ix^d,rho_)*(uawsom_zeta(ix^d)+one)/&
4310 (two*(one+mhd_uawsom_filling_factor*uawsom_zeta(ix^d)-&
4312 uawsom_bi=w(ix^d,mag(idim))
4313 f(ix^d,waplus_)=w(ix^d,waplus_)*(w(ix^d,mom(idim))-&
4314 uawsom_bi/dsqrt(w(ix^d,rho_)))
4315 f(ix^d,waminus_)=w(ix^d,waminus_)*(w(ix^d,mom(idim))+&
4316 uawsom_bi/dsqrt(w(ix^d,rho_)))
4317 f(ix^d,wkplus_)=w(ix^d,wkplus_)*(w(ix^d,mom(idim))-uawsom_bi/uawsom_denom)
4318 f(ix^d,wkminus_)=w(ix^d,wkminus_)*(w(ix^d,mom(idim))+uawsom_bi/uawsom_denom)
4319 {end do\}
4320 end if
4321 ! Get flux of tracer
4322 do iw=1,mhd_n_tracer
4323 {do ix^db=ixomin^db,ixomax^db\}
4324 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4325 {end do\}
4326 end do
4327
4328 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
4329 trim(mhd_hyperbolic_tc_perp_mode)/='off'
4330 if(use_perp_flux) then
4331 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4332 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
4333 if(has_equi_rho_and_p) then
4334 te(ixi^s)=(w(ixi^s,p_)+block%equi_vars(ixi^s,equi_pe0_,b0i)) / &
4335 (r(ixi^s)*rho_loc(ixi^s))
4336 else
4337 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4338 end if
4339 {do ix^db=ixomin^db,ixomax^db\}
4340 do idir=1,ndir
4341 bvec(ix^d,idir)=w(ix^d,mag(idir))
4342 end do
4343 {end do\}
4344 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4345 end if
4346
4347 if(mhd_hyperbolic_tc) then
4348 {do ix^db=ixomin^db,ixomax^db\}
4349 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
4350 f(ix^d,qpar_)=zero
4351 if(use_perp_flux) then
4352 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4353 f(ix^d,qperp_)=zero
4354 end if
4355 {end do\}
4356 end if
4357 end subroutine mhd_get_flux
4358
4359 !> Calculate fluxes within ixO^L for case without energy equation, hence without splitting
4360 !> and assuming polytropic closure
4361 subroutine mhd_get_flux_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4363 use mod_geometry
4365
4366 integer, intent(in) :: ixi^l, ixo^l, idim
4367 ! conservative w
4368 double precision, intent(in) :: wc(ixi^s,nw)
4369 ! primitive w
4370 double precision, intent(in) :: w(ixi^s,nw)
4371 double precision, intent(in) :: x(ixi^s,1:ndim)
4372 double precision,intent(out) :: f(ixi^s,nwflux)
4373
4374 double precision :: vhall(ixi^s,1:ndir)
4375 double precision :: adiabs(ixi^s), gammas(ixi^s)
4376 integer :: iw, ix^d
4377
4378 if(associated(usr_set_adiab)) then
4379 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4380 else
4381 adiabs=mhd_adiab
4382 end if
4383 if(associated(usr_set_gamma)) then
4384 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4385 else
4386 gammas=eos%gamma
4387 end if
4388 {do ix^db=ixomin^db,ixomax^db\}
4389 ! Get flux of density
4390 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4391 ! f_i[m_k]=v_i*m_k-b_k*b_i
4392 ^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_)\
4393 ! normal one includes total pressure
4394 f(ix^d,mom(idim))=f(ix^d,mom(idim))+adiabs(ix^d)*w(ix^d,rho_)**gammas(ix^d)+half*(^c&w(ix^d,b^c_)**2+)
4395 ! f_i[b_k]=v_i*b_k-v_k*b_i
4396 ^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_)\
4397 {end do\}
4398 if(mhd_hall) then
4399 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4400 {do ix^db=ixomin^db,ixomax^db\}
4401 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4402 ^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))\
4403 {end do\}
4404 end if
4405 if(mhd_glm) then
4406 {do ix^db=ixomin^db,ixomax^db\}
4407 f(ix^d,mag(idim))=w(ix^d,psi_)
4408 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4409 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4410 {end do\}
4411 end if
4412 if (mhd_fip) then
4413 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4414 end if
4415 ! Get flux of tracer
4416 do iw=1,mhd_n_tracer
4417 {do ix^db=ixomin^db,ixomax^db\}
4418 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4419 {end do\}
4420 end do
4421 end subroutine mhd_get_flux_noe
4422
4423 !> Calculate fluxes with hydrodynamic energy equation
4424 subroutine mhd_get_flux_hde(wC,w,x,ixI^L,ixO^L,idim,f)
4426 use mod_geometry
4427
4428 integer, intent(in) :: ixi^l, ixo^l, idim
4429 ! conservative w
4430 double precision, intent(in) :: wc(ixi^s,nw)
4431 ! primitive w
4432 double precision, intent(in) :: w(ixi^s,nw)
4433 double precision, intent(in) :: x(ixi^s,1:ndim)
4434 double precision,intent(out) :: f(ixi^s,nwflux)
4435
4436 double precision :: vhall(ixi^s,1:ndir)
4437 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4438 double precision :: bvec(ixi^s,1:ndir)
4439 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4440 double precision :: nperp(ixi^s,1:ndir)
4441 logical :: use_perp_flux
4442 integer :: iw, ix^d, idir
4443
4444 {do ix^db=ixomin^db,ixomax^db\}
4445 ! Get flux of density
4446 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4447 ! f_i[m_k]=v_i*m_k-b_k*b_i
4448 ^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_)\
4449 ! normal one includes total pressure
4450 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4451 ! Get flux of energy
4452 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+w(ix^d,p_))
4453 ! f_i[b_k]=v_i*b_k-v_k*b_i
4454 ^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_)\
4455 {end do\}
4456 if(mhd_hall) then
4457 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4458 {do ix^db=ixomin^db,ixomax^db\}
4459 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4460 ^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))\
4461 {end do\}
4462 end if
4463 if(mhd_glm) then
4464 {do ix^db=ixomin^db,ixomax^db\}
4465 f(ix^d,mag(idim))=w(ix^d,psi_)
4466 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4467 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4468 {end do\}
4469 end if
4470 if (mhd_fip) then
4471 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4472 end if
4473 ! Get flux of tracer
4474 do iw=1,mhd_n_tracer
4475 {do ix^db=ixomin^db,ixomax^db\}
4476 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4477 {end do\}
4478 end do
4479 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
4480 trim(mhd_hyperbolic_tc_perp_mode)/='off'
4481 if(use_perp_flux) then
4482 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4483 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
4484 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4485 {do ix^db=ixomin^db,ixomax^db\}
4486 do idir=1,ndir
4487 bvec(ix^d,idir)=w(ix^d,mag(idir))
4488 end do
4489 {end do\}
4490 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4491 end if
4492 if(mhd_hyperbolic_tc) then
4493 {do ix^db=ixomin^db,ixomax^db\}
4494 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
4495 f(ix^d,qpar_)=zero
4496 if(use_perp_flux) then
4497 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4498 f(ix^d,qperp_)=zero
4499 end if
4500 {end do\}
4501 end if
4502 end subroutine mhd_get_flux_hde
4503
4504 !> Calculate fluxes within ixO^L with possible splitting
4505 !> this covers four cases: B0field=T and mhd_internal_e=T (where has_equi_rho_and_p=F)
4506 !> B0field=T and has_equi_rho_and_p=F for total_energy=T
4507 !> B0field=F and has_equi_rho_and_p=T for total_energy=T
4508 !> B0field=T and has_equi_rho_and_p=T for total_energy=T
4509 subroutine mhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
4511 use mod_geometry
4512
4513 integer, intent(in) :: ixi^l, ixo^l, idim
4514 ! conservative w
4515 double precision, intent(in) :: wc(ixi^s,nw)
4516 ! primitive w
4517 double precision, intent(in) :: w(ixi^s,nw)
4518 double precision, intent(in) :: x(ixi^s,1:ndim)
4519 double precision,intent(out) :: f(ixi^s,nwflux)
4520
4521 double precision :: vhall(ixi^s,1:ndir)
4522 double precision :: ptotal, btotal(ixo^s,1:ndir)
4523 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4524 double precision :: bvec(ixi^s,1:ndir)
4525 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4526 double precision :: nperp(ixi^s,1:ndir)
4527 double precision :: uawsom_zeta(ixi^s), uawsom_radius(ixi^s)
4528 double precision :: uawsom_lperp(ixi^s), uawsom_denom
4529 double precision :: uawsom_pwave, uawsom_bi
4530 logical :: use_perp_flux
4531 integer :: iw, ix^d, idir
4532
4533 if(mhd_uawsom) call mhd_uawsom_get_coefficients(w,x,ixi^l,ixo^l,.true.,&
4534 uawsom_zeta,uawsom_radius,uawsom_lperp)
4535
4536 {do ix^db=ixomin^db,ixomax^db\}
4537 ! Get flux of density
4538 if(has_equi_rho_and_p) then
4539 f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
4540 else
4541 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4542 end if
4543
4544 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4545
4546 if(b0field) then
4547 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)+block%B0(ix^d,^c,idim)\
4548 ptotal=ptotal+(^c&w(ix^d,b^c_)*block%B0(ix^d,^c,idim)+)
4549 ! Get flux of momentum and magnetic field
4550 ! f_i[m_k]=v_i*m_k-b_k*b_i
4551 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-&
4552 btotal(ix^d,idim)*w(ix^d,b^c_)-w(ix^d,mag(idim))*block%B0(ix^d,^c,idim)\
4553 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4554 else
4555 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)\
4556 ! Get flux of momentum and magnetic field
4557 ! f_i[m_k]=v_i*m_k-b_k*b_i
4558 ^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_)\
4559 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4560 end if
4561 if(mhd_uawsom) then
4562 uawsom_pwave=mhd_uawsom_wave_pressure_cell(w(ix^d,:),uawsom_zeta(ix^d))
4563 f(ix^d,mom(idim))=f(ix^d,mom(idim))+uawsom_pwave
4564 end if
4565 ! f_i[b_k]=v_i*b_k-v_k*b_i
4566 ^c&f(ix^d,b^c_)=w(ix^d,mom(idim))*btotal(ix^d,^c)-btotal(ix^d,idim)*w(ix^d,m^c_)\
4567
4568 ! Get flux of energy
4569 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4570 if(mhd_internal_e) then
4571 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4572 else
4573 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4574 -btotal(ix^d,idim)*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4575 if(mhd_uawsom) then
4576 uawsom_denom=dsqrt(w(ix^d,rho_)*(uawsom_zeta(ix^d)+one)/&
4577 (two*(one+mhd_uawsom_filling_factor*uawsom_zeta(ix^d)-&
4579 uawsom_bi=btotal(ix^d,idim)
4580 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,mom(idim))*uawsom_pwave+uawsom_bi*(&
4581 (w(ix^d,waminus_)-w(ix^d,waplus_))/dsqrt(w(ix^d,rho_))+&
4582 (w(ix^d,wkminus_)-w(ix^d,wkplus_))/uawsom_denom)
4583 end if
4584 end if
4585 {end do\}
4586
4587 if(mhd_glm) then
4588 {do ix^db=ixomin^db,ixomax^db\}
4589 f(ix^d,mag(idim))=w(ix^d,psi_)
4590 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4591 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4592 {end do\}
4593 end if
4594
4595 if(mhd_radiation_fld) then
4596 {do ix^db=ixomin^db,ixomax^db\}
4597 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4598 {end do\}
4599 endif
4600
4601 if(mhd_hall) then
4602 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4603 {do ix^db=ixomin^db,ixomax^db\}
4604 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4605 ^c&f(ix^d,b^c_)=f(ix^d,b^c_)+vhall(ix^d,idim)*btotal(ix^d,^c)-btotal(ix^d,idim)*vhall(ix^d,^c)\
4606 if(total_energy) then
4607 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4608 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)*btotal(ix^d,^c)+)&
4609 -btotal(ix^d,idim)*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4610 end if
4611 {end do\}
4612 end if
4613 if (mhd_fip) then
4614 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4615 end if
4616 if(mhd_uawsom) then
4617 {do ix^db=ixomin^db,ixomax^db\}
4618 uawsom_denom=dsqrt(w(ix^d,rho_)*(uawsom_zeta(ix^d)+one)/&
4619 (two*(one+mhd_uawsom_filling_factor*uawsom_zeta(ix^d)-&
4621 uawsom_bi=btotal(ix^d,idim)
4622 f(ix^d,waplus_)=w(ix^d,waplus_)*(w(ix^d,mom(idim))-&
4623 uawsom_bi/dsqrt(w(ix^d,rho_)))
4624 f(ix^d,waminus_)=w(ix^d,waminus_)*(w(ix^d,mom(idim))+&
4625 uawsom_bi/dsqrt(w(ix^d,rho_)))
4626 f(ix^d,wkplus_)=w(ix^d,wkplus_)*(w(ix^d,mom(idim))-uawsom_bi/uawsom_denom)
4627 f(ix^d,wkminus_)=w(ix^d,wkminus_)*(w(ix^d,mom(idim))+uawsom_bi/uawsom_denom)
4628 {end do\}
4629 end if
4630 ! Get flux of tracer
4631 do iw=1,mhd_n_tracer
4632 {do ix^db=ixomin^db,ixomax^db\}
4633 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4634 {end do\}
4635 end do
4636 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
4637 trim(mhd_hyperbolic_tc_perp_mode)/='off'
4638 if(use_perp_flux) then
4639 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4640 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
4641 if(has_equi_rho_and_p) then
4642 te(ixi^s)=(w(ixi^s,p_)+block%equi_vars(ixi^s,equi_pe0_,b0i)) / &
4643 (r(ixi^s)*rho_loc(ixi^s))
4644 else
4645 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4646 end if
4647 {do ix^db=ixomin^db,ixomax^db\}
4648 do idir=1,ndir
4649 bvec(ix^d,idir)=btotal(ix^d,idir)
4650 end do
4651 {end do\}
4652 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4653 end if
4654 if(mhd_hyperbolic_tc) then
4655 {do ix^db=ixomin^db,ixomax^db\}
4656 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*btotal(ix^d,idim)/(dsqrt(^c&btotal(ix^d,^c)**2+)+smalldouble)
4657 f(ix^d,qpar_)=zero
4658 if(use_perp_flux) then
4659 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4660 f(ix^d,qperp_)=zero
4661 end if
4662 {end do\}
4663 end if
4664 end subroutine mhd_get_flux_split
4665
4666 !> Calculate semirelativistic fluxes within ixO^L without any splitting
4667 subroutine mhd_get_flux_semirelati(wC,w,x,ixI^L,ixO^L,idim,f)
4669 use mod_geometry
4670
4671 integer, intent(in) :: ixi^l, ixo^l, idim
4672 ! conservative w
4673 double precision, intent(in) :: wc(ixi^s,nw)
4674 ! primitive w
4675 double precision, intent(in) :: w(ixi^s,nw)
4676 double precision, intent(in) :: x(ixi^s,1:ndim)
4677 double precision,intent(out) :: f(ixi^s,nwflux)
4678 double precision :: sa(ixo^s,1:ndir),e(ixo^s,1:ndir),e2
4679 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4680 double precision :: bvec(ixi^s,1:ndir)
4681 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4682 double precision :: nperp(ixi^s,1:ndir)
4683 logical :: use_perp_flux
4684 integer :: iw, ix^d, idir
4685
4686 {do ix^db=ixomin^db,ixomax^db\}
4687 ! Get flux of density
4688 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4689 ! E=Bxv
4690 {^ifthreec
4691 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4692 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4693 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4694 }
4695 {^iftwoc
4696 e(ix^d,1)=zero
4697 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4698 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4699 }
4700 {^ifonec
4701 e(ix^d,1)=zero
4702 }
4703 e2=(^c&e(ix^d,^c)**2+)
4704 if(mhd_internal_e) then
4705 ! Get flux of internal energy
4706 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4707 else
4708 ! S=ExB
4709 {^ifthreec
4710 sa(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
4711 sa(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
4712 sa(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
4713 }
4714 {^iftwoc
4715 sa(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
4716 sa(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
4717 ! set E2 back to 0, after e^2 is stored
4718 e(ix^d,2)=zero
4719 }
4720 {^ifonec
4721 sa(ix^d,1)=zero
4722 }
4723 ! Get flux of total energy
4724 f(ix^d,e_)=w(ix^d,mom(idim))*(half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)+&
4725 eos%gamma*w(ix^d,p_)*eos%inv_gamma_minus_1)+sa(ix^d,idim)
4726 end if
4727 ! Get flux of momentum
4728 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4729 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4730 ! gas pressure + magnetic pressure + electric pressure
4731 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)
4732 ! compute flux of magnetic field
4733 ! f_i[b_k]=v_i*b_k-v_k*b_i
4734 ^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_)\
4735 {end do\}
4736
4737 if(mhd_glm) then
4738 {do ix^db=ixomin^db,ixomax^db\}
4739 f(ix^d,mag(idim))=w(ix^d,psi_)
4740 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4741 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4742 {end do\}
4743 end if
4744 if (mhd_fip) then
4745 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4746 end if
4747 ! Get flux of tracer
4748 do iw=1,mhd_n_tracer
4749 {do ix^db=ixomin^db,ixomax^db\}
4750 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4751 {end do\}
4752 end do
4753 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
4754 trim(mhd_hyperbolic_tc_perp_mode)/='off'
4755 if(use_perp_flux) then
4756 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4757 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
4758 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4759 {do ix^db=ixomin^db,ixomax^db\}
4760 do idir=1,ndir
4761 bvec(ix^d,idir)=w(ix^d,mag(idir))
4762 end do
4763 {end do\}
4764 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4765 end if
4766 if(mhd_hyperbolic_tc) then
4767 {do ix^db=ixomin^db,ixomax^db\}
4768 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
4769 f(ix^d,qpar_)=zero
4770 if(use_perp_flux) then
4771 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4772 f(ix^d,qperp_)=zero
4773 end if
4774 {end do\}
4775 end if
4776 end subroutine mhd_get_flux_semirelati
4777
4778 subroutine mhd_get_flux_semirelati_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4780 use mod_geometry
4782
4783 integer, intent(in) :: ixi^l, ixo^l, idim
4784 ! conservative w
4785 double precision, intent(in) :: wc(ixi^s,nw)
4786 ! primitive w
4787 double precision, intent(in) :: w(ixi^s,nw)
4788 double precision, intent(in) :: x(ixi^s,1:ndim)
4789 double precision,intent(out) :: f(ixi^s,nwflux)
4790
4791 double precision :: adiabs(ixi^s), gammas(ixi^s)
4792 double precision :: e(ixo^s,1:ndir),e2
4793 integer :: iw, ix^d
4794
4795 if(associated(usr_set_adiab)) then
4796 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4797 else
4798 adiabs=mhd_adiab
4799 end if
4800 if(associated(usr_set_gamma)) then
4801 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4802 else
4803 gammas=eos%gamma
4804 end if
4805 {do ix^db=ixomin^db,ixomax^db\}
4806 ! Get flux of density
4807 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4808 ! E=Bxv
4809 {^ifthreec
4810 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4811 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4812 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4813 e2=(^c&e(ix^d,^c)**2+)
4814 }
4815 {^iftwoc
4816 e(ix^d,1)=zero
4817 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4818 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4819 e2=e(ix^d,2)**2
4820 e(ix^d,2)=zero
4821 }
4822 {^ifonec
4823 e(ix^d,1)=zero
4824 e2=zero
4825 }
4826 ! Get flux of momentum
4827 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4828 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4829 ! gas pressure + magnetic pressure + electric pressure
4830 f(ix^d,mom(idim))=f(ix^d,mom(idim))+adiabs(ix^d)*w(ix^d,rho_)**gammas(ix^d)+half*((^c&w(ix^d,b^c_)**2+)+e2*inv_squared_c)
4831 ! compute flux of magnetic field
4832 ! f_i[b_k]=v_i*b_k-v_k*b_i
4833 ^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_)\
4834 {end do\}
4835
4836 if(mhd_glm) then
4837 {do ix^db=ixomin^db,ixomax^db\}
4838 f(ix^d,mag(idim))=w(ix^d,psi_)
4839 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4840 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4841 {end do\}
4842 end if
4843 if (mhd_fip) then
4844 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4845 end if
4846 ! Get flux of tracer
4847 do iw=1,mhd_n_tracer
4848 {do ix^db=ixomin^db,ixomax^db\}
4849 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4850 {end do\}
4851 end do
4852 end subroutine mhd_get_flux_semirelati_noe
4853
4854 !> Source term J.E_ambi in internal energy
4855 !> For the ambipolar electric field we have E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4856 !> and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4857 !> the source term J.E_ambi = eta_A * B^2 * J_perpB^2 = eta_A * [(JxB)xB]^2/B^2
4858 !> note that J_perpB= - (JxB)xB/B^2
4859 !> multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4860 subroutine add_source_ambipolar_internal_energy(qdt,ixI^L,ixO^L,wCT,w,x)
4862 integer, intent(in) :: ixi^l, ixo^l
4863 double precision, intent(in) :: qdt
4864 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4865 double precision, intent(inout) :: w(ixi^s,1:nw)
4866
4867 double precision :: tmp(ixi^s),btot2(ixi^s)
4868 double precision :: jxbxb(ixi^s,1:3)
4869
4870 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,jxbxb)
4871 ! avoiding nulls here
4872 btot2(ixo^s)=mhd_mag_en_all(wct,ixi^l,ixo^l)
4873 where (btot2(ixo^s)>smalldouble )
4874 tmp(ixo^s) = sum(jxbxb(ixo^s,1:3)**2,dim=ndim+1) / btot2(ixo^s)
4875 elsewhere
4876 tmp(ixo^s) = zero
4877 endwhere
4878 call multiplyambicoef(ixi^l,ixo^l,tmp,wct,x)
4879 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4880 ! hence minus sign here
4881 w(ixo^s,e_)=w(ixo^s,e_)- qdt*tmp(ixo^s)
4882
4883 end subroutine add_source_ambipolar_internal_energy
4884
4885 !> this subroutine computes -J_perpB= (J x B) x B= B(J.B) - J B^2
4886 subroutine mhd_get_jxbxb(w,x,ixI^L,ixO^L,res)
4888
4889 integer, intent(in) :: ixi^l, ixo^l
4890 double precision, intent(in) :: w(ixi^s,nw)
4891 double precision, intent(in) :: x(ixi^s,1:ndim)
4892 double precision, intent(out) :: res(ixi^s,1:3)
4893
4894 double precision :: btot(ixi^s,1:3)
4895 double precision :: current(ixi^s,7-2*ndir:3)
4896 double precision :: tmp(ixi^s),b2(ixi^s)
4897 integer :: idir, idirmin
4898
4899 res=0.d0
4900 ! Calculate current density and idirmin
4901 ! current has nonzero values only for components in the range idirmin, 3
4902 call get_current(w,ixi^l,ixo^l,idirmin,current)
4903
4904 btot=0.d0
4905 if(b0field) then
4906 do idir=1,ndir
4907 btot(ixo^s, idir) = w(ixo^s,mag(idir)) + block%B0(ixo^s,idir,b0i)
4908 enddo
4909 else
4910 do idir=1,ndir
4911 btot(ixo^s, idir) = w(ixo^s,mag(idir))
4912 enddo
4913 endif
4914
4915 tmp(ixo^s)= sum(current(ixo^s,idirmin:3)*btot(ixo^s,idirmin:3),dim=ndim+1) !J.B
4916 b2(ixo^s) = sum(btot(ixo^s,1:3)**2,dim=ndim+1) !B^2
4917 do idir=1,idirmin-1
4918 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s)
4919 enddo
4920 do idir=idirmin,3
4921 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s) - current(ixo^s,idir) * b2(ixo^s)
4922 enddo
4923
4924 ! avoid possible issues at nulls
4925 do idir=1,3
4926 where (b2(ixo^s)<smalldouble )
4927 res(ixo^s,idir) = zero
4928 endwhere
4929 enddo
4930 end subroutine mhd_get_jxbxb
4931
4932 !> Sets the sources for the ambipolar terms for the STS method
4933 !> The sources are added directly (instead of fluxes as in the explicit)
4934 !> at the corresponding indices
4935 !> store_flux_var is explicitly called for each of the fluxes one by one
4936 subroutine sts_set_source_ambipolar(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
4939
4940 integer, intent(in) :: ixi^l,ixo^l,igrid,nflux
4941 double precision, intent(in) :: x(ixi^s,1:ndim)
4942 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
4943 double precision, intent(in) :: my_dt
4944 logical, intent(in) :: fix_conserve_at_step
4945
4946 double precision, dimension(ixI^S,1:3) :: tmp,ff
4947 double precision :: fluxall(ixi^s,1:nflux,1:ndim)
4948 double precision :: fe(ixi^s,sdim:3)
4949 double precision :: btot(ixi^s,1:3),tmp2(ixi^s)
4950 integer :: i, ixa^l, ie_
4951
4952 ixa^l=ixo^l^ladd1;
4953
4954 fluxall=zero
4955
4956 ! here we compute (JxB)xB= - B^2 J_perpB
4957 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,tmp)
4958
4959 ! set ambipolar electric field in tmp: E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4960 ! and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4961 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4962 do i=1,3
4963 call multiplyambicoef(ixi^l,ixa^l,tmp(ixi^s,i),w,x)
4964 enddo
4965
4966 ! Note: internal energy case is handled through add_source_internal_e
4967 ! Note: hydrodynamic energy case is handled through add_source_hydrodynamic_e
4968 ! both of the above use add_source_ambipolar_internal_energy
4969 !
4970 ! Note: total energy case without B0field split is ok here and adds div(BxE_ambi)
4971 ! Note: total energy case in semirelativistic variant (hence no B0field split) is ok here
4972 ! Note: total energy with B0field=T here adds div(B_1xE_ambi) which needs correction in add_source_B0split
4973 if(mhd_energy .and. .not.(mhd_internal_e.or.mhd_hydrodynamic_e)) then
4974 btot(ixa^s,1:3) = 0.d0
4975 ! HERE: only uses B_1 if split, otherwise this is B
4976 btot(ixa^s,1:ndir) = w(ixa^s,mag(1:ndir))
4977 ! compute ff= E_ambi x B (where B can be B_1 if B0field=T)
4978 call cross_product(ixi^l,ixa^l,tmp,btot,ff)
4979 ! compute actual cell face fluxes in ff and their divergence in tmp2
4980 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4981 if(fix_conserve_at_step) fluxall(ixi^s,1,1:ndim)=ff(ixi^s,1:ndim)
4982 ! - sign as the source is actually div(BxE_ambi) and we have div(E_ambi x B) in tmp2
4983 wres(ixo^s,e_)=-tmp2(ixo^s)
4984 endif
4985
4986 if(stagger_grid) then
4987 ! always 2D or more (2.5/3D)
4988 if(ndir>ndim) then
4989 !!!Bz
4990 ff(ixa^s,1) = tmp(ixa^s,2)
4991 ff(ixa^s,2) = -tmp(ixa^s,1)
4992 ff(ixa^s,3) = 0.d0
4993 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4994 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
4995 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
4996 end if
4997 fe=0.d0
4998 call update_faces_ambipolar(ixi^l,ixo^l,w,x,tmp,fe,btot)
4999 ixamax^d=ixomax^d;
5000 ixamin^d=ixomin^d-1;
5001 wres(ixa^s,mag(1:ndim))=-btot(ixa^s,1:ndim)
5002 else
5003 !write curl(ele) as the divergence
5004 !m1={0,ele[[3]],-ele[[2]]}
5005 !m2={-ele[[3]],0,ele[[1]]}
5006 !m3={ele[[2]],-ele[[1]],0}
5007
5008 {^ifoned
5009 !!!Bx
5010 ff(ixa^s,1) = 0.d0
5011 ff(ixa^s,2) = tmp(ixa^s,3)
5012 ff(ixa^s,3) = -tmp(ixa^s,2)
5013 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5014 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
5015 !flux divergence is a source now
5016 wres(ixo^s,mag(1))=-tmp2(ixo^s)
5017 if(ndir==2.or.ndir==3)then
5018 !!!By
5019 ff(ixa^s,1) = -tmp(ixa^s,3)
5020 ff(ixa^s,2) = 0.d0
5021 ff(ixa^s,3) = tmp(ixa^s,1)
5022 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5023 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
5024 wres(ixo^s,mag(2))=-tmp2(ixo^s)
5025 endif
5026 }
5027 {^nooned
5028 !!!Bx
5029 ff(ixa^s,1) = 0.d0
5030 ff(ixa^s,2) = tmp(ixa^s,3)
5031 ff(ixa^s,3) = -tmp(ixa^s,2)
5032 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5033 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
5034 !flux divergence is a source now
5035 wres(ixo^s,mag(1))=-tmp2(ixo^s)
5036 !!!By
5037 ff(ixa^s,1) = -tmp(ixa^s,3)
5038 ff(ixa^s,2) = 0.d0
5039 ff(ixa^s,3) = tmp(ixa^s,1)
5040 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5041 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
5042 wres(ixo^s,mag(2))=-tmp2(ixo^s)
5043 }
5044
5045 if(ndir==3) then
5046 !!!Bz
5047 ff(ixa^s,1) = tmp(ixa^s,2)
5048 ff(ixa^s,2) = -tmp(ixa^s,1)
5049 ff(ixa^s,3) = 0.d0
5050 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5051 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
5052 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
5053 end if
5054
5055 end if
5056
5057 if(fix_conserve_at_step) then
5058 fluxall=my_dt*fluxall
5059 call store_flux(igrid,fluxall,1,ndim,nflux)
5060 if(stagger_grid) then
5061 call store_edge(igrid,ixi^l,my_dt*fe,1,ndim)
5062 end if
5063 end if
5064
5065 end subroutine sts_set_source_ambipolar
5066
5067 !> get ambipolar electric field and the integrals around cell faces
5068 subroutine update_faces_ambipolar(ixI^L,ixO^L,w,x,ECC,fE,circ)
5070
5071 integer, intent(in) :: ixi^l, ixo^l
5072 double precision, intent(in) :: w(ixi^s,1:nw)
5073 double precision, intent(in) :: x(ixi^s,1:ndim)
5074 ! amibipolar electric field at cell centers
5075 double precision, intent(in) :: ecc(ixi^s,1:3)
5076 double precision, intent(out) :: fe(ixi^s,sdim:3)
5077 double precision, intent(out) :: circ(ixi^s,1:ndim)
5078
5079 integer :: hxc^l,ixc^l,ixa^l
5080 integer :: idim1,idim2,idir,ix^d
5081
5082 fe=zero
5083 ! calculate ambipolar electric field on cell edges from cell centers
5084 do idir=sdim,3
5085 ixcmax^d=ixomax^d;
5086 ixcmin^d=ixomin^d+kr(idir,^d)-1;
5087 {do ix^db=0,1\}
5088 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
5089 ixamin^d=ixcmin^d+ix^d;
5090 ixamax^d=ixcmax^d+ix^d;
5091 fe(ixc^s,idir)=fe(ixc^s,idir)+ecc(ixa^s,idir)
5092 {end do\}
5093 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0*block%dsC(ixc^s,idir)
5094 end do
5095
5096 ! Calculate circulation on each face to get value of line integral of
5097 ! electric field in the positive idir direction.
5098 ixcmax^d=ixomax^d;
5099 ixcmin^d=ixomin^d-1;
5100
5101 circ=zero
5102 do idim1=1,ndim ! Coordinate perpendicular to face
5103 do idim2=1,ndim
5104 do idir=sdim,3 ! Direction of line integral
5105 ! Assemble indices
5106 hxc^l=ixc^l-kr(idim2,^d);
5107 ! Add line integrals in direction idir
5108 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5109 +lvc(idim1,idim2,idir)&
5110 *(fe(ixc^s,idir)&
5111 -fe(hxc^s,idir))
5112 end do
5113 end do
5114 circ(ixc^s,idim1)=circ(ixc^s,idim1)/block%surfaceC(ixc^s,idim1)
5115 end do
5116
5117 end subroutine update_faces_ambipolar
5118
5119 !> use cell-center flux vector to get cell-face flux vector
5120 !> which will be used to add the source term as the divergence of the flux
5121 !> we return fluxes at all faces as well as the divergence of the flux
5122 !> Note that for ndir>ndim, we do not modify the input cell center flux
5123 subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
5125
5126 integer, intent(in) :: ixi^l, ixo^l
5127 double precision, dimension(ixI^S,1:3), intent(inout) :: ff
5128 double precision, intent(out) :: src(ixi^s)
5129
5130 double precision :: ffc(ixi^s,1:ndim)
5131 double precision :: dxinv(ndim)
5132 integer :: idims, ix^d, ixa^l, ixb^l, ixc^l
5133
5134 ixa^l=ixo^l^ladd1;
5135 dxinv=1.d0/dxlevel
5136 ! cell corner flux in ffc
5137 ! TO BE GENERALIZED FOR NON-UNIFORM NON-CARTESIAN MESH
5138 if (slab_uniform)then
5139 ffc=0.d0
5140 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
5141 {do ix^db=0,1\}
5142 ixbmin^d=ixcmin^d+ix^d;
5143 ixbmax^d=ixcmax^d+ix^d;
5144 ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
5145 {end do\}
5146 ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
5147 else
5148 call mpistop("to generalize using volume averaging")
5149 endif
5150 ! now get flux at cell face from corner fluxes in fcc
5151 ff(ixi^s,1:ndim)=0.d0
5152 do idims=1,ndim
5153 ixb^l=ixo^l-kr(idims,^d);
5154 ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
5155 {do ix^db=0,1 \}
5156 if({ ix^d==0 .and. ^d==idims | .or.}) then
5157 ixbmin^d=ixcmin^d-ix^d;
5158 ixbmax^d=ixcmax^d-ix^d;
5159 ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
5160 end if
5161 {end do\}
5162 ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
5163 end do
5164 src=0.d0
5165 if(slab_uniform) then
5166 do idims=1,ndim
5167 ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
5168 ixb^l=ixo^l-kr(idims,^d);
5169 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
5170 end do
5171 else
5172 do idims=1,ndim
5173 ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
5174 ixb^l=ixo^l-kr(idims,^d);
5175 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
5176 end do
5177 src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
5178 end if
5179 end subroutine get_flux_on_cell_face
5180
5181 !> Calculates the explicit dt for the ambipolar term
5182 !> This function is used by both explicit scheme and STS method
5183 function get_ambipolar_dt(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
5185
5186 integer, intent(in) :: ixi^l, ixo^l
5187 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
5188 double precision, intent(in) :: w(ixi^s,1:nw)
5189 double precision :: dtnew
5190
5191 double precision :: coef
5192 double precision :: dxarr(ndim)
5193 double precision :: tmp(ixi^s)
5194
5195 ^d&dxarr(^d)=dx^d;
5196 tmp(ixo^s) = mhd_mag_en_all(w, ixi^l, ixo^l)
5197 call multiplyambicoef(ixi^l,ixo^l,tmp,w,x)
5198 ! now we have -mhd_eta_ambi B^2 /rho^2 in tmp
5199 coef = maxval(dabs(tmp(ixo^s)))
5200 if(coef/=0.d0) then
5201 coef=1.d0/coef
5202 else
5203 coef=bigdouble
5204 end if
5205 if(slab_uniform) then
5206 dtnew=minval(dxarr(1:ndim))**2.0d0*coef
5207 else
5208 dtnew=minval(block%ds(ixo^s,1:ndim))**2.0d0*coef
5209 end if
5210
5211 end function get_ambipolar_dt
5212
5213 !> multiply res by the ambipolar coefficient
5214 !> The ambipolar coefficient is calculated as -mhd_eta_ambi/rho^2
5215 !> The user may mask its value in the user file
5216 !> by implementing usr_mask_ambipolar subroutine
5217 subroutine multiplyambicoef(ixI^L,ixO^L,res,w,x)
5219 integer, intent(in) :: ixi^l, ixo^l
5220 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
5221 double precision, intent(inout) :: res(ixi^s)
5222 double precision :: tmp(ixi^s)
5223 double precision :: rho(ixi^s)
5224
5225 call mhd_get_rho(w,x,ixi^l,ixi^l,rho)
5226 tmp(ixi^s)=-mhd_eta_ambi/rho(ixi^s)**2
5227 if (associated(usr_mask_ambipolar)) then
5228 call usr_mask_ambipolar(ixi^l,ixo^l,w,x,tmp)
5229 end if
5230 res(ixo^s) = tmp(ixo^s) * res(ixo^s)
5231
5232 end subroutine multiplyambicoef
5233
5234 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
5235 subroutine mhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5241 use mod_cak_force, only: cak_add_source
5242
5243 integer, intent(in) :: ixi^l, ixo^l
5244 double precision, intent(in) :: qdt,dtfactor
5245 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
5246 double precision, intent(inout) :: w(ixi^s,1:nw)
5247 logical, intent(in) :: qsourcesplit
5248 logical, intent(inout) :: active
5249
5250 !TODO local_timestep support is only added for splitting
5251 ! but not for other nonideal terms such gravity, RC, viscosity,..
5252 ! it will also only work for divbfix 'linde', which does not require
5253 ! modification as it does not use dt in the update
5254
5255 if (.not. qsourcesplit) then
5256 if(mhd_uawsom) then
5257 active = .true.
5258 call mhd_add_source_uawsom(qdt,ixi^l,ixo^l,wct,wctprim,w,x)
5259 end if
5260 if(mhd_internal_e) then
5261 ! Source for solving internal energy
5262 active = .true.
5263 call add_source_internal_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5264 else
5265 if(has_equi_rho_and_p) then
5266 active = .true.
5267 call add_equi_terms(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5268 end if
5269 end if
5270
5271 if(mhd_hyperbolic_tc) then
5272 active = .true.
5273 call add_hyperbolic_tc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5274 end if
5275
5276 ! Source for B0 splitting
5277 if (b0field) then
5278 active = .true.
5279 ! this adds source to momentum of type J0 x B0 and to energy equation
5280 ! latter always + J0 * E (electric field being E_ideal, E_hall, E_ambi)
5281 ! used for total energy variants
5282 call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5283 end if
5284
5285 ! Sources for resistivity in eqs. for e, B1, B2 and B3
5286 if (abs(mhd_eta)>smalldouble)then
5287 active = .true.
5288 call add_source_res_exp(qdt,ixi^l,ixo^l,wct,w,x)
5289 end if
5290
5291 if (mhd_ambipolar_exp)then
5292 active = .true.
5293 call add_source_ambi_exp(qdt,ixi^l,ixo^l,wct,w,x)
5294 end if
5295
5296 if (mhd_eta_hyper>0.d0)then
5297 active = .true.
5298 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
5299 end if
5300
5301 if(mhd_hydrodynamic_e) then
5302 ! Source for solving hydrodynamic energy
5303 active = .true.
5304 call add_source_hydrodynamic_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5305 else if (mhd_semirelativistic) then
5306 ! add sources for semirelativistic MHD
5307 active = .true.
5308 call add_source_semirelativistic(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5309 end if
5310 end if
5311
5312 {^nooned
5313 if(source_split_divb .eqv. qsourcesplit) then
5314 ! Sources related to div B
5315 select case (type_divb)
5316 case (divb_ct)
5317 continue ! Do nothing
5318 case (divb_linde)
5319 active = .true.
5320 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5321 case (divb_glm)
5322 active = .true.
5323 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5324 case (divb_powel)
5325 active = .true.
5326 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5327 case (divb_janhunen)
5328 active = .true.
5329 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5330 case (divb_lindejanhunen)
5331 active = .true.
5332 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5333 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5334 case (divb_lindepowel)
5335 active = .true.
5336 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5337 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5338 case (divb_lindeglm)
5339 active = .true.
5340 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5341 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5342 case (divb_multigrid)
5343 continue ! Do nothing
5344 case (divb_none)
5345 ! Do nothing
5346 case default
5347 call mpistop('Unknown divB fix')
5348 end select
5349 end if
5350 }
5351
5352 if(mhd_radiative_cooling) then
5353 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5354 w,x,qsourcesplit,active, rc_fl)
5355 end if
5356
5357 if(mhd_viscosity) then
5358 call viscosity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5359 w,x,mhd_energy,qsourcesplit,active)
5360 end if
5361
5362 if(mhd_gravity) then
5363 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5364 w,x,gravity_energy,qsourcesplit,active)
5365 end if
5366
5367 if (mhd_cak_force) then
5368 call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,mhd_energy,qsourcesplit,active)
5369 end if
5370
5371 ! This is where the radiation force and heating/cooling are added
5372 if (mhd_radiation_fld) then
5373 call mhd_add_radiation_source(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
5374 endif
5375
5376 ! update temperature from new pressure, density, and old ionization degree
5377 if(eos%eos_type == 'PI') then
5378 if(.not.qsourcesplit) then
5379 active = .true.
5380 call eos%update_eos(ixi^l,ixo^l,w,x)
5381 end if
5382 end if
5383
5384 end subroutine mhd_add_source
5385
5386 subroutine mhd_add_radiation_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5387 use mod_constants
5389 use mod_usr_methods
5390 use mod_fld
5391
5392 integer, intent(in) :: ixi^l, ixo^l
5393 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
5394 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
5395 double precision, intent(inout) :: w(ixi^s,1:nw)
5396 logical, intent(in) :: qsourcesplit
5397 logical, intent(inout) :: active
5398
5399 ! add radiation force and work done by it, changes momentum and gas energy
5400 ! handle photon tiring, heating and cooling exchange between gas and radiation field
5401 call add_fld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active,fld_fl)
5402
5403 end subroutine mhd_add_radiation_source
5404
5405 !> add some source terms to total energy related to has_equi_rho_and_p=T
5406 subroutine add_equi_terms(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5408 use mod_geometry
5409 use mod_usr_methods
5410
5411 integer, intent(in) :: ixi^l, ixo^l
5412 double precision, intent(in) :: qdt,dtfactor
5413 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5414 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5415 double precision, intent(inout) :: w(ixi^s,1:nw)
5416
5417 double precision :: divv(ixi^s)
5418 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5419 double precision :: gravity_field(ixi^s,1:ndim)
5420 integer :: idir
5421
5422 if(slab_uniform) then
5423 if(nghostcells .gt. 2) then
5424 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,3)
5425 else
5426 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,2)
5427 end if
5428 else
5429 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv)
5430 end if
5431 divv(ixo^s)=divv(ixo^s)*eos%gamma*eos%inv_gamma_minus_1
5432 if(local_timestep) then
5433 w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5434 else
5435 w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5436 end if
5437 if(b0field)then
5438 if(b0field_forcefree.and.mhd_gravity)then
5439 ! add -v dot(rho_0 g)/(gamma-1)
5440 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5441 do idir=1,ndim
5442 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
5443 enddo
5444 else
5445 a=0.d0
5446 b=0.d0
5447 ! store B0 magnetic field in b
5448 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5449 ! store J0 current in a
5450 do idir=7-2*ndir,3
5451 a(ixo^s,idir)=block%J0(ixo^s,idir)
5452 end do
5453 call cross_product(ixi^l,ixo^l,a,b,axb)
5454 ! add -v dot(rho_0 g + J0 x B_0)/(gamma-1)
5455 do idir=1,ndir
5456 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*axb(ixo^s,idir)*eos%inv_gamma_minus_1
5457 enddo
5458 if(mhd_gravity)then
5459 ! add -v dot(rho_0 g)/(gamma-1)
5460 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5461 do idir=1,ndim
5462 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
5463 enddo
5464 endif
5465 endif
5466 else
5467 if(mhd_gravity)then
5468 ! add -v dot(rho_0 g)/(gamma-1)
5469 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5470 do idir=1,ndim
5471 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
5472 enddo
5473 endif
5474 endif
5475 end subroutine add_equi_terms
5476
5477 subroutine mhd_get_hyperbolic_tc_geometry(ixI^L,ixO^L,Te,Bvec,bgradT,gradTperp_mag,nperp)
5479 use mod_geometry, only: gradient
5480 integer, intent(in) :: ixi^l,ixo^l
5481 double precision, intent(in) :: te(ixi^s)
5482 double precision, intent(in) :: bvec(ixi^s,1:ndir)
5483 double precision, intent(out) :: bgradt(ixi^s), gradtperp_mag(ixi^s)
5484 double precision, intent(out) :: nperp(ixi^s,1:ndir)
5485
5486 double precision :: bmag, bunitvec(ndir), gradt(ndir), gradt_perp(ndir)
5487 double precision :: gradt_cell(ixi^s,1:ndir)
5488 integer :: ix^d, idir
5489
5490 gradt_cell=zero
5491 if(.not. slab_uniform) then
5492 do idir=1,ndim
5493 call gradient(te,ixi^l,ixo^l,idir,gradt_cell(ixi^s,idir))
5494 end do
5495 end if
5496
5497 {^iftwod
5498 do ix2=ixomin2,ixomax2
5499 do ix1=ixomin1,ixomax1
5500 bmag=zero
5501 do idir=1,ndir
5502 bmag=bmag+bvec(ix^d,idir)**2
5503 end do
5504 bmag=dsqrt(bmag)
5505
5506 if(bmag>smalldouble) then
5507 do idir=1,ndir
5508 bunitvec(idir)=bvec(ix^d,idir)/bmag
5509 end do
5510 else
5511 do idir=1,ndir
5512 bunitvec(idir)=zero
5513 end do
5514 end if
5515 if(slab_uniform) then
5516 gradt(1)=((8.d0*(te(ix1+1,ix2)-te(ix1-1,ix2))-te(ix1+2,ix2)+te(ix1-2,ix2))/12.d0)/block%ds(ix^d,1)
5517 gradt(2)=((8.d0*(te(ix1,ix2+1)-te(ix1,ix2-1))-te(ix1,ix2+2)+te(ix1,ix2-2))/12.d0)/block%ds(ix^d,2)
5518 if(ndir>2) gradt(3)=zero
5519 else
5520 do idir=1,ndir
5521 gradt(idir)=gradt_cell(ix^d,idir)
5522 end do
5523 end if
5524
5525 bgradt(ix^d)=zero
5526 do idir=1,ndir
5527 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
5528 end do
5529
5530 do idir=1,ndir
5531 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
5532 end do
5533
5534 gradtperp_mag(ix^d)=zero
5535 do idir=1,ndir
5536 gradtperp_mag(ix^d)=gradtperp_mag(ix^d)+gradt_perp(idir)**2
5537 end do
5538 gradtperp_mag(ix^d)=dsqrt(gradtperp_mag(ix^d))
5539
5540 if(gradtperp_mag(ix^d)>smalldouble) then
5541 do idir=1,ndir
5542 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
5543 end do
5544 else
5545 gradtperp_mag(ix^d)=zero
5546 do idir=1,ndir
5547 nperp(ix^d,idir)=zero
5548 end do
5549 end if
5550 end do
5551 end do
5552 }
5553 {^ifthreed
5554 do ix3=ixomin3,ixomax3
5555 do ix2=ixomin2,ixomax2
5556 do ix1=ixomin1,ixomax1
5557 bmag=dsqrt(bvec(ix^d,1)**2+bvec(ix^d,2)**2+bvec(ix^d,3)**2)
5558 if(bmag>smalldouble) then
5559 bunitvec(1)=bvec(ix^d,1)/bmag
5560 bunitvec(2)=bvec(ix^d,2)/bmag
5561 bunitvec(3)=bvec(ix^d,3)/bmag
5562 else
5563 bunitvec(1)=zero
5564 bunitvec(2)=zero
5565 bunitvec(3)=zero
5566 end if
5567
5568 if(slab_uniform) then
5569 gradt(1)=((8.d0*(te(ix1+1,ix2,ix3)-te(ix1-1,ix2,ix3))-te(ix1+2,ix2,ix3)+te(ix1-2,ix2,ix3))/12.d0)/block%ds(ix^d,1)
5570 gradt(2)=((8.d0*(te(ix1,ix2+1,ix3)-te(ix1,ix2-1,ix3))-te(ix1,ix2+2,ix3)+te(ix1,ix2-2,ix3))/12.d0)/block%ds(ix^d,2)
5571 gradt(3)=((8.d0*(te(ix1,ix2,ix3+1)-te(ix1,ix2,ix3-1))-te(ix1,ix2,ix3+2)+te(ix1,ix2,ix3-2))/12.d0)/block%ds(ix^d,3)
5572 else
5573 do idir=1,ndir
5574 gradt(idir)=gradt_cell(ix^d,idir)
5575 end do
5576 end if
5577
5578 bgradt(ix^d)=zero
5579 do idir=1,ndir
5580 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
5581 end do
5582
5583 do idir=1,ndir
5584 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
5585 end do
5586
5587 gradtperp_mag(ix^d)=dsqrt(gradt_perp(1)**2+gradt_perp(2)**2+gradt_perp(3)**2)
5588 if(gradtperp_mag(ix^d)>smalldouble) then
5589 do idir=1,ndir
5590 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
5591 end do
5592 else
5593 gradtperp_mag(ix^d)=zero
5594 do idir=1,ndir
5595 nperp(ix^d,idir)=zero
5596 end do
5597 end if
5598 end do
5599 end do
5600 end do
5601 }
5602 end subroutine mhd_get_hyperbolic_tc_geometry
5603
5604 subroutine add_hyperbolic_tc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5606 use mod_geometry, only: gradient
5607 integer, intent(in) :: ixi^l,ixo^l
5608 double precision, intent(in) :: qdt
5609 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
5610 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
5611 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
5612
5613 double precision, dimension(ixI^S) :: r,te,rho_loc,pth_loc
5614 double precision, dimension(ixI^S) :: ne_loc,nh_dummy
5615 double precision, dimension(ixI^S,1:ndir) :: bvec
5616 double precision, dimension(ixI^S) :: bgradt, gradtperp_mag
5617 double precision, dimension(ixI^S,1:ndir) :: nperp
5618 double precision, dimension(ixI^S) :: gradt_geom
5619 double precision, parameter :: xe_prefac_cgs = 4.753567596681522d6
5620 double precision :: kappa_t5,kappa_t5_perp,kappa_t5_perp_eff
5621 double precision :: kappa_t7,f_sat,kappat5_bgradt,kappat5_gradtperp,tau,b2,fb,gradt1
5622 double precision :: qclass_diss
5623 double precision :: bmag_loc,tloc,tcond,nloc_code,cchi,chi
5624 double precision :: cmax(ndim),c2,cfast2,avmincs2(ndim),inv_rho
5625 logical :: use_perp_source
5626 integer :: ix^d,idir
5627
5628 ! xe_prefac_cgs expects B [G], T [K], and ne [cm^-3]. Convert the
5629 ! normalisation units explicitly in SI mode, while retaining code-unit
5630 ! state variables in the cell loop below.
5631 cchi=zero
5632 if(trim(mhd_hyperbolic_tc_perp_mode)=='electron_magnetization') then
5633 if(si_unit) then
5634 cchi = (xe_prefac_cgs/mhd_hyperbolic_tc_coulomb_log) * &
5635 (1.d4*unit_magneticfield)*unit_temperature**1.5d0 / &
5636 (1.d-6*unit_numberdensity)
5637 else
5638 cchi = (xe_prefac_cgs/mhd_hyperbolic_tc_coulomb_log) * &
5640 end if
5641 end if
5642 call eos%get_Rfactor(wct,x,ixi^l,ixi^l,r)
5643 {do ix^db=iximin^db,iximax^db\}
5644 if(has_equi_rho_and_p) then
5645 rho_loc(ix^d)=wctprim(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
5646 pth_loc(ix^d)=wctprim(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)
5647 else
5648 rho_loc(ix^d)=wctprim(ix^d,rho_)
5649 pth_loc(ix^d)=wctprim(ix^d,p_)
5650 end if
5651 te(ix^d)=pth_loc(ix^d)/(r(ix^d)*rho_loc(ix^d))
5652 {end do\}
5653 ! Electron number density in code units. Under the FI/PI normalisation,
5654 ! rho_code equals nH_code. FI uses the composition-dependent fully ionised
5655 ! electron count. PI obtains the local electron count from its R factor:
5656 ! R*(2+3 A_He) = (n_nuclei+n_e)/n_H. LTE stores ne explicitly.
5657 if(trim(mhd_hyperbolic_tc_perp_mode)=='electron_magnetization') then
5658 if(eos%eos_type=='LTE') then
5659 call eos%get_ne_nH(ixi^l,ixi^l,wct, x,ne_loc,nh_dummy)
5660 else if(eos%eos_type=='PI') then
5661 ne_loc(ixi^s)=rho_loc(ixi^s)*max(r(ixi^s)*(2.d0+3.d0*eos%He_abundance) &
5662 -(1.d0+eos%He_abundance),smalldouble)
5663 else
5664 ne_loc(ixi^s)=rho_loc(ixi^s)*(1.d0+2.d0*eos%He_abundance)
5665 end if
5666 end if
5667 use_perp_source = mhd_hyperbolic_tc_use_perp .and. &
5668 trim(mhd_hyperbolic_tc_perp_mode)/='off'
5669 if(b0field) then
5670 {do ix^db=ixomin^db,ixomax^db\}
5671 do idir=1,ndir
5672 bvec(ix^d,idir)=wct(ix^d,mag(idir))+block%B0(ix^d,idir,0)
5673 end do
5674 {end do\}
5675 else
5676 {do ix^db=ixomin^db,ixomax^db\}
5677 do idir=1,ndir
5678 bvec(ix^d,idir)=wct(ix^d,mag(idir))
5679 end do
5680 {end do\}
5681 end if
5682 {^nooned
5683 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
5684 }
5685 {^ifoned
5686 gradt_geom=zero
5687 if(.not.slab_uniform) then
5688 call gradient(te,ixi^l,ixo^l,1,gradt_geom)
5689 end if
5690 do ix1=ixomin1,ixomax1
5693 kappa_t7=kappa_t5*te(ix1)
5694 else
5695 tcond = te(ix1)
5696 if(mhd_trac) then
5697 tcond = max(tcond, block%wextra(ix1,tcoff_))
5698 end if
5699 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5700 kappa_t7=kappa_t5*tcond
5701 end if
5702 if(slab_uniform) then
5703 gradt1=((8.d0*(te(ix1+1)-te(ix1-1))-te(ix1+2)+te(ix1-2))/12.d0)/block%ds(ix1,1)
5704 else
5705 gradt1=gradt_geom(ix1)
5706 end if
5707 b2=zero
5708 do idir=1,ndir
5709 b2=b2+bvec(ix1,idir)**2
5710 end do
5711 if(b2>smalldouble**2) then
5712 bgradt(ix1)=bvec(ix1,1)*gradt1/dsqrt(b2)
5713 else
5714 bgradt(ix1)=zero
5715 end if
5716 kappat5_bgradt=kappa_t5*bgradt(ix1)
5717 inv_rho=1.d0/rho_loc(ix1)
5718 c2=eos%gamma*pth_loc(ix1)*inv_rho
5719 cfast2 = b2*inv_rho + c2
5720 avmincs2(1) = cfast2**2 - 4.0d0*c2*bvec(ix1,1)**2*inv_rho
5721 cmax(1) = sqrt(half*(cfast2 + sqrt(dabs(avmincs2(1)))))
5722 if(mhd_hyperbolic_tc_sat) then
5723 f_sat=one/(one+dabs(kappat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5724 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*cmax(1)**2))
5725 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5726 else
5727 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/&
5728 max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*cmax(1)**2))
5729 end if
5730 end do
5731 }
5732 {^iftwod
5733 do ix2=ixomin2,ixomax2
5734 do ix1=ixomin1,ixomax1
5737 kappa_t7=kappa_t5*te(ix^d)
5738 else
5739 tcond=te(ix^d)
5740 if(mhd_trac) then
5741 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5742 end if
5743 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5744 kappa_t7 = kappa_t5*tcond
5745 end if
5746 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5747 b2 = zero
5748 do idir = 1, ndir
5749 b2 = b2 + bvec(ix^d,idir)**2
5750 end do
5751 if(use_perp_source) then
5752 select case(trim(mhd_hyperbolic_tc_perp_mode))
5753 case('fixed_reference')
5754 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5755 case('weak_field_isotropization')
5756 if(mhd_hyperbolic_tc_bmin>zero) then
5757 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5758 else
5759 fb=one
5760 end if
5761 kappa_t5_perp_eff=(one-fb)*kappa_t5
5762 kappa_t5_perp=kappa_t5_perp_eff
5763 case('electron_magnetization')
5764 bmag_loc = dsqrt(b2)
5765 tloc = max(te(ix^d), smalldouble)
5766 nloc_code = max(ne_loc(ix^d), smalldouble)
5767 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5768 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5769 kappa_t5_perp = kappa_t5_perp_eff
5770 case default
5771 kappa_t5_perp=zero
5772 end select
5773 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5774 end if
5775 inv_rho=1.d0/rho_loc(ix^d)
5776 c2=eos%gamma*pth_loc(ix^d)*inv_rho
5777 cfast2 = b2*inv_rho + c2
5778 do idir=1,ndim
5779 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5780 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5781 end do
5782 if(mhd_hyperbolic_tc_sat) then
5783 qclass_diss=dabs(kappat5_bgradt)
5784 if(use_perp_source) &
5785 qclass_diss=dsqrt(kappat5_bgradt**2+kappat5_gradtperp**2)
5786 f_sat=one/(one+qclass_diss/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5787 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5788 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5789 if(use_perp_source) then
5790 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5791 end if
5792 else
5793 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5794 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5795 if(use_perp_source) then
5796 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5797 end if
5798 end if
5799 end do
5800 end do
5801 }
5802 {^ifthreed
5803 do ix3=ixomin3,ixomax3
5804 do ix2=ixomin2,ixomax2
5805 do ix1=ixomin1,ixomax1
5808 kappa_t7=kappa_t5*te(ix^d)
5809 else
5810 tcond=te(ix^d)
5811 if(mhd_trac) then
5812 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5813 end if
5814 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5815 kappa_t7 = kappa_t5*tcond
5816 end if
5817 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5818 b2 = zero
5819 do idir = 1, ndir
5820 b2 = b2 + bvec(ix^d,idir)**2
5821 end do
5822 if(use_perp_source) then
5823 select case(trim(mhd_hyperbolic_tc_perp_mode))
5824 case('fixed_reference')
5825 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5826 case('weak_field_isotropization')
5827 if(mhd_hyperbolic_tc_bmin>zero) then
5828 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5829 else
5830 fb=one
5831 end if
5832 kappa_t5_perp_eff=(one-fb)*kappa_t5
5833 kappa_t5_perp=kappa_t5_perp_eff
5834 case('electron_magnetization')
5835 bmag_loc = dsqrt(b2)
5836 tloc = max(te(ix^d), smalldouble)
5837 nloc_code = max(ne_loc(ix^d), smalldouble)
5838 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5839 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5840 kappa_t5_perp = kappa_t5_perp_eff
5841 case default
5842 kappa_t5_perp=zero
5843 end select
5844 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5845 end if
5846 inv_rho=1.d0/rho_loc(ix^d)
5847 c2=eos%gamma*pth_loc(ix^d)*inv_rho
5848 cfast2 = b2*inv_rho + c2
5849 do idir = 1, ndim
5850 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5851 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5852 end do
5853 if(mhd_hyperbolic_tc_sat) then
5854 qclass_diss=dabs(kappat5_bgradt)
5855 if(use_perp_source) &
5856 qclass_diss=dsqrt(kappat5_bgradt**2+kappat5_gradtperp**2)
5857 f_sat=one/(one+qclass_diss/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5858 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5859 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5860 if(use_perp_source) then
5861 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5862 end if
5863 else
5864 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5865 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5866 if(use_perp_source) then
5867 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5868 end if
5869 end if
5870 end do
5871 end do
5872 end do
5873 }
5874 end subroutine add_hyperbolic_tc_source
5875
5876 !> Compute the Lorentz force (JxB) Note: Unused subroutine
5877 !> perhaps useful for post-processing when made public
5878 subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
5880 integer, intent(in) :: ixi^l, ixo^l
5881 double precision, intent(in) :: w(ixi^s,1:nw)
5882 double precision, intent(inout) :: jxb(ixi^s,3)
5883 double precision :: a(ixi^s,3), b(ixi^s,3)
5884 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5885 double precision :: current(ixi^s,7-2*ndir:3)
5886 integer :: idir, idirmin
5887
5888 b=0.0d0
5889 if(b0field) then
5890 do idir = 1, ndir
5891 b(ixo^s, idir) = w(ixo^s,mag(idir))+block%B0(ixo^s,idir,0)
5892 end do
5893 else
5894 do idir = 1, ndir
5895 b(ixo^s, idir) = w(ixo^s,mag(idir))
5896 end do
5897 end if
5898
5899 ! store J current in a
5900 call get_current(w,ixi^l,ixo^l,idirmin,current)
5901
5902 a=0.0d0
5903 do idir=7-2*ndir,3
5904 a(ixo^s,idir)=current(ixo^s,idir)
5905 end do
5906
5907 call cross_product(ixi^l,ixo^l,a,b,jxb)
5908 end subroutine get_lorentz_force
5909
5910 subroutine mhd_get_rho(w,x,ixI^L,ixO^L,rho)
5912 integer, intent(in) :: ixi^l, ixo^l
5913 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
5914 double precision, intent(out) :: rho(ixi^s)
5915
5916 if(has_equi_rho_and_p) then
5917 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
5918 else
5919 rho(ixo^s) = w(ixo^s,rho_)
5920 endif
5921
5922 end subroutine mhd_get_rho
5923
5924 !> handle small or negative internal energy
5925 subroutine mhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
5928 integer, intent(in) :: ixi^l,ixo^l, ie
5929 double precision, intent(inout) :: w(ixi^s,1:nw)
5930 double precision, intent(in) :: x(ixi^s,1:ndim)
5931 character(len=*), intent(in) :: subname
5932
5933 double precision :: rho(ixi^s)
5934 integer :: idir
5935 logical :: flag(ixi^s,1:nw)
5936
5937 flag=.false.
5938 if(has_equi_rho_and_p) then
5939 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1<small_e)&
5940 flag(ixo^s,ie)=.true.
5941 else
5942 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
5943 endif
5944 if(any(flag(ixo^s,ie))) then
5945 select case (small_values_method)
5946 case ("replace")
5947 if(has_equi_rho_and_p) then
5948 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
5949 block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1
5950 else
5951 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
5952 endif
5953 case ("average")
5954 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
5955 case default
5956 ! small values error shows primitive variables
5957 w(ixo^s,e_)=w(ixo^s,e_)*eos%gamma_minus_1
5958 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
5959 do idir = 1, ndir
5960 w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
5961 end do
5962 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
5963 end select
5964 end if
5965
5966 end subroutine mhd_handle_small_ei
5967
5968
5969 !> Source terms after split off time-independent magnetic field
5970 subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5972
5973 integer, intent(in) :: ixi^l, ixo^l
5974 double precision, intent(in) :: qdt, dtfactor,wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5975 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5976 double precision, intent(inout) :: w(ixi^s,1:nw)
5977
5978 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5979 integer :: idir
5980
5981 a=0.d0
5982 b=0.d0
5983 ! for force-free field J0xB0 =0
5984 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) then
5985 ! store B0 magnetic field in b
5986 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5987
5988 ! store J0 current in a
5989 do idir=7-2*ndir,3
5990 a(ixo^s,idir)=block%J0(ixo^s,idir)
5991 end do
5992 call cross_product(ixi^l,ixo^l,a,b,axb)
5993 if(local_timestep) then
5994 do idir=1,3
5995 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5996 enddo
5997 else
5998 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5999 endif
6000 ! add J0xB0 source term in momentum equations
6001 w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
6002 end if
6003
6004 if(total_energy) then
6005 a=0.d0
6006 ! for free-free field -(vxB0) dot J0 =0
6007 b(ixo^s,:)=wctprim(ixo^s,mag(:))
6008 ! store full magnetic field B0+B1 in b
6009 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
6010 ! store velocity in a
6011 a(ixi^s,1:ndir)=wctprim(ixi^s,mom(1:ndir))
6012 ! -E = a x b
6013 call cross_product(ixi^l,ixo^l,a,b,axb)
6014 if(local_timestep) then
6015 do idir=1,3
6016 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
6017 enddo
6018 else
6019 axb(ixo^s,:)=axb(ixo^s,:)*qdt
6020 endif
6021 ! add -(vxB) dot J0 source term in energy equation
6022 ! where it is adding -J0 dot (vxB_1) when appropriate
6023 do idir=7-2*ndir,3
6024 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
6025 end do
6026 if(mhd_hall) then
6027 ! store hall velocity in a, only partial current is needed
6028 call mhd_getv_hall(wct,x,ixi^l,ixo^l,a,.true.)
6029 ! -E = a x b
6030 call cross_product(ixi^l,ixo^l,a,b,axb)
6031 if(local_timestep) then
6032 do idir=1,3
6033 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
6034 enddo
6035 else
6036 axb(ixo^s,:)=axb(ixo^s,:)*qdt
6037 endif
6038 ! add -(vxB) dot J0 source term in energy equation
6039 do idir=7-2*ndir,3
6040 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
6041 end do
6042 endif
6043 if(mhd_ambipolar_sts) then
6044 ! in STS variant of ambipolar, we added for split B the term div(B_1xE_ambi)
6045 ! hence needs to add J_0 dot E_ambi
6046 ! to get finally the term etaA (J_perpB)^/B^2-B_1 dot (curl Eambi)
6047 !reuse axb
6048 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,axb)
6049 ! source J0 * E
6050 do idir=sdim,3
6051 !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
6052 call multiplyambicoef(ixi^l,ixo^l,axb(ixi^s,idir),wct,x)
6053 w(ixo^s,e_)=w(ixo^s,e_)+qdt*axb(ixo^s,idir)*block%J0(ixo^s,idir)
6054 enddo
6055 endif
6056 end if
6057
6058
6059 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
6060
6061 end subroutine add_source_b0split
6062
6063 !> Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176
6064 subroutine add_source_semirelativistic(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6066 use mod_geometry
6067
6068 integer, intent(in) :: ixi^l, ixo^l
6069 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6070 double precision, intent(inout) :: w(ixi^s,1:nw)
6071 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
6072
6073 double precision :: e(ixi^s,1:3),curle(ixi^s,1:3),dive(ixi^s)
6074 integer :: idir, idirmin, ix^d
6075
6076 ! if ndir<3 the source is zero
6077 {^ifthreec
6078 {do ix^db=iximin^db,iximax^db\}
6079 ! E=Bxv
6080 e(ix^d,1)=w(ix^d,b2_)*wctprim(ix^d,m3_)-w(ix^d,b3_)*wctprim(ix^d,m2_)
6081 e(ix^d,2)=w(ix^d,b3_)*wctprim(ix^d,m1_)-w(ix^d,b1_)*wctprim(ix^d,m3_)
6082 e(ix^d,3)=w(ix^d,b1_)*wctprim(ix^d,m2_)-w(ix^d,b2_)*wctprim(ix^d,m1_)
6083 {end do\}
6084 call divvector(e,ixi^l,ixo^l,dive)
6085 ! curl E
6086 call curlvector(e,ixi^l,ixo^l,curle,idirmin,1,3)
6087 ! add source term in momentum equations (1/c0^2-1/c^2)(E divE - E x curlE)
6088 ! equation (26) and (27)
6089 {do ix^db=ixomin^db,ixomax^db\}
6090 w(ix^d,m1_)=w(ix^d,m1_)+qdt*(inv_squared_c0-inv_squared_c)*&
6091 (e(ix^d,1)*dive(ix^d)-e(ix^d,2)*curle(ix^d,3)+e(ix^d,3)*curle(ix^d,2))
6092 w(ix^d,m2_)=w(ix^d,m2_)+qdt*(inv_squared_c0-inv_squared_c)*&
6093 (e(ix^d,2)*dive(ix^d)-e(ix^d,3)*curle(ix^d,1)+e(ix^d,1)*curle(ix^d,3))
6094 w(ix^d,m3_)=w(ix^d,m3_)+qdt*(inv_squared_c0-inv_squared_c)*&
6095 (e(ix^d,3)*dive(ix^d)-e(ix^d,1)*curle(ix^d,2)+e(ix^d,2)*curle(ix^d,1) )
6096 {end do\}
6097 }
6098
6099 end subroutine add_source_semirelativistic
6100
6101 !> Source terms for internal energy version of MHD
6102 subroutine add_source_internal_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6104 use mod_geometry
6105
6106 integer, intent(in) :: ixi^l, ixo^l
6107 double precision, intent(in) :: qdt
6108 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6109 double precision, intent(inout) :: w(ixi^s,1:nw)
6110 double precision, intent(in) :: wctprim(ixi^s,1:nw)
6111
6112 double precision :: divv(ixi^s), tmp
6113 integer :: ix^d
6114
6115 if(slab_uniform) then
6116 if(nghostcells .gt. 2) then
6117 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,3)
6118 else
6119 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,2)
6120 end if
6121 else
6122 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv)
6123 end if
6124 {do ix^db=ixomin^db,ixomax^db\}
6125 tmp=w(ix^d,e_)
6126 w(ix^d,e_)=w(ix^d,e_)-qdt*wctprim(ix^d,p_)*divv(ix^d)
6127 if(w(ix^d,e_)<small_e) then
6128 w(ix^d,e_)=tmp
6129 end if
6130 {end do\}
6131 if(mhd_ambipolar_sts)then
6132 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
6133 end if
6134
6135 if(fix_small_values) then
6136 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'add_source_internal_e')
6137 end if
6138 end subroutine add_source_internal_e
6139
6140 !> Source terms for hydrodynamic energy version of MHD
6141 subroutine add_source_hydrodynamic_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6143 use mod_geometry
6144 use mod_usr_methods, only: usr_gravity
6145
6146 integer, intent(in) :: ixi^l, ixo^l
6147 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6148 double precision, intent(inout) :: w(ixi^s,1:nw)
6149 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
6150
6151 double precision :: b(ixi^s,3), j(ixi^s,3), jxb(ixi^s,3)
6152 double precision :: current(ixi^s,7-2*ndir:3)
6153 double precision :: bu(ixo^s,1:ndir), tmp(ixo^s), b2(ixo^s)
6154 double precision :: gravity_field(ixi^s,1:ndir), vaoc
6155 integer :: idir, idirmin, idims, ix^d
6156
6157 {^nothreed
6158 b=0.0d0
6159 do idir = 1, ndir
6160 b(ixo^s, idir) = wct(ixo^s,mag(idir))
6161 end do
6162
6163 if(slab_uniform)then
6164 ! get current in fourth order accuracy in Cartesian
6165 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
6166 else
6167 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6168 endif
6169
6170 j=0.0d0
6171 do idir=7-2*ndir,3
6172 j(ixo^s,idir)=current(ixo^s,idir)
6173 end do
6174
6175 ! get Lorentz force JxB
6176 call cross_product(ixi^l,ixo^l,j,b,jxb)
6177 }
6178 {^ifthreed
6179 if(slab_uniform)then
6180 ! get current in fourth order accuracy in Cartesian
6181 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,1,ndir,.true.)
6182 else
6183 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6184 endif
6185 ! get Lorentz force JxB
6186 call cross_product(ixi^l,ixo^l,current,wct(ixi^s,mag(1:ndir)),jxb)
6187 }
6188
6189 ! mhd_semirelativistic does not combine with mhd_hydrodynamic_e
6190 !!if(mhd_semirelativistic) then
6191 !! ! (v . nabla) v
6192 !! do idir=1,ndir
6193 !! do idims=1,ndim
6194 !! call gradient(wCTprim(ixI^S,mom(idir)),ixI^L,ixO^L,idims,J(ixI^S,idims))
6195 !! end do
6196 !! B(ixO^S,idir)=sum(wCTprim(ixO^S,mom(1:ndir))*J(ixO^S,1:ndir),dim=ndim+1)
6197 !! end do
6198 !! ! nabla p
6199 !! do idir=1,ndir
6200 !! call gradient(wCTprim(ixI^S,p_),ixI^L,ixO^L,idir,J(ixI^S,idir))
6201 !! end do
6202 !! if(mhd_gravity) then
6203 !! gravity_field=0.d0
6204 !! call usr_gravity(ixI^L,ixO^L,wCT,x,gravity_field(ixI^S,1:ndim))
6205 !! do idir=1,ndir
6206 !! 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)
6207 !! end do
6208 !! else
6209 !! do idir=1,ndir
6210 !! B(ixO^S,idir)=wCT(ixO^S,rho_)*B(ixO^S,idir)+J(ixO^S,idir)-JxB(ixO^S,idir)
6211 !! end do
6212 !! end if
6213 !! b2(ixO^S)=sum(wCT(ixO^S,mag(:))**2,dim=ndim+1)
6214 !! tmp(ixO^S)=sqrt(b2(ixO^S))
6215 !! where(tmp(ixO^S)>smalldouble)
6216 !! tmp(ixO^S)=1.d0/tmp(ixO^S)
6217 !! else where
6218 !! tmp(ixO^S)=0.d0
6219 !! end where
6220 !! ! unit vector of magnetic field
6221 !! do idir=1,ndir
6222 !! bu(ixO^S,idir)=wCT(ixO^S,mag(idir))*tmp(ixO^S)
6223 !! end do
6224 !! !b2(ixO^S)=b2(ixO^S)/w(ixO^S,rho_)*inv_squared_c
6225 !! !b2(ixO^S)=b2(ixO^S)/(1.d0+b2(ixO^S))
6226 !! {do ix^DB=ixOmin^DB,ixOmax^DB\}
6227 !! ! Va^2/c^2
6228 !! Vaoc=b2(ix^D)/w(ix^D,rho_)*inv_squared_c
6229 !! ! Va^2/c^2 / (1+Va^2/c^2)
6230 !! b2(ix^D)=Vaoc/(1.d0+Vaoc)
6231 !! {end do\}
6232 !! ! bu . F
6233 !! tmp(ixO^S)=sum(bu(ixO^S,1:ndir)*B(ixO^S,1:ndir),dim=ndim+1)
6234 !! ! Rempel 2017 ApJ 834, 10 equation (54)
6235 !! do idir=1,ndir
6236 !! J(ixO^S,idir)=b2(ixO^S)*(B(ixO^S,idir)-bu(ixO^S,idir)*tmp(ixO^S))
6237 !! end do
6238 !! !! Rempel 2017 ApJ 834, 10 equation (29) add SR force at momentum equation
6239 !! do idir=1,ndir
6240 !! w(ixO^S,mom(idir))=w(ixO^S,mom(idir))+qdt*J(ixO^S,idir)
6241 !! end do
6242 !! ! Rempel 2017 ApJ 834, 10 equation (30) add work of Lorentz force and SR force
6243 !! w(ixO^S,e_)=w(ixO^S,e_)+qdt*sum(wCTprim(ixO^S,mom(1:ndir))*&
6244 !! (JxB(ixO^S,1:ndir)+J(ixO^S,1:ndir)),dim=ndim+1)
6245 !!else
6246 ! add work of Lorentz force
6247 w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*jxb(ixo^s,1:ndir),dim=ndim+1)
6248 !!end if
6249
6250 if(mhd_ambipolar_sts)then
6251 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
6252 end if
6253
6254 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hydrodynamic_e')
6255
6256 end subroutine add_source_hydrodynamic_e
6257
6258 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
6259 !> each direction, non-conservative. Uses the generic Laplacian
6260 !> with fourth order central difference (on uniform cartesian) for the laplacian. Then the
6261 !> stencil is 5 (2 neighbours). NOTE: Unused subroutine!
6262 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
6264 use mod_usr_methods
6265 use mod_geometry
6266
6267 integer, intent(in) :: ixi^l, ixo^l
6268 double precision, intent(in) :: qdt
6269 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6270 double precision, intent(inout) :: w(ixi^s,1:nw)
6271
6272 integer :: ixa^l,idir,jdir,kdir,idirmin,idim
6273 double precision :: tmp(ixi^s),tmp2(ixi^s)
6274
6275 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6276 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6277 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
6278 double precision :: lapl_vec(ixi^s,1:ndir)
6279
6280 ! Calculating resistive sources involves one extra layer
6281 ! asking here for two, so Cartesian works with 4th order CD
6282 ixa^l=ixo^l^ladd2;
6283
6284 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6285 call mpistop("Error in add_source_res1: Non-conforming input limits")
6286
6287 ! Calculate current density and idirmin
6288 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6289
6290 if (mhd_eta>zero)then
6291 eta(ixa^s)=mhd_eta
6292 gradeta(ixo^s,1:ndim)=zero
6293 else
6294 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
6295 do idim=1,ndim
6296 call gradient(eta,ixi^l,ixo^l,idim,tmp)
6297 gradeta(ixo^s,idim)=tmp(ixo^s)
6298 end do
6299 end if
6300
6301 if(b0field) then
6302 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
6303 else
6304 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
6305 end if
6306
6307 call laplacian_of_vector(bf,ixi^l,ixo^l,lapl_vec)
6308
6309 do idir=1,ndir
6310 ! Multiply by eta to store eta*Laplace B_idir
6311 tmp(ixo^s)=lapl_vec(ixo^s,idir)*eta(ixo^s)
6312
6313 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
6314 if (mhd_eta<zero)then
6315 do jdir=1,ndim; do kdir=idirmin,3
6316 if (lvc(idir,jdir,kdir)/=0)then
6317 if (lvc(idir,jdir,kdir)==1)then
6318 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
6319 else
6320 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
6321 end if
6322 end if
6323 end do; end do
6324 end if
6325
6326 ! Add sources related to eta*laplB-grad(eta) x J to B and e
6327 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
6328 if(total_energy) then
6329 w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
6330 end if
6331 end do ! idir
6332
6333 if(mhd_energy) then
6334 ! de/dt+=eta*J**2
6335 w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
6336 end if
6337
6338 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
6339
6340 end subroutine add_source_res1
6341
6342 !> Add resistive source to w within ixO in an explicit fashion
6343 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
6344 subroutine add_source_res_exp(qdt,ixI^L,ixO^L,wCT,w,x)
6346 use mod_usr_methods
6347 use mod_geometry
6348
6349 integer, intent(in) :: ixi^l, ixo^l
6350 double precision, intent(in) :: qdt
6351 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6352 double precision, intent(inout) :: w(ixi^s,1:nw)
6353
6354 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6355 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
6356 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
6357 integer :: ixa^l,idir,idirmin,idirmin1
6358
6359 ixa^l=ixo^l^ladd2;
6360
6361 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6362 call mpistop("Error in add_source_res_exp: Non-conforming input limits")
6363
6364 ixa^l=ixo^l^ladd1;
6365 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
6366 ! Determine exact value of idirmin while doing the loop.
6367 call get_current(wct,ixi^l,ixa^l,idirmin,current)
6368
6369 tmpvec=zero
6370 if(mhd_eta>zero)then
6371 do idir=idirmin,3
6372 tmpvec(ixa^s,idir)=current(ixa^s,idir)*mhd_eta
6373 end do
6374 else
6375 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
6376 do idir=idirmin,3
6377 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
6378 end do
6379 end if
6380
6381 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
6382 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
6383 if(stagger_grid) then
6384 if(ndim==2.and.ndir==3) then
6385 ! if 2.5D
6386 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
6387 end if
6388 else
6389 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
6390 end if
6391
6392 if(mhd_energy) then
6393 if(mhd_eta>zero)then
6394 tmp(ixo^s)=qdt*mhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
6395 else
6396 tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
6397 end if
6398 if(total_energy) then
6399 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
6400 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6401 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6402 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6403 else
6404 ! add eta*J**2 source term in the internal energy equation
6405 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6406 end if
6407 end if
6408
6409 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res_exp')
6410 end subroutine add_source_res_exp
6411
6412
6413 !> Add ambipolar source to w within ixO in an explicit fashion
6414 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
6415 subroutine add_source_ambi_exp(qdt,ixI^L,ixO^L,wCT,w,x)
6417 use mod_usr_methods
6418 use mod_geometry
6419
6420 integer, intent(in) :: ixi^l, ixo^l
6421 double precision, intent(in) :: qdt
6422 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6423 double precision, intent(inout) :: w(ixi^s,1:nw)
6424
6425 double precision :: current(ixi^s,1:3),curlj(ixi^s,1:3)
6426 double precision :: tmpvec(ixi^s,1:3),tmp(ixi^s),btot2(ixi^s)
6427 integer :: ixa^l,idir,idirmin1
6428
6429 ixa^l=ixo^l^ladd2;
6430
6431 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6432 call mpistop("Error in add_source_ambi_exp: Non-conforming input limits")
6433
6434 ixa^l=ixo^l^ladd1;
6435 ! Calculate -J_perpB = (JxB)xB
6436 call mhd_get_jxbxb(wct,x,ixi^l,ixa^l,current)
6437
6438 tmpvec=current
6439 do idir=1,3
6440 !set electric field in tmpvec : E=nuA * jxbxb, where nuA=-etaA/rho^2
6441 !tmpvec(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
6442 call multiplyambicoef(ixi^l,ixa^l,tmpvec(ixi^s,idir),wct,x)
6443 end do
6444
6445 ! dB/dt= -curl(J_perpB*etaA), thus B_i=B_i-eps_ijk d_j Jeta_k
6446 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
6447 if(stagger_grid) then
6448 if(ndim==2.and.ndir==3) then
6449 ! if 2.5D
6450 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
6451 end if
6452 else
6453 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
6454 end if
6455
6456 if(mhd_energy) then
6457 ! compute ambipolar heating term: nuA* J_perpB^2/ B^2
6458 ! avoiding nulls here
6459 btot2(ixa^s)=mhd_mag_en_all(wct,ixi^l,ixa^l)
6460 where (btot2(ixa^s)>smalldouble )
6461 tmp(ixa^s) = sum(current(ixa^s,1:3)**2,dim=ndim+1) / btot2(ixa^s)
6462 elsewhere
6463 tmp(ixa^s) = zero
6464 endwhere
6465 ! multiply with nuA where nuA=-etaA/rho^2
6466 call multiplyambicoef(ixi^l,ixa^l,tmp,wct,x)
6467 ! compensate - sign and add timestep
6468 tmp(ixo^s)=-qdt*tmp(ixo^s)
6469 if(total_energy) then
6470 ! de/dt= +div(B x E_ambi) = eta J^2 - B dot curl(eta J)
6471 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6472 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6473 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6474 else
6475 ! add eta*J**2 source term in the internal or hydrodynamic energy equation
6476 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6477 end if
6478 end if
6479
6480 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_ambi_exp')
6481 end subroutine add_source_ambi_exp
6482
6483 !> Add Hyper-resistive source to w within ixO
6484 !> Uses 9 point stencil (4 neighbours) in each direction.
6485 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
6487 use mod_geometry
6488
6489 integer, intent(in) :: ixi^l, ixo^l
6490 double precision, intent(in) :: qdt
6491 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6492 double precision, intent(inout) :: w(ixi^s,1:nw)
6493 !.. local ..
6494 double precision :: current(ixi^s,7-2*ndir:3)
6495 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
6496 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
6497
6498 ixa^l=ixo^l^ladd3;
6499 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6500 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
6501
6502 call get_current(wct,ixi^l,ixa^l,idirmin,current)
6503 tmpvec(ixa^s,1:ndir)=zero
6504 do jdir=idirmin,3
6505 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
6506 end do
6507
6508 ixa^l=ixo^l^ladd2;
6509 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6510
6511 ixa^l=ixo^l^ladd1;
6512 tmpvec(ixa^s,1:ndir)=zero
6513 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
6514 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mhd_eta_hyper
6515
6516 ixa^l=ixo^l;
6517 tmpvec2(ixa^s,1:ndir)=zero
6518 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6519
6520 do idir=1,ndir
6521 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
6522 end do
6523
6524 if(total_energy) then
6525 ! de/dt= +div(B x Ehyper)
6526 ixa^l=ixo^l^ladd1;
6527 tmpvec2(ixa^s,1:ndir)=zero
6528 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
6529 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
6530 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
6531 end do; end do; end do
6532 tmp(ixo^s)=zero
6533 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
6534 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
6535 end if
6536
6537 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
6538
6539 end subroutine add_source_hyperres
6540
6541 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
6542 ! Add divB related sources to w within ixO
6543 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
6544 ! giving the EGLM-MHD scheme or GLM-MHD scheme
6546 use mod_geometry
6547
6548 integer, intent(in) :: ixi^l, ixo^l
6549 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6550 double precision, intent(inout) :: w(ixi^s,1:nw)
6551
6552 double precision:: divb(ixi^s), gradpsi(ixi^s), ba(ixo^s,1:ndir)
6553 integer :: idir
6554
6555
6556 ! dPsi/dt = - Ch^2/Cp^2 Psi
6557 if (mhd_glm_alpha < zero) then
6558 w(ixo^s,psi_) = abs(mhd_glm_alpha)*wct(ixo^s,psi_)
6559 else
6560 ! implicit update of Psi variable
6561 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
6562 if(slab_uniform) then
6563 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
6564 else
6565 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
6566 end if
6567 end if
6568
6569 if(mhd_glm_extended) then
6570 if(b0field) then
6571 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
6572 else
6573 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))
6574 end if
6575 ! gradient of Psi
6576 if(total_energy) then
6577 do idir=1,ndim
6578 select case(typegrad)
6579 case("central")
6580 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6581 case("limited")
6582 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6583 end select
6584 ! e = e -qdt (b . grad(Psi))
6585 w(ixo^s,e_) = w(ixo^s,e_)-qdt*ba(ixo^s,idir)*gradpsi(ixo^s)
6586 end do
6587 end if
6588
6589 ! We calculate now div B
6590 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6591
6592 ! m = m - qdt b div b
6593 do idir=1,ndir
6594 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*ba(ixo^s,idir)*divb(ixo^s)
6595 end do
6596 end if
6597
6598 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
6599
6600 end subroutine add_source_glm
6601
6602 !> Add divB related sources to w within ixO corresponding to Powel
6603 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
6605
6606 integer, intent(in) :: ixi^l, ixo^l
6607 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6608 double precision, intent(inout) :: w(ixi^s,1:nw)
6609
6610 double precision :: divb(ixi^s), ba(1:ndir)
6611 integer :: idir, ix^d
6612
6613 ! calculate div B
6614 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6615
6616 if(b0field) then
6617 {do ix^db=ixomin^db,ixomax^db\}
6618 ! b = b - qdt v * div b
6619 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6620 ! m = m - qdt b div b
6621 ^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)\
6622 if (total_energy) then
6623 ! e = e - qdt (v . b) * div b
6624 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)
6625 end if
6626 {end do\}
6627 else
6628 {do ix^db=ixomin^db,ixomax^db\}
6629 ! b = b - qdt v * div b
6630 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6631 ! m = m - qdt b div b
6632 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)-qdt*wct(ix^d,b^c_)*divb(ix^d)\
6633 if (total_energy) then
6634 ! e = e - qdt (v . b) * div b
6635 w(ix^d,e_)=w(ix^d,e_)-qdt*(^c&wct(ix^d,m^c_)*wct(ix^d,b^c_)+)*divb(ix^d)
6636 end if
6637 {end do\}
6638 end if
6639
6640 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
6641
6642 end subroutine add_source_powel
6643
6644 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
6645 ! Add divB related sources to w within ixO
6646 ! corresponding to Janhunen, just the term in the induction equation.
6648
6649 integer, intent(in) :: ixi^l, ixo^l
6650 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6651 double precision, intent(inout) :: w(ixi^s,1:nw)
6652
6653 double precision :: divb(ixi^s)
6654 integer :: idir, ix^d
6655
6656 ! calculate div B
6657 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6658
6659 {do ix^db=ixomin^db,ixomax^db\}
6660 ! b = b - qdt v * div b
6661 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6662 {end do\}
6663
6664 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
6665
6666 end subroutine add_source_janhunen
6667
6668 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
6669 ! Add Linde's divB related sources to wnew within ixO
6671 use mod_geometry
6672
6673 integer, intent(in) :: ixi^l, ixo^l
6674 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6675 double precision, intent(inout) :: w(ixi^s,1:nw)
6676
6677 double precision :: divb(ixi^s),graddivb(ixi^s)
6678 integer :: idim, idir, ixp^l, i^d, iside
6679 logical, dimension(-1:1^D&) :: leveljump
6680
6681 ! Calculate div B
6682 ixp^l=ixo^l^ladd1;
6683 call get_divb(wct,ixi^l,ixp^l,divb, mhd_divb_nth)
6684
6685 ! for AMR stability, retreat one cell layer from the boarders of level jump
6686 {do i^db=-1,1\}
6687 if(i^d==0|.and.) cycle
6688 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
6689 leveljump(i^d)=.true.
6690 else
6691 leveljump(i^d)=.false.
6692 end if
6693 {end do\}
6694
6695 ixp^l=ixo^l;
6696 do idim=1,ndim
6697 select case(idim)
6698 {case(^d)
6699 do iside=1,2
6700 i^dd=kr(^dd,^d)*(2*iside-3);
6701 if (leveljump(i^dd)) then
6702 if (iside==1) then
6703 ixpmin^d=ixomin^d-i^d
6704 else
6705 ixpmax^d=ixomax^d-i^d
6706 end if
6707 end if
6708 end do
6709 \}
6710 end select
6711 end do
6712
6713 ! Add Linde's diffusive terms
6714 do idim=1,ndim
6715 ! Calculate grad_idim(divb)
6716 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
6717
6718 {do i^db=ixpmin^db,ixpmax^db\}
6719 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
6720 graddivb(i^d)=graddivb(i^d)*divbdiff/(^d&1.0d0/block%ds({i^d},^d)**2+)
6721
6722 w(i^d,mag(idim))=w(i^d,mag(idim))+graddivb(i^d)
6723
6724 if (typedivbdiff=='all' .and. total_energy) then
6725 ! e += B_idim*eta*grad_idim(divb)
6726 w(i^d,e_)=w(i^d,e_)+wct(i^d,mag(idim))*graddivb(i^d)
6727 end if
6728 {end do\}
6729 end do
6730
6731 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
6732
6733 end subroutine add_source_linde
6734
6735 !> get dimensionless div B = |divB| * volume / area / |B|
6736 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
6737
6739
6740 integer, intent(in) :: ixi^l, ixo^l
6741 double precision, intent(in) :: w(ixi^s,1:nw)
6742 double precision :: divb(ixi^s), dsurface(ixi^s)
6743
6744 double precision :: invb(ixo^s)
6745 integer :: ixa^l,idims
6746
6747 call get_divb(w,ixi^l,ixo^l,divb)
6748 invb(ixo^s)=sqrt(mhd_mag_en_all(w,ixi^l,ixo^l))
6749 where(invb(ixo^s)/=0.d0)
6750 invb(ixo^s)=1.d0/invb(ixo^s)
6751 end where
6752 if(slab_uniform) then
6753 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
6754 else
6755 ixamin^d=ixomin^d-1;
6756 ixamax^d=ixomax^d-1;
6757 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
6758 do idims=1,ndim
6759 ixa^l=ixo^l-kr(idims,^d);
6760 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
6761 end do
6762 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
6763 block%dvolume(ixo^s)/dsurface(ixo^s)
6764 end if
6765
6766 end subroutine get_normalized_divb
6767
6768 !> Calculate idirmin and the idirmin:3 components of the common current array
6769 !> make sure that dxlevel(^D) is set correctly.
6770 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
6772 use mod_geometry
6773
6774 integer, intent(in) :: ixo^l, ixi^l
6775 double precision, intent(in) :: w(ixi^s,1:nw)
6776 integer, intent(out) :: idirmin
6777
6778 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6779 double precision :: current(ixi^s,7-2*ndir:3)
6780 integer :: idir, idirmin0
6781
6782 idirmin0 = 7-2*ndir
6783
6784 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
6785
6786 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
6787 block%J0(ixo^s,idirmin0:3)
6788 end subroutine get_current
6789
6790 !> If resistivity is not zero, check diffusion time limit for dt and similar other effects
6791 subroutine mhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
6793 use mod_usr_methods
6795 use mod_gravity, only: gravity_get_dt
6796 use mod_cak_force, only: cak_get_dt
6797 use mod_fld, only: fld_radforce_get_dt
6798
6799 integer, intent(in) :: ixi^l, ixo^l
6800 double precision, intent(inout) :: dtnew
6801 double precision, intent(in) :: dx^d
6802 double precision, intent(in) :: wprim(ixi^s,1:nw)
6803 double precision, intent(in) :: x(ixi^s,1:ndim)
6804
6805 double precision :: dxarr(ndim)
6806 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6807 integer :: idirmin,idim
6808
6809 dtnew = bigdouble
6810
6811 ^d&dxarr(^d)=dx^d;
6812 if (mhd_eta>zero)then
6813 if(slab_uniform) then
6814 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mhd_eta
6815 else
6816 dtnew=dtdiffpar*minval(block%ds(ixo^s,1:ndim))**2/mhd_eta
6817 end if
6818 else if (mhd_eta<zero)then
6819 call get_current(wprim,ixi^l,ixo^l,idirmin,current)
6820 call usr_special_resistivity(wprim,ixi^l,ixo^l,idirmin,x,current,eta)
6821 dtnew=bigdouble
6822 do idim=1,ndim
6823 if(slab_uniform) then
6824 dtnew=min(dtnew,&
6825 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
6826 else
6827 dtnew=min(dtnew,&
6828 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
6829 end if
6830 end do
6831 end if
6832
6833 if(mhd_eta_hyper>zero) then
6834 if(slab_uniform) then
6835 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mhd_eta_hyper,dtnew)
6836 else
6837 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mhd_eta_hyper,dtnew)
6838 end if
6839 end if
6840
6841 if(mhd_viscosity) then
6842 call viscosity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6843 end if
6844
6845 if(mhd_gravity) then
6846 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6847 end if
6848
6849 if(mhd_ambipolar_exp) then
6850 dtnew=min(dtdiffpar*get_ambipolar_dt(wprim,ixi^l,ixo^l,dx^d,x),dtnew)
6851 endif
6852
6853 if (mhd_cak_force) then
6854 call cak_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6855 end if
6856
6857 if(mhd_radiation_fld) then
6858 call fld_radforce_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x,fld_fl)
6859 endif
6860
6861 end subroutine mhd_get_dt
6862
6863 !> Wrappers for the FLD implicit (MG diffusion) hooks: phys_implicit_update /
6864 !> phys_evaluate_implicit have fixed interfaces with no fluid argument, so
6865 !> these inject the module's fld_fl object into the threaded fld routines.
6866 subroutine mhd_fld_implicit_update(dtfactor,qdt,qtC,psa,psb)
6868 use mod_fld, only: fld_implicit_update
6869 type(state), target :: psa(max_blocks)
6870 type(state), target :: psb(max_blocks)
6871 double precision, intent(in) :: qdt
6872 double precision, intent(in) :: qtc
6873 double precision, intent(in) :: dtfactor
6874
6875 call fld_implicit_update(dtfactor,qdt,qtc,psa,psb,fld_fl)
6876 end subroutine mhd_fld_implicit_update
6877
6878 subroutine mhd_fld_evaluate_implicit(qtC,psa)
6881 type(state), target :: psa(max_blocks)
6882 double precision, intent(in) :: qtc
6883
6884 call fld_evaluate_implicit(qtc,psa,fld_fl)
6885 end subroutine mhd_fld_evaluate_implicit
6886
6887 ! Add geometrical source terms to w
6888 ! Geometric sources to momentum and induction
6889 ! for the regular case, not semi-relativistic, nor any splitting active
6890 ! but possibly no energy equation at all
6891 ! NOTE: Hall terms in induction not handled yet
6892 subroutine mhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6894 use mod_geometry
6897
6898 integer, intent(in) :: ixi^l, ixo^l
6899 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6900 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6901
6902 double precision :: adiabs(ixi^s), gammas(ixi^s)
6903 double precision :: tmp,tmp1,invr,cot
6904 integer :: ix^d
6905 integer :: mr_,mphi_ ! Polar var. names
6906 integer :: br_,bphi_
6907
6908 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6909 br_=mag(1); bphi_=mag(1)-1+phi_
6910
6911 if(.not.mhd_energy) then
6912 if(associated(usr_set_adiab)) then
6913 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6914 else
6915 adiabs=mhd_adiab
6916 end if
6917 if(associated(usr_set_gamma)) then
6918 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6919 else
6920 gammas=eos%gamma
6921 end if
6922 end if
6923
6924 select case (coordinate)
6925 case (cylindrical)
6926 {do ix^db=ixomin^db,ixomax^db\}
6927 ! include dt in invr, invr is always used with qdt
6928 if(local_timestep) then
6929 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6930 else
6931 invr=qdt/x(ix^d,1)
6932 end if
6933 if(mhd_energy) then
6934 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6935 else
6936 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6937 end if
6938 if(phi_>0) then
6939 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6940 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6941 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6942 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6943 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6944 if(.not.stagger_grid) then
6945 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6946 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6947 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6948 end if
6949 else
6950 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6951 end if
6952 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6953 {end do\}
6954 case (spherical)
6955 {do ix^db=ixomin^db,ixomax^db\}
6956 ! include dt in invr, invr is always used with qdt
6957 if(local_timestep) then
6958 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6959 else
6960 invr=qdt/x(ix^d,1)
6961 end if
6962 if(mhd_energy) then
6963 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6964 else
6965 tmp1=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6966 end if
6967 ! m1
6968 {^ifonec
6969 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6970 }
6971 {^noonec
6972 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6973 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6974 }
6975 ! b1
6976 if(mhd_glm) then
6977 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6978 end if
6979 {^ifoned
6980 cot=0.d0
6981 }
6982 {^nooned
6983 cot=1.d0/tan(x(ix^d,2))
6984 }
6985 {^iftwoc
6986 ! m2
6987 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6988 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6989 ! b2
6990 if(.not.stagger_grid) then
6991 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6992 if(mhd_glm) then
6993 tmp=tmp+wprim(ix^d,psi_)*cot
6994 end if
6995 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6996 end if
6997 }
6998 {^ifthreec
6999 ! m2
7000 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7001 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
7002 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
7003 ! b2
7004 if(.not.stagger_grid) then
7005 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7006 if(mhd_glm) then
7007 tmp=tmp+wprim(ix^d,psi_)*cot
7008 end if
7009 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
7010 end if
7011 ! m3
7012 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7013 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7014 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7015 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7016 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
7017 ! b3
7018 if(.not.stagger_grid) then
7019 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7020 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7021 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7022 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7023 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7024 end if
7025 }
7026 {end do\}
7027 end select
7028
7029 if (mhd_rotating_frame) then
7030 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7031 end if
7032
7033 end subroutine mhd_add_source_geom
7034
7035 ! Add geometrical source terms to w
7036 ! Geometric sources to momentum and induction
7037 ! for the semi-relativistic, hence no splitting active
7038 ! but possibly no energy equation at all
7039 ! NOTE: Hall terms in induction not handled yet
7040 subroutine mhd_add_source_geom_semirelati(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
7042 use mod_geometry
7045
7046 integer, intent(in) :: ixi^l, ixo^l
7047 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
7048 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
7049
7050 double precision :: adiabs(ixi^s), gammas(ixi^s)
7051 double precision :: tmp,tmp1,tmp2,invr,cot,ef(ixo^s,1:ndir)
7052 integer :: ix^d
7053 integer :: mr_,mphi_ ! Polar var. names
7054 integer :: br_,bphi_
7055
7056 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
7057 br_=mag(1); bphi_=mag(1)-1+phi_
7058
7059 if(.not.mhd_energy) then
7060 if(associated(usr_set_adiab)) then
7061 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
7062 else
7063 adiabs=mhd_adiab
7064 end if
7065 if(associated(usr_set_gamma)) then
7066 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
7067 else
7068 gammas=eos%gamma
7069 end if
7070 end if
7071
7072 select case (coordinate)
7073 case (cylindrical)
7074 {do ix^db=ixomin^db,ixomax^db\}
7075 ! include dt in invr, invr is always used with qdt
7076 if(local_timestep) then
7077 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7078 else
7079 invr=qdt/x(ix^d,1)
7080 end if
7081 if(mhd_energy) then
7082 tmp=wprim(ix^d,p_)
7083 else
7084 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)
7085 end if
7086 ! E=Bxv
7087 {^ifthreec
7088 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
7089 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
7090 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7091 }
7092 {^iftwoc
7093 ef(ix^d,1)=zero
7094 ! store e3 in e2 to count e3 when ^C is from 1 to 2
7095 ef(ix^d,2)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7096 }
7097 {^ifonec
7098 ef(ix^d,1)=zero
7099 }
7100 if(phi_>0) then
7101 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+&
7102 half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c) -&
7103 wprim(ix^d,bphi_)**2+wprim(ix^d,rho_)*wprim(ix^d,mphi_)**2)
7104 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
7105 -wprim(ix^d,rho_)*wprim(ix^d,mphi_)*wprim(ix^d,mr_) &
7106 +wprim(ix^d,bphi_)*wprim(ix^d,br_)+ef(ix^d,phi_)*ef(ix^d,1)*inv_squared_c)
7107 if(.not.stagger_grid) then
7108 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7109 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
7110 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
7111 end if
7112 else
7113 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+half*((^c&wprim(ix^d,b^c_)**2+)+&
7114 (^c&ef(ix^d,^c)**2+)*inv_squared_c))
7115 end if
7116 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
7117 {end do\}
7118 case (spherical)
7119 {do ix^db=ixomin^db,ixomax^db\}
7120 ! include dt in invr, invr is always used with qdt
7121 if(local_timestep) then
7122 invr=block%dt(ix^d)*dtfactor/x(ix^d,1)
7123 else
7124 invr=qdt/x(ix^d,1)
7125 end if
7126 ! E=Bxv
7127 {^ifthreec
7128 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
7129 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
7130 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7131 }
7132 {^iftwoc
7133 ! store e3 in e1 to count e3 when ^C is from 1 to 2
7134 ef(ix^d,1)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7135 ef(ix^d,2)=zero
7136 }
7137 {^ifonec
7138 ef(ix^d,1)=zero
7139 }
7140 if(mhd_energy) then
7141 tmp1=wprim(ix^d,p_)+half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c)
7142 else
7143 tmp1=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c)
7144 end if
7145 ! m1
7146 {^ifonec
7147 w(ix^d,m1_)=w(ix^d,m1_)+two*tmp1*invr
7148 }
7149 {^noonec
7150 w(ix^d,m1_)=w(ix^d,m1_)+invr*&
7151 (two*tmp1+(^ce&wprim(ix^d,rho_)*wprim(ix^d,m^ce_)**2-&
7152 wprim(ix^d,b^ce_)**2-ef(ix^d,^ce)**2*inv_squared_c+))
7153 }
7154 ! b1
7155 if(mhd_glm) then
7156 w(ix^d,b1_)=w(ix^d,b1_)+invr*2.0d0*wprim(ix^d,psi_)
7157 end if
7158 {^ifoned
7159 cot=0.d0
7160 }
7161 {^nooned
7162 cot=1.d0/tan(x(ix^d,2))
7163 }
7164 {^iftwoc
7165 ! m2
7166 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_)&
7167 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c)
7168 ! b2
7169 if(.not.stagger_grid) then
7170 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7171 if(mhd_glm) then
7172 tmp=tmp+wprim(ix^d,psi_)*cot
7173 end if
7174 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
7175 end if
7176 }
7177
7178 {^ifthreec
7179 ! m2
7180 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_) &
7181 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c&
7182 +(wprim(ix^d,rho_)*wprim(ix^d,m3_)**2&
7183 -wprim(ix^d,b3_)**2-ef(ix^d,3)**2*inv_squared_c)*cot)
7184 ! b2
7185 if(.not.stagger_grid) then
7186 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7187 if(mhd_glm) then
7188 tmp=tmp+wprim(ix^d,psi_)*cot
7189 end if
7190 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
7191 end if
7192 ! m3
7193 w(ix^d,m3_)=w(ix^d,m3_)+invr*&
7194 (-wprim(ix^d,m3_)*wprim(ix^d,m1_)*wprim(ix^d,rho_) &
7195 +wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7196 +ef(ix^d,3)*ef(ix^d,1)*inv_squared_c&
7197 +(-wprim(ix^d,m2_)*wprim(ix^d,m3_)*wprim(ix^d,rho_) &
7198 +wprim(ix^d,b2_)*wprim(ix^d,b3_)&
7199 +ef(ix^d,2)*ef(ix^d,3)*inv_squared_c)*cot)
7200 ! b3
7201 if(.not.stagger_grid) then
7202 w(ix^d,b3_)=w(ix^d,b3_)+invr*&
7203 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7204 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7205 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7206 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7207 end if
7208 }
7209 {end do\}
7210 end select
7211
7212 if (mhd_rotating_frame) then
7213 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7214 end if
7215
7216 end subroutine mhd_add_source_geom_semirelati
7217
7218 ! Add geometrical source terms to w
7219 ! Geometric sources to momentum and induction
7220 ! for those cases where any kind of splitting (B0field or has_equi_rho_and_p) is active
7221 ! This implies that there is an energy equation included for sure
7222 ! B0field impacts terms in induction equation and geometric sources for them
7223 ! both flags affect the terms in momentum equation, in three variants (TF, TT, FT)
7224 ! NOTE: Hall terms in induction not handled yet
7225 subroutine mhd_add_source_geom_split(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
7227 use mod_geometry
7230
7231 integer, intent(in) :: ixi^l, ixo^l
7232 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
7233 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
7234
7235 double precision :: tmp,tmp1,tmp2,invr,cot
7236 double precision :: adiabs(ixi^s), gammas(ixi^s)
7237 integer :: ix^d
7238 integer :: mr_,mphi_ ! Polar var. names
7239 integer :: br_,bphi_
7240
7241 if(.not.mhd_energy) then
7242 if(associated(usr_set_adiab)) then
7243 call usr_set_adiab(wprim,x,ixi^l,ixo^l,adiabs)
7244 else
7245 adiabs=mhd_adiab
7246 end if
7247 if(associated(usr_set_gamma)) then
7248 call usr_set_gamma(wprim,x,ixi^l,ixo^l,gammas)
7249 else
7250 gammas=eos%gamma
7251 end if
7252 end if
7253
7254 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
7255 br_=mag(1); bphi_=mag(1)-1+phi_
7256
7257
7258 select case (coordinate)
7259 case (cylindrical)
7260 {do ix^db=ixomin^db,ixomax^db\}
7261 ! include dt in invr, invr is always used with qdt
7262 if(local_timestep) then
7263 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7264 else
7265 invr=qdt/x(ix^d,1)
7266 end if
7267 if(mhd_energy) then
7268 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
7269 else
7270 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
7271 end if
7272 if(b0field) tmp=tmp+(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
7273 if(phi_>0) then
7274 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
7275 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
7276 if(b0field) then
7277 w(ix^d,mr_)=w(ix^d,mr_)+invr*(-block%B0(ix^d,phi_,0)*wprim(ix^d,bphi_)-wprim(ix^d,bphi_)*block%B0(ix^d,phi_,0))
7278 endif
7279 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
7280 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
7281 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
7282 if(b0field) then
7283 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(block%B0(ix^d,phi_,0)*wprim(ix^d,br_)+wprim(ix^d,bphi_)*block%B0(ix^d,r_,0))
7284 endif
7285 if(.not.stagger_grid) then
7286 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7287 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
7288 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
7289 if(b0field) then
7290 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7291 (block%B0(ix^d,phi_,0)*wprim(ix^d,mr_) &
7292 -block%B0(ix^d,r_,0)*wprim(ix^d,mphi_))
7293 endif
7294 end if
7295 else
7296 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
7297 end if
7298 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
7299 {end do\}
7300 case (spherical)
7301 {do ix^db=ixomin^db,ixomax^db\}
7302 ! include dt in invr, invr is always used with qdt
7303 if(local_timestep) then
7304 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7305 else
7306 invr=qdt/x(ix^d,1)
7307 end if
7308 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
7309 if(b0field) tmp2=(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
7310 ! m1
7311 {^ifonec
7312 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
7313 if(b0field) w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp2*invr
7314 }
7315 {^noonec
7316 if(b0field) then
7317 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
7318 (two*(tmp1+tmp2)+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+)- &
7319 (^ce&two*block%B0(ix^d,^ce,0)*wprim(ix^d,b^ce_)+))
7320 else
7321 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
7322 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
7323 end if
7324 }
7325 ! b1
7326 if(mhd_glm) then
7327 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
7328 end if
7329 {^ifoned
7330 cot=0.d0
7331 }
7332 {^nooned
7333 cot=1.d0/tan(x(ix^d,2))
7334 }
7335 {^iftwoc
7336 ! m2
7337 if(b0field) then
7338 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7339 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
7340 +wprim(ix^d,b1_)*block%B0(ix^d,2,0))
7341 else
7342 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7343 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
7344 end if
7345 ! b2
7346 if(.not.stagger_grid) then
7347 if(b0field) then
7348 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
7349 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
7350 else
7351 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7352 end if
7353 if(mhd_glm) then
7354 tmp=tmp+wprim(ix^d,psi_)*cot
7355 end if
7356 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
7357 end if
7358 }
7359 {^ifthreec
7360 ! m2
7361 if(b0field) then
7362 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7363 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
7364 +wprim(ix^d,b1_)*block%B0(ix^d,2,0)&
7365 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2-two*block%B0(ix^d,3,0)*wprim(ix^d,b3_))*cot)
7366 else
7367 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7368 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
7369 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
7370 end if
7371 ! b2
7372 if(.not.stagger_grid) then
7373 if(b0field) then
7374 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
7375 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
7376 else
7377 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7378 end if
7379 if(mhd_glm) then
7380 tmp=tmp+wprim(ix^d,psi_)*cot
7381 end if
7382 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
7383 end if
7384 ! m3
7385 if(b0field) then
7386 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7387 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7388 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7389 +block%B0(ix^d,1,0)*wprim(ix^d,b3_) &
7390 +wprim(ix^d,b1_)*block%B0(ix^d,3,0) &
7391 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7392 -wprim(ix^d,b2_)*wprim(ix^d,b3_) &
7393 +block%B0(ix^d,2,0)*wprim(ix^d,b3_) &
7394 +wprim(ix^d,b2_)*block%B0(ix^d,3,0))*cot)
7395 else
7396 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7397 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7398 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7399 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7400 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
7401 end if
7402 ! b3
7403 if(.not.stagger_grid) then
7404 if(b0field) then
7405 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7406 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7407 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7408 +wprim(ix^d,m1_)*block%B0(ix^d,3,0) &
7409 -wprim(ix^d,m3_)*block%B0(ix^d,1,0) &
7410 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7411 -wprim(ix^d,m2_)*wprim(ix^d,b3_) &
7412 +wprim(ix^d,m3_)*block%B0(ix^d,2,0) &
7413 -wprim(ix^d,m2_)*block%B0(ix^d,3,0))*cot)
7414 else
7415 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7416 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7417 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7418 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7419 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7420 end if
7421 end if
7422 }
7423 {end do\}
7424 end select
7425
7426 if (mhd_rotating_frame) then
7427 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7428 end if
7429
7430 end subroutine mhd_add_source_geom_split
7431
7432 !> Compute 2 times total magnetic energy
7433 function mhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
7435 integer, intent(in) :: ixi^l, ixo^l
7436 double precision, intent(in) :: w(ixi^s, nw)
7437 double precision :: mge(ixo^s)
7438
7439 if (b0field) then
7440 mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
7441 else
7442 mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
7443 end if
7444 end function mhd_mag_en_all
7445
7446 subroutine mhd_getv_hall(w,x,ixI^L,ixO^L,vHall,partial)
7448 use mod_geometry
7449
7450 integer, intent(in) :: ixi^l, ixo^l
7451 double precision, intent(in) :: w(ixi^s,nw)
7452 double precision, intent(in) :: x(ixi^s,1:ndim)
7453 double precision, intent(inout) :: vhall(ixi^s,1:ndir)
7454 logical, intent(in), optional :: partial
7455
7456 double precision :: current(ixi^s,7-2*ndir:3)
7457 double precision :: rho(ixi^s)
7458 integer :: idir, idirmin, ix^d
7459 logical :: use_partial
7460
7461 use_partial=.false.
7462 if(present(partial)) use_partial=partial
7463 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
7464 if(.not.use_partial)then
7465 ! Calculate current density and idirmin, including J0 when split
7466 call get_current(w,ixi^l,ixo^l,idirmin,current)
7467 else
7468 if(slab_uniform) then
7469 ! fourth order CD in cartesian
7470 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
7471 else
7472 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir)
7473 endif
7474 endif
7475 do idir = idirmin, ndir
7476 {do ix^db=ixomin^db,ixomax^db\}
7477 vhall(ix^d,idir)=-mhd_etah*current(ix^d,idir)/rho(ix^d)
7478 {end do\}
7479 end do
7480
7481 end subroutine mhd_getv_hall
7482
7483 subroutine mhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
7485 use mod_usr_methods
7486 integer, intent(in) :: ixi^l, ixo^l, idir
7487 double precision, intent(in) :: qt
7488 double precision, intent(inout) :: wlc(ixi^s,1:nw), wrc(ixi^s,1:nw)
7489 double precision, intent(inout) :: wlp(ixi^s,1:nw), wrp(ixi^s,1:nw)
7490 type(state) :: s
7491
7492 double precision :: db(ixo^s), dpsi(ixo^s)
7493 integer :: ix^d
7494
7495 if(stagger_grid) then
7496 {do ix^db=ixomin^db,ixomax^db\}
7497 wlc(ix^d,mag(idir))=s%ws(ix^d,idir)
7498 wrc(ix^d,mag(idir))=s%ws(ix^d,idir)
7499 wlp(ix^d,mag(idir))=s%ws(ix^d,idir)
7500 wrp(ix^d,mag(idir))=s%ws(ix^d,idir)
7501 {end do\}
7502 else
7503 ! Solve the Riemann problem for the linear 2x2 system for normal
7504 ! B-field and GLM_Psi according to Dedner 2002:
7505 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
7506 ! Gives the Riemann solution on the interface
7507 ! for the normal B component and Psi in the GLM-MHD system.
7508 ! 23/04/2013 Oliver Porth
7509 {do ix^db=ixomin^db,ixomax^db\}
7510 db(ix^d)=wrp(ix^d,mag(idir))-wlp(ix^d,mag(idir))
7511 dpsi(ix^d)=wrp(ix^d,psi_)-wlp(ix^d,psi_)
7512 wlp(ix^d,mag(idir))=half*(wrp(ix^d,mag(idir))+wlp(ix^d,mag(idir))-dpsi(ix^d)/cmax_global)
7513 wlp(ix^d,psi_)=half*(wrp(ix^d,psi_)+wlp(ix^d,psi_)-db(ix^d)*cmax_global)
7514 wrp(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7515 wrp(ix^d,psi_)=wlp(ix^d,psi_)
7516 if(total_energy) then
7517 wrc(ix^d,e_)=wrc(ix^d,e_)-half*wrc(ix^d,mag(idir))**2
7518 wlc(ix^d,e_)=wlc(ix^d,e_)-half*wlc(ix^d,mag(idir))**2
7519 end if
7520 wrc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7521 wrc(ix^d,psi_)=wlp(ix^d,psi_)
7522 wlc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7523 wlc(ix^d,psi_)=wlp(ix^d,psi_)
7524 ! modify total energy according to the change of magnetic field
7525 if(total_energy) then
7526 wrc(ix^d,e_)=wrc(ix^d,e_)+half*wrc(ix^d,mag(idir))**2
7527 wlc(ix^d,e_)=wlc(ix^d,e_)+half*wlc(ix^d,mag(idir))**2
7528 end if
7529 {end do\}
7530 end if
7531
7532 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
7533
7534 end subroutine mhd_modify_wlr
7535
7536 subroutine mhd_boundary_adjust(igrid,psb)
7538 integer, intent(in) :: igrid
7539 type(state), target :: psb(max_blocks)
7540
7541 integer :: ib, idims, iside, ixo^l, i^d
7542
7543 block=>ps(igrid)
7544 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7545 do idims=1,ndim
7546 ! to avoid using as yet unknown corner info in more than 1D, we
7547 ! fill only interior mesh ranges of the ghost cell ranges at first,
7548 ! and progressively enlarge the ranges to include corners later
7549 do iside=1,2
7550 i^d=kr(^d,idims)*(2*iside-3);
7551 if (neighbor_type(i^d,igrid)/=1) cycle
7552 ib=(idims-1)*2+iside
7553 if(.not.boundary_divbfix(ib)) cycle
7554 if(any(typeboundary(:,ib)==bc_special)) then
7555 ! MF nonlinear force-free B field extrapolation and data driven
7556 ! require normal B of the first ghost cell layer to be untouched by
7557 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
7558 select case (idims)
7559 {case (^d)
7560 if (iside==2) then
7561 ! maximal boundary
7562 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
7563 ixomax^dd=ixghi^dd;
7564 else
7565 ! minimal boundary
7566 ixomin^dd=ixglo^dd;
7567 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
7568 end if \}
7569 end select
7570 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
7571 end if
7572 end do
7573 end do
7574
7575 end subroutine mhd_boundary_adjust
7576
7577 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
7579
7580 integer, intent(in) :: ixg^l,ixo^l,ib
7581 double precision, intent(inout) :: w(ixg^s,1:nw)
7582 double precision, intent(in) :: x(ixg^s,1:ndim)
7583
7584 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
7585 integer :: ix^d,ixf^l
7586
7587 select case(ib)
7588 case(1)
7589 ! 2nd order CD for divB=0 to set normal B component better
7590 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7591 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7592 {^iftwod
7593 ixfmin1=ixomin1+1
7594 ixfmax1=ixomax1+1
7595 ixfmin2=ixomin2+1
7596 ixfmax2=ixomax2-1
7597 if(slab_uniform) then
7598 dx1x2=dxlevel(1)/dxlevel(2)
7599 do ix1=ixfmax1,ixfmin1,-1
7600 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
7601 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7602 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7603 enddo
7604 else
7605 do ix1=ixfmax1,ixfmin1,-1
7606 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
7607 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
7608 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7609 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7610 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7611 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7612 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7613 end do
7614 end if
7615 }
7616 {^ifthreed
7617 ixfmin1=ixomin1+1
7618 ixfmax1=ixomax1+1
7619 ixfmin2=ixomin2+1
7620 ixfmax2=ixomax2-1
7621 ixfmin3=ixomin3+1
7622 ixfmax3=ixomax3-1
7623 if(slab_uniform) then
7624 dx1x2=dxlevel(1)/dxlevel(2)
7625 dx1x3=dxlevel(1)/dxlevel(3)
7626 do ix1=ixfmax1,ixfmin1,-1
7627 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7628 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7629 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7630 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7631 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7632 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7633 end do
7634 else
7635 do ix1=ixfmax1,ixfmin1,-1
7636 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7637 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7638 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7639 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7640 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7641 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7642 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7643 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7644 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7645 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7646 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7647 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7648 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7649 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7650 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7651 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7652 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7653 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7654 end do
7655 end if
7656 }
7657 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7658 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7659 case(2)
7660 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7661 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7662 {^iftwod
7663 ixfmin1=ixomin1-1
7664 ixfmax1=ixomax1-1
7665 ixfmin2=ixomin2+1
7666 ixfmax2=ixomax2-1
7667 if(slab_uniform) then
7668 dx1x2=dxlevel(1)/dxlevel(2)
7669 do ix1=ixfmin1,ixfmax1
7670 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
7671 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7672 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7673 enddo
7674 else
7675 do ix1=ixfmin1,ixfmax1
7676 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
7677 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
7678 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7679 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7680 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7681 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7682 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7683 end do
7684 end if
7685 }
7686 {^ifthreed
7687 ixfmin1=ixomin1-1
7688 ixfmax1=ixomax1-1
7689 ixfmin2=ixomin2+1
7690 ixfmax2=ixomax2-1
7691 ixfmin3=ixomin3+1
7692 ixfmax3=ixomax3-1
7693 if(slab_uniform) then
7694 dx1x2=dxlevel(1)/dxlevel(2)
7695 dx1x3=dxlevel(1)/dxlevel(3)
7696 do ix1=ixfmin1,ixfmax1
7697 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7698 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7699 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7700 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7701 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7702 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7703 end do
7704 else
7705 do ix1=ixfmin1,ixfmax1
7706 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7707 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7708 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7709 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7710 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7711 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7712 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7713 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7714 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7715 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7716 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7717 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7718 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7719 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7720 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7721 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7722 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7723 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7724 end do
7725 end if
7726 }
7727 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7728 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7729 case(3)
7730 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7731 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7732 {^iftwod
7733 ixfmin1=ixomin1+1
7734 ixfmax1=ixomax1-1
7735 ixfmin2=ixomin2+1
7736 ixfmax2=ixomax2+1
7737 if(slab_uniform) then
7738 dx2x1=dxlevel(2)/dxlevel(1)
7739 do ix2=ixfmax2,ixfmin2,-1
7740 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
7741 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7742 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7743 enddo
7744 else
7745 do ix2=ixfmax2,ixfmin2,-1
7746 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
7747 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
7748 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7749 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7750 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7751 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7752 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7753 end do
7754 end if
7755 }
7756 {^ifthreed
7757 ixfmin1=ixomin1+1
7758 ixfmax1=ixomax1-1
7759 ixfmin3=ixomin3+1
7760 ixfmax3=ixomax3-1
7761 ixfmin2=ixomin2+1
7762 ixfmax2=ixomax2+1
7763 if(slab_uniform) then
7764 dx2x1=dxlevel(2)/dxlevel(1)
7765 dx2x3=dxlevel(2)/dxlevel(3)
7766 do ix2=ixfmax2,ixfmin2,-1
7767 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7768 ix2+1,ixfmin3:ixfmax3,mag(2)) &
7769 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7770 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7771 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7772 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7773 end do
7774 else
7775 do ix2=ixfmax2,ixfmin2,-1
7776 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
7777 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
7778 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7779 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
7780 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7781 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7782 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7783 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7784 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7785 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7786 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7787 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7788 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7789 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7790 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7791 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7792 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
7793 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7794 end do
7795 end if
7796 }
7797 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7798 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7799 case(4)
7800 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7801 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7802 {^iftwod
7803 ixfmin1=ixomin1+1
7804 ixfmax1=ixomax1-1
7805 ixfmin2=ixomin2-1
7806 ixfmax2=ixomax2-1
7807 if(slab_uniform) then
7808 dx2x1=dxlevel(2)/dxlevel(1)
7809 do ix2=ixfmin2,ixfmax2
7810 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
7811 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7812 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7813 end do
7814 else
7815 do ix2=ixfmin2,ixfmax2
7816 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
7817 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
7818 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7819 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7820 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7821 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7822 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7823 end do
7824 end if
7825 }
7826 {^ifthreed
7827 ixfmin1=ixomin1+1
7828 ixfmax1=ixomax1-1
7829 ixfmin3=ixomin3+1
7830 ixfmax3=ixomax3-1
7831 ixfmin2=ixomin2-1
7832 ixfmax2=ixomax2-1
7833 if(slab_uniform) then
7834 dx2x1=dxlevel(2)/dxlevel(1)
7835 dx2x3=dxlevel(2)/dxlevel(3)
7836 do ix2=ixfmin2,ixfmax2
7837 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7838 ix2-1,ixfmin3:ixfmax3,mag(2)) &
7839 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7840 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7841 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7842 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7843 end do
7844 else
7845 do ix2=ixfmin2,ixfmax2
7846 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
7847 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
7848 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7849 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
7850 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7851 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7852 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7853 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7854 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7855 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7856 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7857 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7858 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7859 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7860 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7861 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7862 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
7863 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7864 end do
7865 end if
7866 }
7867 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7868 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7869 {^ifthreed
7870 case(5)
7871 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7872 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7873 ixfmin1=ixomin1+1
7874 ixfmax1=ixomax1-1
7875 ixfmin2=ixomin2+1
7876 ixfmax2=ixomax2-1
7877 ixfmin3=ixomin3+1
7878 ixfmax3=ixomax3+1
7879 if(slab_uniform) then
7880 dx3x1=dxlevel(3)/dxlevel(1)
7881 dx3x2=dxlevel(3)/dxlevel(2)
7882 do ix3=ixfmax3,ixfmin3,-1
7883 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
7884 ixfmin2:ixfmax2,ix3+1,mag(3)) &
7885 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7886 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7887 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7888 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7889 end do
7890 else
7891 do ix3=ixfmax3,ixfmin3,-1
7892 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
7893 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
7894 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7895 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
7896 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7897 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7898 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7899 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7900 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7901 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7902 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7903 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7904 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7905 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7906 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7907 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7908 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
7909 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7910 end do
7911 end if
7912 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7913 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7914 case(6)
7915 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7916 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7917 ixfmin1=ixomin1+1
7918 ixfmax1=ixomax1-1
7919 ixfmin2=ixomin2+1
7920 ixfmax2=ixomax2-1
7921 ixfmin3=ixomin3-1
7922 ixfmax3=ixomax3-1
7923 if(slab_uniform) then
7924 dx3x1=dxlevel(3)/dxlevel(1)
7925 dx3x2=dxlevel(3)/dxlevel(2)
7926 do ix3=ixfmin3,ixfmax3
7927 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
7928 ixfmin2:ixfmax2,ix3-1,mag(3)) &
7929 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7930 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7931 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7932 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7933 end do
7934 else
7935 do ix3=ixfmin3,ixfmax3
7936 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
7937 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
7938 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7939 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
7940 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7941 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7942 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7943 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7944 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7945 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7946 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7947 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7948 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7949 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7950 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7951 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7952 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
7953 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7954 end do
7955 end if
7956 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7957 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7958 }
7959 case default
7960 call mpistop("Special boundary is not defined for this region")
7961 end select
7962
7963 end subroutine fixdivb_boundary
7964
7965 {^nooned
7966 subroutine mhd_clean_divb_multigrid(qdt, qt, active)
7967 use mod_forest
7970 use mod_geometry
7971
7972 double precision, intent(in) :: qdt !< Current time step
7973 double precision, intent(in) :: qt !< Current time
7974 logical, intent(inout) :: active !< Output if the source is active
7975
7976 integer :: id
7977 integer, parameter :: max_its = 50
7978 double precision :: residual_it(max_its), max_divb
7979 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
7980 double precision :: res
7981 double precision, parameter :: max_residual = 1d-3
7982 double precision, parameter :: residual_reduction = 1d-10
7983 integer :: iigrid, igrid
7984 integer :: n, nc, lvl, ix^l, ixc^l, idim
7985 type(tree_node), pointer :: pnode
7986
7987 mg%operator_type = mg_laplacian
7988
7989 ! Set boundary conditions
7990 do n = 1, 2*ndim
7991 idim = (n+1)/2
7992 select case (typeboundary(mag(idim), n))
7993 case (bc_symm)
7994 ! d/dx B = 0, take phi = 0
7995 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7996 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7997 case (bc_asymm)
7998 ! B = 0, so grad(phi) = 0
7999 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
8000 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
8001 case (bc_cont)
8002 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
8003 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
8004 case (bc_special)
8005 ! Assume Dirichlet boundary conditions, derivative zero
8006 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
8007 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
8008 case (bc_periodic)
8009 ! Nothing to do here
8010 case default
8011 write(*,*) "mhd_clean_divb_multigrid warning: unknown boundary type"
8012 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
8013 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
8014 end select
8015 end do
8016
8017 ix^l=ixm^ll^ladd1;
8018 max_divb = 0.0d0
8019
8020 ! Store divergence of B as right-hand side
8021 do iigrid = 1, igridstail
8022 igrid = igrids(iigrid);
8023 pnode => igrid_to_node(igrid, mype)%node
8024 id = pnode%id
8025 lvl = mg%boxes(id)%lvl
8026 nc = mg%box_size_lvl(lvl)
8027
8028 ! Geometry subroutines expect this to be set
8029 block => ps(igrid)
8030 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
8031
8032 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
8034 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
8035 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
8036 end do
8037
8038 ! Solve laplacian(phi) = divB
8039 if(stagger_grid) then
8040 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
8041 mpi_max, icomm, ierrmpi)
8042
8043 if (mype == 0) print *, "Performing multigrid divB cleaning"
8044 if (mype == 0) print *, "iteration vs residual"
8045 ! Solve laplacian(phi) = divB
8046 do n = 1, max_its
8047 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
8048 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
8049 if (residual_it(n) < residual_reduction * max_divb) exit
8050 end do
8051 if (mype == 0 .and. n > max_its) then
8052 print *, "divb_multigrid warning: not fully converged"
8053 print *, "current amplitude of divb: ", residual_it(max_its)
8054 print *, "multigrid smallest grid: ", &
8055 mg%domain_size_lvl(:, mg%lowest_lvl)
8056 print *, "note: smallest grid ideally has <= 8 cells"
8057 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
8058 print *, "note: dx/dy/dz should be similar"
8059 end if
8060 else
8061 do n = 1, max_its
8062 call mg_fas_vcycle(mg, max_res=res)
8063 if (res < max_residual) exit
8064 end do
8065 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
8066 end if
8067
8068
8069 ! Correct the magnetic field
8070 do iigrid = 1, igridstail
8071 igrid = igrids(iigrid);
8072 pnode => igrid_to_node(igrid, mype)%node
8073 id = pnode%id
8074
8075 ! Geometry subroutines expect this to be set
8076 block => ps(igrid)
8077 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
8078
8079 ! Compute the gradient of phi
8080 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
8081
8082 if(stagger_grid) then
8083 do idim =1, ndim
8084 ixcmin^d=ixmlo^d-kr(idim,^d);
8085 ixcmax^d=ixmhi^d;
8086 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
8087 ! Apply the correction B* = B - gradient(phi)
8088 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
8089 end do
8090 ! store cell-center magnetic energy
8091 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
8092 ! change cell-center magnetic field
8093 call mhd_face_to_center(ixm^ll,ps(igrid))
8094 else
8095 do idim = 1, ndim
8096 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
8097 end do
8098 ! store cell-center magnetic energy
8099 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
8100 ! Apply the correction B* = B - gradient(phi)
8101 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
8102 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
8103 end if
8104
8105 if(total_energy) then
8106 ! Determine magnetic energy difference
8107 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
8108 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
8109 ! Keep thermal pressure the same
8110 ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
8111 end if
8112 end do
8113
8114 active = .true.
8115
8116 end subroutine mhd_clean_divb_multigrid
8117 }
8118
8119 !> get electric field through averaging neighors to update faces in CT
8120 subroutine mhd_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8122 use mod_usr_methods
8123
8124 integer, intent(in) :: ixi^l, ixo^l
8125 double precision, intent(in) :: qt,qdt
8126 ! cell-center primitive variables
8127 double precision, intent(in) :: wp(ixi^s,1:nw)
8128 type(state) :: sct, s
8129 type(ct_velocity) :: vcts
8130 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8131 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8132
8133 double precision :: circ(ixi^s,1:ndim)
8134 ! non-ideal electric field on cell edges
8135 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8136 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
8137 integer :: idim1,idim2,idir,iwdim1,iwdim2
8138
8139 associate(bfaces=>s%ws,x=>s%x)
8140
8141 ! Calculate contribution to FEM of each edge,
8142 ! that is, estimate value of line integral of
8143 ! electric field in the positive idir direction.
8144
8145 ! if there is resistivity, get eta J
8146 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8147
8148 ! if there is ambipolar diffusion, get E_ambi
8149 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8150
8151 do idim1=1,ndim
8152 iwdim1 = mag(idim1)
8153 i1kr^d=kr(idim1,^d);
8154 do idim2=1,ndim
8155 iwdim2 = mag(idim2)
8156 i2kr^d=kr(idim2,^d);
8157 do idir=sdim,3! Direction of line integral
8158 ! Allow only even permutations
8159 if (lvc(idim1,idim2,idir)==1) then
8160 ixcmax^d=ixomax^d;
8161 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8162 ! average cell-face electric field to cell edges
8163 {do ix^db=ixcmin^db,ixcmax^db\}
8164 fe(ix^d,idir)=quarter*&
8165 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
8166 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
8167 ! add resistive electric field at cell edges E=-vxB+eta J
8168 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
8169 ! add ambipolar electric field
8170 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
8171
8172 ! times time step and edge length
8173 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
8174 {end do\}
8175 end if
8176 end do
8177 end do
8178 end do
8179
8180 ! allow user to change inductive electric field, especially for boundary driven applications
8181 if(associated(usr_set_electric_field)) &
8182 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8183
8184 circ(ixi^s,1:ndim)=zero
8185
8186 ! Calculate circulation on each face
8187 do idim1=1,ndim ! Coordinate perpendicular to face
8188 ixcmax^d=ixomax^d;
8189 ixcmin^d=ixomin^d-kr(idim1,^d);
8190 do idim2=1,ndim
8191 ixa^l=ixc^l-kr(idim2,^d);
8192 do idir=sdim,3 ! Direction of line integral
8193 ! Assemble indices
8194 if(lvc(idim1,idim2,idir)==1) then
8195 ! Add line integrals in direction idir
8196 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8197 +(fe(ixc^s,idir)&
8198 -fe(ixa^s,idir))
8199 else if(lvc(idim1,idim2,idir)==-1) then
8200 ! Add line integrals in direction idir
8201 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8202 -(fe(ixc^s,idir)&
8203 -fe(ixa^s,idir))
8204 end if
8205 end do
8206 end do
8207 {do ix^db=ixcmin^db,ixcmax^db\}
8208 ! Divide by the area of the face to get dB/dt
8209 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8210 ! Time update cell-face magnetic field component
8211 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8212 end if
8213 {end do\}
8214 end do
8215
8216 end associate
8217
8218 end subroutine mhd_update_faces_average
8219
8220 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
8221 subroutine mhd_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8223 use mod_usr_methods
8224 use mod_geometry
8225
8226 integer, intent(in) :: ixi^l, ixo^l
8227 double precision, intent(in) :: qt, qdt
8228 ! cell-center primitive variables
8229 double precision, intent(in) :: wp(ixi^s,1:nw)
8230 type(state) :: sct, s
8231 type(ct_velocity) :: vcts
8232 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8233 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8234
8235 double precision :: circ(ixi^s,1:ndim)
8236 ! electric field at cell centers
8237 double precision :: ecc(ixi^s,sdim:3)
8238 double precision :: ein(ixi^s,sdim:3)
8239 ! gradient of E at left and right side of a cell face
8240 double precision :: el(ixi^s),er(ixi^s)
8241 ! gradient of E at left and right side of a cell corner
8242 double precision :: elc,erc
8243 ! non-ideal electric field on cell edges
8244 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8245 ! current on cell edges
8246 double precision :: jce(ixi^s,sdim:3)
8247 ! location at cell faces
8248 double precision :: xs(ixgs^t,1:ndim)
8249 double precision :: gradi(ixgs^t)
8250 integer :: ixc^l,ixa^l
8251 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
8252
8253 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
8254
8255 ! if there is resistivity, get eta J
8256 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8257
8258 ! if there is ambipolar diffusion, get E_ambi
8259 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8260
8261 if(b0field) then
8262 {do ix^db=iximin^db,iximax^db\}
8263 ! Calculate electric field at cell centers
8264 {^ifthreed
8265 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_)
8266 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_)
8267 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_)
8268 }
8269 {^iftwod
8270 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8271 }
8272 {^ifoned
8273 ecc(ix^d,3)=0.d0
8274 }
8275 {end do\}
8276 else
8277 {do ix^db=iximin^db,iximax^db\}
8278 ! Calculate electric field at cell centers
8279 {^ifthreed
8280 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
8281 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
8282 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8283 }
8284 {^iftwod
8285 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8286 }
8287 {^ifoned
8288 ecc(ix^d,3)=0.d0
8289 }
8290 {end do\}
8291 end if
8292
8293 ! Calculate contribution to FEM of each edge,
8294 ! that is, estimate value of line integral of
8295 ! electric field in the positive idir direction.
8296 ! evaluate electric field along cell edges according to equation (41)
8297 do idim1=1,ndim
8298 iwdim1 = mag(idim1)
8299 i1kr^d=kr(idim1,^d);
8300 do idim2=1,ndim
8301 iwdim2 = mag(idim2)
8302 i2kr^d=kr(idim2,^d);
8303 do idir=sdim,3 ! Direction of line integral
8304 ! Allow only even permutations
8305 if (lvc(idim1,idim2,idir)==1) then
8306 ixcmax^d=ixomax^d;
8307 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8308 ! Assemble indices
8309 ! average cell-face electric field to cell edges
8310 {do ix^db=ixcmin^db,ixcmax^db\}
8311 fe(ix^d,idir)=quarter*&
8312 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
8313 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
8314 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)
8315 {end do\}
8316 ! add slope in idim2 direction from equation (50)
8317 ixamin^d=ixcmin^d;
8318 ixamax^d=ixcmax^d+i1kr^d;
8319 {do ix^db=ixamin^db,ixamax^db\}
8320 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
8321 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
8322 {end do\}
8323 {!dir$ ivdep
8324 do ix^db=ixcmin^db,ixcmax^db\}
8325 if(vnorm(ix^d,idim1)>0.d0) then
8326 elc=el(ix^d)
8327 else if(vnorm(ix^d,idim1)<0.d0) then
8328 elc=el({ix^d+i1kr^d})
8329 else
8330 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
8331 end if
8332 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
8333 erc=er(ix^d)
8334 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
8335 erc=er({ix^d+i1kr^d})
8336 else
8337 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
8338 end if
8339 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
8340 {end do\}
8341
8342 ! add slope in idim1 direction from equation (50)
8343 ixamin^d=ixcmin^d;
8344 ixamax^d=ixcmax^d+i2kr^d;
8345 {do ix^db=ixamin^db,ixamax^db\}
8346 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
8347 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
8348 {end do\}
8349 {!dir$ ivdep
8350 do ix^db=ixcmin^db,ixcmax^db\}
8351 if(vnorm(ix^d,idim2)>0.d0) then
8352 elc=el(ix^d)
8353 else if(vnorm(ix^d,idim2)<0.d0) then
8354 elc=el({ix^d+i2kr^d})
8355 else
8356 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
8357 end if
8358 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
8359 erc=er(ix^d)
8360 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
8361 erc=er({ix^d+i2kr^d})
8362 else
8363 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
8364 end if
8365 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
8366 ! difference between average and upwind interpolated E
8367 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)-ein(ix^d,idir)
8368 ! add resistive electric field at cell edges E=-vxB+eta J
8369 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
8370 ! add ambipolar electric field
8371 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
8372
8373 ! times time step and edge length
8374 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
8375 {end do\}
8376 end if
8377 end do
8378 end do
8379 end do
8380
8382 ! add upwind diffused magnetic energy back to energy
8383 ! calculate current density at cell edges
8384 jce=0.d0
8385 do idim1=1,ndim
8386 do idim2=1,ndim
8387 do idir=sdim,3
8388 if (lvc(idim1,idim2,idir)==0) cycle
8389 ixcmax^d=ixomax^d;
8390 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8391 ixamax^d=ixcmax^d-kr(idir,^d)+1;
8392 ixamin^d=ixcmin^d;
8393 ! current at transverse faces
8394 xs(ixa^s,:)=x(ixa^s,:)
8395 xs(ixa^s,idim2)=x(ixa^s,idim2)+half*s%dx(ixa^s,idim2)
8396 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi)
8397 if (lvc(idim1,idim2,idir)==1) then
8398 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8399 else
8400 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8401 end if
8402 end do
8403 end do
8404 end do
8405 do idir=sdim,3
8406 ixcmax^d=ixomax^d;
8407 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8408 ! E dot J on cell edges
8409 ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
8410 ! average from cell edge to cell center
8411 {^ifthreed
8412 if(idir==1) then
8413 {do ix^db=ixomin^db,ixomax^db\}
8414 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1,ix2-1,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
8415 +ein(ix1,ix2-1,ix3-1,idir))
8416 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8417 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8418 {end do\}
8419 else if(idir==2) then
8420 {do ix^db=ixomin^db,ixomax^db\}
8421 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
8422 +ein(ix1-1,ix2,ix3-1,idir))
8423 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8424 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8425 {end do\}
8426 else
8427 {do ix^db=ixomin^db,ixomax^db\}
8428 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2-1,ix3,idir)&
8429 +ein(ix1-1,ix2-1,ix3,idir))
8430 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8431 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8432 {end do\}
8433 end if
8434 }
8435 {^iftwod
8436 !idir=3
8437 {do ix^db=ixomin^db,ixomax^db\}
8438 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,idir)+ein(ix1,ix2-1,idir)&
8439 +ein(ix1-1,ix2-1,idir))
8440 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8441 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8442 {end do\}
8443 }
8444 ! save additional numerical resistive heating to an extra variable
8445 !! if(nwextra>0) then
8446 !! block%w(ixO^S,nw)=block%w(ixO^S,nw)+jce(ixO^S,idir)
8447 !! end if
8448 end do
8449 end if
8450
8451 ! allow user to change inductive electric field, especially for boundary driven applications
8452 if(associated(usr_set_electric_field)) &
8453 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8454
8455 circ(ixi^s,1:ndim)=zero
8456
8457 ! Calculate circulation on each face
8458 do idim1=1,ndim ! Coordinate perpendicular to face
8459 ixcmax^d=ixomax^d;
8460 ixcmin^d=ixomin^d-kr(idim1,^d);
8461 do idim2=1,ndim
8462 ixa^l=ixc^l-kr(idim2,^d);
8463 do idir=sdim,3 ! Direction of line integral
8464 ! Assemble indices
8465 if(lvc(idim1,idim2,idir)==1) then
8466 ! Add line integrals in direction idir
8467 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8468 +(fe(ixc^s,idir)&
8469 -fe(ixa^s,idir))
8470 else if(lvc(idim1,idim2,idir)==-1) then
8471 ! Add line integrals in direction idir
8472 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8473 -(fe(ixc^s,idir)&
8474 -fe(ixa^s,idir))
8475 end if
8476 end do
8477 end do
8478 {do ix^db=ixcmin^db,ixcmax^db\}
8479 ! Divide by the area of the face to get dB/dt
8480 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8481 ! Time update cell-face magnetic field component
8482 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8483 end if
8484 {end do\}
8485 end do
8486
8487 end associate
8488
8489 end subroutine mhd_update_faces_contact
8490
8491 !> update faces
8492 subroutine mhd_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8494 use mod_usr_methods
8496
8497 integer, intent(in) :: ixi^l, ixo^l
8498 double precision, intent(in) :: qt, qdt
8499 ! cell-center primitive variables
8500 double precision, intent(in) :: wp(ixi^s,1:nw)
8501 type(state) :: sct, s
8502 type(ct_velocity) :: vcts
8503 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8504 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8505
8506 double precision :: vtill(ixi^s,2)
8507 double precision :: vtilr(ixi^s,2)
8508 double precision :: bfacetot(ixi^s,ndim)
8509 double precision :: btill(ixi^s,ndim)
8510 double precision :: btilr(ixi^s,ndim)
8511 double precision :: cp(ixi^s,2)
8512 double precision :: cm(ixi^s,2)
8513 double precision :: circ(ixi^s,1:ndim)
8514 ! non-ideal electric field on cell edges
8515 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8516 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
8517 integer :: idim1,idim2,idir,ix^d
8518
8519 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
8520 cbarmax=>vcts%cbarmax)
8521
8522 ! Calculate contribution to FEM of each edge,
8523 ! that is, estimate value of line integral of
8524 ! electric field in the positive idir direction.
8525
8526 ! Loop over components of electric field
8527
8528 ! idir: electric field component we need to calculate
8529 ! idim1: directions in which we already performed the reconstruction
8530 ! idim2: directions in which we perform the reconstruction
8531
8532 ! if there is resistivity, get eta J
8533 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8534
8535 ! if there is ambipolar diffusion, get E_ambi
8536 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8537
8538 do idir=sdim,3
8539 ! Indices
8540 ! idir: electric field component
8541 ! idim1: one surface
8542 ! idim2: the other surface
8543 ! cyclic permutation: idim1,idim2,idir=1,2,3
8544 ! Velocity components on the surface
8545 ! follow cyclic premutations:
8546 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
8547
8548 ixcmax^d=ixomax^d;
8549 ixcmin^d=ixomin^d-1+kr(idir,^d);
8550
8551 ! Set indices and directions
8552 idim1=mod(idir,3)+1
8553 idim2=mod(idir+1,3)+1
8554
8555 jxc^l=ixc^l+kr(idim1,^d);
8556 ixcp^l=ixc^l+kr(idim2,^d);
8557
8558 ! Reconstruct transverse transport velocities
8559 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
8560 vtill(ixi^s,2),vtilr(ixi^s,2))
8561
8562 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
8563 vtill(ixi^s,1),vtilr(ixi^s,1))
8564
8565 ! Reconstruct magnetic fields
8566 ! Eventhough the arrays are larger, reconstruct works with
8567 ! the limits ixG.
8568 if(b0field) then
8569 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
8570 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
8571 else
8572 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
8573 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
8574 end if
8575 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
8576 btill(ixi^s,idim1),btilr(ixi^s,idim1))
8577
8578 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
8579 btill(ixi^s,idim2),btilr(ixi^s,idim2))
8580
8581 ! Take the maximum characteristic
8582
8583 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
8584 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
8585
8586 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
8587 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
8588
8589
8590 ! Calculate eletric field
8591 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
8592 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
8593 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
8594 /(cp(ixc^s,1)+cm(ixc^s,1)) &
8595 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
8596 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
8597 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
8598 /(cp(ixc^s,2)+cm(ixc^s,2))
8599
8600 ! add resistive electric field at cell edges E=-vxB+eta J
8601 if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
8602 ! add ambipolar electric field
8603 if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
8604
8605 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
8606
8607 if (.not.slab) then
8608 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
8609 fe(ixc^s,idir)=zero
8610 end where
8611 end if
8612
8613 end do
8614
8615 ! allow user to change inductive electric field, especially for boundary driven applications
8616 if(associated(usr_set_electric_field)) &
8617 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8618
8619 circ(ixi^s,1:ndim)=zero
8620
8621 ! Calculate circulation on each face: interal(fE dot dl)
8622 do idim1=1,ndim ! Coordinate perpendicular to face
8623 ixcmax^d=ixomax^d;
8624 ixcmin^d=ixomin^d-kr(idim1,^d);
8625 do idim2=1,ndim
8626 do idir=sdim,3 ! Direction of line integral
8627 ! Assemble indices
8628 if(lvc(idim1,idim2,idir)/=0) then
8629 hxc^l=ixc^l-kr(idim2,^d);
8630 ! Add line integrals in direction idir
8631 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8632 +lvc(idim1,idim2,idir)&
8633 *(fe(ixc^s,idir)&
8634 -fe(hxc^s,idir))
8635 end if
8636 end do
8637 end do
8638 {do ix^db=ixcmin^db,ixcmax^db\}
8639 ! Divide by the area of the face to get dB/dt
8640 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8641 ! Time update cell-face magnetic field component
8642 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8643 end if
8644 {end do\}
8645 end do
8646
8647 end associate
8648 end subroutine mhd_update_faces_hll
8649
8650 !> calculate eta J at cell edges
8651 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
8653 use mod_usr_methods
8654 use mod_geometry
8655
8656 integer, intent(in) :: ixi^l, ixo^l
8657 ! cell-center primitive variables
8658 double precision, intent(in) :: wp(ixi^s,1:nw)
8659 type(state), intent(in) :: sct, s
8660 ! current on cell edges
8661 double precision :: jce(ixi^s,sdim:3)
8662
8663 ! current on cell centers
8664 double precision :: jcc(ixi^s,7-2*ndir:3)
8665 ! location at cell faces
8666 double precision :: xs(ixgs^t,1:ndim)
8667 ! resistivity
8668 double precision :: eta(ixi^s)
8669 double precision :: gradi(ixgs^t)
8670 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
8671
8672 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
8673 ! calculate current density at cell edges
8674 jce=0.d0
8675 do idim1=1,ndim
8676 do idim2=1,ndim
8677 do idir=sdim,3
8678 if (lvc(idim1,idim2,idir)==0) cycle
8679 ixcmax^d=ixomax^d;
8680 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8681 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
8682 ixbmin^d=ixcmin^d;
8683 ! current at transverse faces
8684 xs(ixb^s,:)=x(ixb^s,:)
8685 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
8686 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
8687 if (lvc(idim1,idim2,idir)==1) then
8688 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8689 else
8690 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8691 end if
8692 end do
8693 end do
8694 end do
8695 ! get resistivity
8696 if(mhd_eta>zero)then
8697 jce(ixi^s,:)=jce(ixi^s,:)*mhd_eta
8698 else
8699 ixa^l=ixo^l^ladd1;
8700 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
8701 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
8702 ! calculate eta on cell edges
8703 do idir=sdim,3
8704 ixcmax^d=ixomax^d;
8705 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8706 jcc(ixc^s,idir)=0.d0
8707 {do ix^db=0,1\}
8708 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8709 ixamin^d=ixcmin^d+ix^d;
8710 ixamax^d=ixcmax^d+ix^d;
8711 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
8712 {end do\}
8713 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
8714 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
8715 end do
8716 end if
8717
8718 end associate
8719 end subroutine get_resistive_electric_field
8720
8721 !> get ambipolar electric field on cell edges
8722 subroutine get_ambipolar_electric_field(ixI^L,ixO^L,w,x,fE)
8724
8725 integer, intent(in) :: ixi^l, ixo^l
8726 double precision, intent(in) :: w(ixi^s,1:nw)
8727 double precision, intent(in) :: x(ixi^s,1:ndim)
8728 double precision, intent(out) :: fe(ixi^s,sdim:3)
8729
8730 double precision :: jxbxb(ixi^s,1:3)
8731 integer :: idir,ixa^l,ixc^l,ix^d
8732
8733 ixa^l=ixo^l^ladd1;
8734 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,jxbxb)
8735 ! calculate electric field on cell edges from cell centers
8736 do idir=sdim,3
8737 ! set ambipolar electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
8738 ! E_ambi(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
8739 call multiplyambicoef(ixi^l,ixa^l,jxbxb(ixi^s,idir),w,x)
8740 ixcmax^d=ixomax^d;
8741 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8742 fe(ixc^s,idir)=0.d0
8743 {do ix^db=0,1\}
8744 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8745 ixamin^d=ixcmin^d+ix^d;
8746 ixamax^d=ixcmax^d+ix^d;
8747 fe(ixc^s,idir)=fe(ixc^s,idir)+jxbxb(ixa^s,idir)
8748 {end do\}
8749 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0
8750 end do
8751
8752 end subroutine get_ambipolar_electric_field
8753
8754 !> calculate cell-center values from face-center values
8755 subroutine mhd_face_to_center(ixO^L,s)
8757 ! Non-staggered interpolation range
8758 integer, intent(in) :: ixo^l
8759 type(state) :: s
8760
8761 integer :: ix^d
8762
8763 ! calculate cell-center values from face-center values in 2nd order
8764 ! because the staggered arrays have an additional place to the left.
8765 ! Interpolate to cell barycentre using arithmetic average
8766 ! This might be done better later, to make the method less diffusive.
8767 {!dir$ ivdep
8768 do ix^db=ixomin^db,ixomax^db\}
8769 {^ifthreed
8770 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8771 +s%ws(ix1-1,ix2,ix3,1)*s%surfaceC(ix1-1,ix2,ix3,1))
8772 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8773 +s%ws(ix1,ix2-1,ix3,2)*s%surfaceC(ix1,ix2-1,ix3,2))
8774 s%w(ix^d,b3_)=half/s%surface(ix^d,3)*(s%ws(ix^d,3)*s%surfaceC(ix^d,3)&
8775 +s%ws(ix1,ix2,ix3-1,3)*s%surfaceC(ix1,ix2,ix3-1,3))
8776 }
8777 {^iftwod
8778 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8779 +s%ws(ix1-1,ix2,1)*s%surfaceC(ix1-1,ix2,1))
8780 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8781 +s%ws(ix1,ix2-1,2)*s%surfaceC(ix1,ix2-1,2))
8782 }
8783 {end do\}
8784
8785 ! calculate cell-center values from face-center values in 4th order
8786 !do idim=1,ndim
8787 ! gxO^L=ixO^L-2*kr(idim,^D);
8788 ! hxO^L=ixO^L-kr(idim,^D);
8789 ! jxO^L=ixO^L+kr(idim,^D);
8790
8791 ! ! Interpolate to cell barycentre using fourth order central formula
8792 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
8793 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8794 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8795 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8796 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
8797 !end do
8798
8799 ! calculate cell-center values from face-center values in 6th order
8800 !do idim=1,ndim
8801 ! fxO^L=ixO^L-3*kr(idim,^D);
8802 ! gxO^L=ixO^L-2*kr(idim,^D);
8803 ! hxO^L=ixO^L-kr(idim,^D);
8804 ! jxO^L=ixO^L+kr(idim,^D);
8805 ! kxO^L=ixO^L+2*kr(idim,^D);
8806
8807 ! ! Interpolate to cell barycentre using sixth order central formula
8808 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
8809 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
8810 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8811 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8812 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8813 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
8814 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
8815 !end do
8816
8817 end subroutine mhd_face_to_center
8818
8819 !> calculate magnetic field from vector potential
8820 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
8823
8824 integer, intent(in) :: ixis^l, ixi^l, ixo^l
8825 double precision, intent(inout) :: ws(ixis^s,1:nws)
8826 double precision, intent(in) :: x(ixi^s,1:ndim)
8827
8828 double precision :: adummy(ixis^s,1:3)
8829
8830 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
8831
8832 end subroutine b_from_vector_potential
8833
8834end module mod_mhd_phys
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
subroutine cak_init(phys_gamma)
Initialize the module.
subroutine cak_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Check time step for total radiation contribution.
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.
Module for physical and numeric constants.
double precision, parameter bigdouble
A very large real number.
double precision, parameter zero
some frequently used numbers
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 b_from_vector_potentiala(ixisl, ixil, ixol, ws, x, a)
calculate magnetic field from vector potential A at cell edges
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition mod_convert.t:59
PI (partial-ionisation) ionisation-degree backend for the eos% family.
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
Module for flux conservation near refinement boundaries.
subroutine, public store_flux(igrid, fc, idimlim, nwfluxin)
subroutine, public store_edge(igrid, ixil, fe, idimlim)
Module for flux limited diffusion (FLD)-approximation in Radiation-(Magneto)hydrodynamics simulations...
Definition mod_fld.t:13
logical fld_no_mg
Definition mod_fld.t:35
double precision, public fld_bisect_tol
Tolerance for bisection method for Energy sourceterms This is a percentage of the minimum of gas- and...
Definition mod_fld.t:25
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x, fl)
get dt limit for radiation force and FLD explicit source additions NOTE: w is primitive on entry
Definition mod_fld.t:381
double precision, public fld_diff_tol
Tolerance for radiative Energy diffusion.
Definition mod_fld.t:27
character(len=40) fld_fluxlimiter
flux limiter choice
Definition mod_fld.t:41
character(len=40) fld_opal_table
Definition mod_fld.t:39
double precision, public fld_cnorm
Definition mod_fld.t:36
double precision, public fld_kappa0
Opacity value when using constant opacity.
Definition mod_fld.t:22
subroutine, public add_fld_rad_force(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
Definition mod_fld.t:224
character(len=40) fld_opacity_law
switches for opacity
Definition mod_fld.t:38
character(len=40) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
Definition mod_fld.t:47
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure, fl)
Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
Definition mod_fld.t:524
logical fld_radforce_split
source split for energy interact and radforce:
Definition mod_fld.t:18
logical fld_bound_diff
switches for using changed cmax-cmin bounds
Definition mod_fld.t:32
subroutine, public fld_implicit_update(dtfactor, qdt, qtc, psa, psb, fl)
Calling all subroutines to perform the multigrid method Communicates rad_e and diff_coeff to multigri...
Definition mod_fld.t:784
subroutine, public fld_evaluate_implicit(qtc, psa, fl)
inplace update of psa==>F_im(psa)
Definition mod_fld.t:932
subroutine, public fld_init()
Initialising FLD-module Read opacities Initialise Multigrid and adimensionalise kappa.
Definition mod_fld.t:116
integer nth_for_diff_mg
diffusion coefficient stencil control
Definition mod_fld.t:45
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
subroutine, public get_divb(w, ixil, ixol, divb, nth_in)
Calculate div B within ixO.
integer, dimension(:), allocatable, public mag
Indices of the magnetic field.
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
integer coordinate
Definition mod_geometry.t:7
integer, parameter cartesian
Definition mod_geometry.t:8
subroutine laplacian_of_vector(qvec, ixil, ixol, lapl_qvec)
integer, parameter cylindrical
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...
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
subroutine gradientf(q, x, ixil, ixol, idir, gradq, nth_in, pm_in)
subroutine gradientl(q, ixil, ixol, idir, gradq)
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 arad_norm
Normalised radiation constant.
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.
integer ixghi
Upper index of grid block arrays.
pure subroutine cross_product(ixil, ixol, a, b, axb)
Cross product of two vectors.
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.
double precision unit_opacity
Physical scaling factor for Opacity.
integer, parameter unitpar
file handle for IO
double precision unit_mass
Physical scaling factor for mass.
logical use_imex_scheme
whether IMEX in use or not
integer, dimension(3, 3) kr
Kronecker delta tensor.
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 const_rad_a
Physical factors useful for radiation fld.
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.
logical local_timestep
each cell has its own timestep or not
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
integer, dimension(:), allocatable flux_method
Which flux scheme of spatial discretization to use (per grid level)
double precision, dimension(:), allocatable, parameter d
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.
integer nwauxio
Number of auxiliary variables that are only included in output.
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.
double precision unit_radflux
Physical scaling factor for radiation flux.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter sdim
starting dimension for electric field
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)
integer max_blocks
The maximum number of grid blocks in a processor.
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
integer, parameter unitconvert
double precision unit_erad
Physical scaling factor for radiation energy density.
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(wprim, ixil, ixol, dtnew, dxd, x)
Definition mod_gravity.t:81
subroutine gravity_init()
Initialize the module.
Definition mod_gravity.t:26
subroutine gravity_add_source(qdt, ixil, ixol, wct, wctprim, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
Definition mod_gravity.t:43
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, public mhd_get_trad(w, x, ixil, ixol, trad)
Calculates radiation temperature.
integer, public, protected c_
logical, public, protected mhd_gravity
Whether gravity is added.
integer, public, protected fip_
Index of the FIP passive scalar rho*fip in conserved form, fip in primitive form.
logical, public, protected mhd_internal_e
Whether internal energy is solved instead of total energy.
double precision, public, protected mhd_trac_delta
TRAC-7 (Johnston 2021, A&A 654 A2): target number of cells resolving the TR.
logical, public, protected mhd_glm_extended
Whether extended GLM-MHD is used with additional sources.
logical, public mhd_hyperbolic_tc_constant
character(len=std_len), public, protected type_ct
Method type of constrained transport.
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
subroutine, public mhd_clean_divb_multigrid(qdt, qt, active)
integer, public, protected qpar_
Index of the field-aligned heat flux q_parallel.
logical, public, protected mhd_radiative_cooling
Whether radiative cooling is added.
subroutine, public mhd_e_to_ei(ixil, ixol, w, x)
Transform total energy to internal energy.
double precision, public mhd_adiab
The adiabatic constant.
double precision, public divbdiff
Coefficient of diffusive divB cleaning.
double precision, public mhd_eta_hyper
The MHD hyper-resistivity.
character(len=std_len), public, protected mhd_uawsom_reflection_mode
Algebra used by the Alfven-wave reflection source. one_dimensional_gradient retains the original one-...
double precision, public, protected mhd_hyperbolic_tc_bmin
Field-strength transition scale for perpendicular closure.
double precision, public, protected rr
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
double precision, public, protected mhd_uawsom_sigma
Dimensionless multiplier in the one_dimensional_gradient source only.
integer, public, protected mhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
integer, public, protected wkminus_
double precision, public, protected mhd_uawsom_thread_radius0
subroutine, public get_normalized_divb(w, ixil, ixol, divb)
get dimensionless div B = |divB| * volume / area / |B|
integer, public, protected mhd_uawsom_height_dim
Cartesian direction used for the prescribed density contrast and reflection gradient.
logical, public numerical_resistive_heating
Whether numerical resistive heating is included when solving partial energy equation.
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
logical, public, protected mhd_rotating_frame
Whether rotating frame is activated.
logical, public, protected mhd_semirelativistic
Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved.
integer, public, protected mhd_divb_nth
Whether divB is computed with a fourth order approximation.
integer, public, protected mhd_n_tracer
Number of tracer species.
integer, public, protected te_
Indices of temperature.
integer, public, protected m
integer, public equi_rho0_
equi vars indices in the stateequi_vars array
integer, public, protected mhd_trac_type
Which TRAC method is used.
logical, public, protected mhd_cak_force
Whether plasma is partially ionized Whether CAK radiation line force is activated.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
double precision, public, protected mhd_uawsom_zeta0
Base transverse density contrast and filling factor.
integer, public, protected ne_
Index of the electron number density for LTE module.
logical, public, protected mhd_hall
Whether Hall-MHD is used.
type(te_fluid), allocatable, public te_fl_mhd
type of fluid for thermal emission synthesis
logical, public, protected mhd_ambipolar
Whether Ambipolar term is used.
logical, public, protected mhd_hyperbolic_tc
Whether thermal conduction is used.
logical, public, protected mhd_hyperbolic_tc_sat
Whether saturation is considered for hyperbolic TC. When the perpendicular channel is active,...
double precision, public, protected mhd_hyperbolic_tc_kappa_perp_factor
Relative perpendicular hyperbolic-TC coefficient in fixed/strong-field limit: kappa_perp0 = mhd_hyper...
logical, public has_equi_rho_and_p
whether split off equilibrium density and pressure
double precision, public mhd_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
double precision function, dimension(ixo^s), public mhd_mag_en_all(w, ixil, ixol)
Compute 2 times total magnetic energy.
pure double precision function, public mhd_uawsom_wave_energy_cell(wcell)
logical, public, protected mhd_radiation_fld
Whether radiation-gas interaction is handled using flux limited diffusion.
subroutine, public multiplyambicoef(ixil, ixol, res, w, x)
multiply res by the ambipolar coefficient The ambipolar coefficient is calculated as -mhd_eta_ambi/rh...
subroutine, public b_from_vector_potential(ixisl, ixil, ixol, ws, x)
calculate magnetic field from vector potential
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
integer, public, protected waminus_
logical, public, protected mhd_viscosity
Whether viscosity is added.
subroutine, public mhd_get_pradiation_from_prim(w, x, ixil, ixol, prad)
Calculate radiation pressure within ixO^L.
double precision, public, protected mhd_reduced_c
Reduced speed of light for semirelativistic MHD: 2% of light speed.
logical, public, protected mhd_energy
Whether an energy equation is used.
logical, public, protected mhd_ambipolar_exp
Whether Ambipolar term is implemented explicitly.
double precision, public mhd_hyperbolic_tc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
logical, public, protected mhd_glm
Whether GLM-MHD is used to control div B.
double precision, public, protected mhd_uawsom_zeta_scale
Physical input scales (lengths and magnetic field); converted to code units at init.
type(fld_fluid), allocatable, public fld_fl
Radiation fluid object (gas-EoS callbacks for FLD), wired in mhd_link_eos.
logical, public clean_initial_divb
clean initial divB
double precision, public mhd_eta
The MHD resistivity.
logical, public divbwave
Add divB wave in Roe solver.
logical, public, protected mhd_uawsom_reflection
Enable conservative Alfvén reflection (one-dimensional or Cartesian gradient-vorticity)
logical, public, protected mhd_magnetofriction
Whether magnetofriction is added.
double precision, public, protected mhd_trac_mask
Height of the mask used in the TRAC method.
procedure(mask_subroutine), pointer, public usr_mask_ambipolar
elemental pure double precision function, public mhd_uawsom_rho2_factor_cell(zeta)
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
logical, public, protected mhd_uawsom_kink_reflection
Enable conservative kink-wave reflection from the kink-speed gradient.
double precision, public, protected mhd_uawsom_filling_factor
integer, public, protected waplus_
Conserved wave-energy indices. The plus variables propagate against B.
subroutine, public mhd_uawsom_rho2_factor(ixil, ixol, w, x, factor)
double precision, public, protected mhd_uawsom_alfven_corr_length0
logical, public, protected mhd_thermal_conduction
Whether thermal conduction is used.
integer, public equi_pe0_
subroutine, public mhd_get_csrad2_prim(w, x, ixil, ixol, csound)
Calculate modified squared fast wave speed for FLD NOTE: w is primitive on entry here!...
integer, public, protected qperp_
Index of the perpendicular heat flux q_perp.
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
character(len=std_len), public, protected mhd_hyperbolic_tc_perp_mode
Perpendicular hyperbolic-TC closure mode: 'off' = disabled 'fixed_reference' = fixed classical ratio ...
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
pure double precision function, public mhd_uawsom_wave_pressure_cell(wcell, zeta)
logical, public, protected mhd_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
logical, public, protected mhd_particles
Whether particles module is added.
integer, public, protected b
subroutine, public mhd_face_to_center(ixol, s)
calculate cell-center values from face-center values
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
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, public mhd_etah
Hall resistivity.
subroutine, public mhd_get_v(w, x, ixil, ixol, v)
Calculate v vector.
double precision, public mhd_eta_ambi
The MHD ambipolar coefficient.
logical, public, protected mhd_fip
Whether FIP passive scalar is enabled.
logical, public, protected mhd_hydrodynamic_e
Whether hydrodynamic energy is solved instead of total energy.
integer, public, protected r_e
Index of the radiation energy.
subroutine, public mhd_phys_init()
logical, public, protected mhd_trac
Whether TRAC method is used.
subroutine, public mhd_get_csrad2(w, x, ixil, ixol, csound)
Calculate modified squared sound speed for FLD NOTE: only for diagnostic purposes,...
subroutine, public mhd_get_pthermal_plus_pradiation(w, x, ixil, ixol, pth_plus_prad)
Calculates the sum of the gas pressure and the max Prad tensor element.
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
integer, public, protected wkplus_
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
double precision, public, protected mhd_hyperbolic_tc_coulomb_log
Constant Coulomb logarithm used by the simplified electron-magnetization closure. It is a namelist pa...
integer, public, protected rho_
Index of the density (in the w array)
double precision, public, protected mhd_uawsom_bref
logical, public, protected b0field_forcefree
B0 field is force-free.
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
integer, public, protected tweight_
logical, public, protected mhd_ambipolar_sts
Whether Ambipolar term is implemented using supertimestepping.
logical, public, protected mhd_hyperbolic_tc_use_perp
Whether the perpendicular hyperbolic-TC channel is enabled.
subroutine, public mhd_ei_to_e(ixil, ixol, w, x)
Transform internal energy to total energy.
integer, public, protected e_
Index of the energy density (-1 if not present)
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
subroutine, public mhd_get_rho(w, x, ixil, ixol, rho)
logical, public, protected mhd_uawsom
Enable the Uniturbulence and Alfven Wave Solar Model extension.
logical, public, protected mhd_fld_pradtensor
integer, public, protected psi_
Indices of the GLM psi.
logical, public mhd_equi_thermal
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.
subroutine particles_init()
Initialize particle data and parameters.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine findl(tpoint, lpoint, fl)
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
subroutine calc_l_extended(tpoint, lpoint, 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.
subroutine, public small_values_average(ixil, ixol, w, x, w_flag, windex)
subroutine, public small_values_error(wprim, x, ixil, ixol, w_flag, subname)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method which can be used for multiple source terms in the governing equatio...
subroutine, public add_sts_method(sts_getdt, sts_set_sources, startvar, nflux, startwbc, nwbc, evolve_b)
subroutine which added programatically a term to be calculated using STS Params: sts_getdt function c...
subroutine, public set_conversion_methods_to_head(sts_before_first_cycle, sts_after_last_cycle)
Set the hooks called before the first cycle and after the last cycle in the STS update This method sh...
subroutine, public set_error_handling_to_head(sts_error_handling)
Set the hook of error handling in the STS update. This method is called before updating the BC....
subroutine, public sts_init()
Initialize sts module.
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
double precision function, public get_tc_dt_mhd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation) Note: also used in 1D MHD (or for neutrals i...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_hd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
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.
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
double precision time_htc_total
Definition mod_timing.t:27
double precision time_htc0
Definition mod_timing.t:27
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_adiab), pointer usr_set_adiab
procedure(set_adiab), pointer usr_set_gamma
procedure(sub_get_heating), pointer usr_get_heating
procedure(phys_gravity), pointer usr_gravity
procedure(uawsom_coefficients), pointer usr_uawsom_coefficients
Optionally provide local UAWSoM closure coefficients. The returned thread radius and Alfven correlati...
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.
subroutine, public viscosity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
procedure(sub_add_source), pointer, public viscosity_add_source
subroutine, public viscosity_init(phys_wider_stencil)
Initialize the module.
Radiation fluid object: gas-EoS callbacks the FLD module needs, wired by the physics module at link t...
Definition mod_fld.t:63
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11