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