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_physics
11 use mod_comm_lib, only: mpistop
13
14 implicit none
15 private
16
17 !> The adiabatic index
18 double precision, public :: mhd_gamma = 5.d0/3.0d0
19 !> The adiabatic constant
20 double precision, public :: mhd_adiab = 1.0d0
21 !> The MHD resistivity
22 double precision, public :: mhd_eta = 0.0d0
23 !> The MHD hyper-resistivity
24 double precision, public :: mhd_eta_hyper = 0.0d0
25 !> Hall resistivity
26 double precision, public :: mhd_etah = 0.0d0
27 !> The MHD ambipolar coefficient
28 double precision, public :: mhd_eta_ambi = 0.0d0
29 !> 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 !> Helium abundance over Hydrogen
42 double precision, public, protected :: he_abundance=0.1d0
43 !> Ionization fraction of H
44 !> H_ion_fr = H+/(H+ + H)
45 double precision, public, protected :: h_ion_fr=1d0
46 !> Ionization fraction of He
47 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
48 double precision, public, protected :: he_ion_fr=1d0
49 !> Ratio of number He2+ / number He+ + He2+
50 !> He_ion_fr2 = He2+/(He2+ + He+)
51 double precision, public, protected :: he_ion_fr2=1d0
52 ! used for eq of state when it is not defined by units,
53 ! the units do not contain terms related to ionization fraction
54 ! and it is p = RR * rho * T
55 double precision, public, protected :: rr=1d0
56 !> gamma minus one and its inverse
57 double precision :: gamma_1, inv_gamma_1
58 !> inverse of squared speed of light c0 and reduced speed of light c
59 double precision :: inv_squared_c0, inv_squared_c
60 !> equi vars indices in the state%equi_vars array
61 integer, public :: equi_rho0_ = -1
62 integer, public :: equi_pe0_ = -1
63 !> Number of tracer species
64 integer, public, protected :: mhd_n_tracer = 0
65 !> Index of the density (in the w array)
66 integer, public, protected :: rho_
67 !> Indices of the momentum density
68 integer, allocatable, public, protected :: mom(:)
69 !> Indices of the momentum density for the form of better vectorization
70 integer, public, protected :: ^c&m^C_
71 !> Index of the energy density (-1 if not present)
72 integer, public, protected :: e_
73 !> Indices of the magnetic field for the form of better vectorization
74 integer, public, protected :: ^c&b^C_
75 !> Index of the gas pressure (-1 if not present) should equal e_
76 integer, public, protected :: p_
77 !> Index of the field-aligned heat flux q_parallel
78 integer, public, protected :: qpar_
79 !> Index of the perpendicular heat flux q_perp
80 integer, public, protected :: qperp_
81 !> Indices of the GLM psi
82 integer, public, protected :: psi_
83 !> Index of the radiation energy
84 integer, public, protected :: r_e
85 !> Indices of temperature
86 integer, public, protected :: te_
87 !> Index of the FIP passive scalar rho*fip in conserved form, fip in primitive form
88 integer, public, protected :: fip_ = -1
89 !> Whether FIP passive scalar is enabled
90 logical, public, protected :: mhd_fip = .false.
91 !> Index of the cutoff temperature for the TRAC method
92 integer, public, protected :: tcoff_
93 integer, public, protected :: tweight_
94 !> Indices of the tracers
95 integer, allocatable, public, protected :: tracer(:)
96 !> The number of waves
97 integer :: nwwave=8
98 !> Method type of divb in a integer for good performance
99 integer :: type_divb
100 !> To skip * layer of ghost cells during divB=0 fix for boundary
101 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
102 ! DivB cleaning methods
103 integer, parameter :: divb_none = 0
104 integer, parameter :: divb_multigrid = -1
105 integer, parameter :: divb_glm = 1
106 integer, parameter :: divb_powel = 2
107 integer, parameter :: divb_janhunen = 3
108 integer, parameter :: divb_linde = 4
109 integer, parameter :: divb_lindejanhunen = 5
110 integer, parameter :: divb_lindepowel = 6
111 integer, parameter :: divb_lindeglm = 7
112 integer, parameter :: divb_ct = 8
113 !> Whether an energy equation is used
114 logical, public, protected :: mhd_energy = .true.
115 !> Whether thermal conduction is used
116 logical, public, protected :: mhd_thermal_conduction = .false.
117 !> Whether radiative cooling is added
118 logical, public, protected :: mhd_radiative_cooling = .false.
119 !> Whether thermal conduction is used
120 logical, public, protected :: mhd_hyperbolic_tc = .false.
121 !> Whether saturation is considered for hyperbolic TC
122 logical, public, protected :: mhd_hyperbolic_tc_sat = .false.
123 !> Whether the perpendicular hyperbolic-TC channel is enabled
124 logical, public, protected :: mhd_hyperbolic_tc_use_perp = .false.
125 !> Perpendicular hyperbolic-TC closure mode:
126 !> 0 = off, 1 = fixed anisotropy, 2 = field-strength-dependent isotropization
127 !> 3 = magnetization-based closure kappa_perp = kappa_parallel/(1+chi^2)
128 integer, public, protected :: mhd_hyperbolic_tc_perp_mode = 0
129 !> Relative perpendicular hyperbolic-TC coefficient in fixed/strong-field limit:
130 !> kappa_perp0 = mhd_hyperbolic_tc_kappa_perp_factor * kappa_parallel
131 double precision, public, protected :: mhd_hyperbolic_tc_kappa_perp_factor = 0.d0
132 !> Field-strength transition scale for perpendicular closure
133 double precision, public, protected :: mhd_hyperbolic_tc_bmin = 0.d0
134 !> Whether viscosity is added
135 logical, public, protected :: mhd_viscosity = .false.
136 !> Whether gravity is added
137 logical, public, protected :: mhd_gravity = .false.
138 !> Whether rotating frame is activated
139 logical, public, protected :: mhd_rotating_frame = .false.
140 !> Whether Hall-MHD is used
141 logical, public, protected :: mhd_hall = .false.
142 !> Whether Ambipolar term is used
143 logical, public, protected :: mhd_ambipolar = .false.
144 !> Whether Ambipolar term is implemented using supertimestepping
145 logical, public, protected :: mhd_ambipolar_sts = .false.
146 !> Whether Ambipolar term is implemented explicitly
147 logical, public, protected :: mhd_ambipolar_exp = .false.
148 !> Whether particles module is added
149 logical, public, protected :: mhd_particles = .false.
150 !> Whether magnetofriction is added
151 logical, public, protected :: mhd_magnetofriction = .false.
152 !> Whether GLM-MHD is used to control div B
153 logical, public, protected :: mhd_glm = .false.
154 !> Whether extended GLM-MHD is used with additional sources
155 logical, public, protected :: mhd_glm_extended = .true.
156 !> Whether TRAC method is used
157 logical, public, protected :: mhd_trac = .false.
158 !> Which TRAC method is used
159 integer, public, protected :: mhd_trac_type=1
160 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
161 integer, public, protected :: mhd_trac_finegrid=4
162 !> Whether internal energy is solved instead of total energy
163 logical, public, protected :: mhd_internal_e = .false.
164 !> Whether hydrodynamic energy is solved instead of total energy
165 logical, public, protected :: mhd_hydrodynamic_e = .false.
166 !> Whether divB cleaning sources are added splitting from fluid solver
167 logical, public, protected :: source_split_divb = .false.
168 !> Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved
169 logical, public, protected :: mhd_semirelativistic = .false.
170 !> Whether plasma is partially ionized
171 logical, public, protected :: mhd_partial_ionization = .false.
172 !> Whether CAK radiation line force is activated
173 logical, public, protected :: mhd_cak_force = .false.
174 !> Whether radiation-gas interaction is handled using flux limited diffusion
175 logical, public, protected :: mhd_radiation_fld = .false.
176 !> whether split off equilibrium density and pressure
177 logical, public :: has_equi_rho_and_p = .false.
178 logical, public :: mhd_equi_thermal = .false.
179 !> whether dump full variables (when splitting is used) in a separate dat file
180 logical, public, protected :: mhd_dump_full_vars = .false.
181 !> Whether divB is computed with a fourth order approximation
182 integer, public, protected :: mhd_divb_nth = 1
183 !> Add divB wave in Roe solver
184 logical, public :: divbwave = .true.
185 !> clean initial divB
186 logical, public :: clean_initial_divb = .false.
187 ! remove the below flag and assume default value = .false.
188 ! when eq state properly implemented everywhere
189 ! and not anymore through units
190 logical, public, protected :: eq_state_units = .true.
191 !> To control divB=0 fix for boundary
192 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
193 !> B0 field is force-free
194 logical, public, protected :: b0field_forcefree=.true.
195 !> Whether an total energy equation is used
196 logical :: total_energy = .true.
197 !> Whether numerical resistive heating is included when solving partial energy equation
198 logical, public :: numerical_resistive_heating = .false.
199 !> Whether gravity work is included in energy equation
200 logical :: gravity_energy
201 !> Method type to clean divergence of B
202 character(len=std_len), public, protected :: typedivbfix = 'linde'
203 !> Method type of constrained transport
204 character(len=std_len), public, protected :: type_ct = 'uct_contact'
205 !> Update all equations due to divB cleaning
206 character(len=std_len) :: typedivbdiff = 'all'
207 !> type of fluid for thermal conduction
208 type(tc_fluid), public, allocatable :: tc_fl
209 !> type of fluid for thermal emission synthesis
210 type(te_fluid), public, allocatable :: te_fl_mhd
211 !> type of fluid for radiative cooling
212 type(rc_fluid), public, allocatable :: rc_fl
213
214 !define the subroutine interface for the ambipolar mask
215 abstract interface
216
217 subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
219 integer, intent(in) :: ixi^l, ixo^l
220 double precision, intent(in) :: x(ixi^s,1:ndim)
221 double precision, intent(in) :: w(ixi^s,1:nw)
222 double precision, intent(inout) :: res(ixi^s)
223 end subroutine mask_subroutine
224
225 end interface
226
227 procedure(mask_subroutine), pointer :: usr_mask_ambipolar => null()
228 procedure(sub_convert), pointer :: mhd_to_primitive => null()
229 procedure(sub_convert), pointer :: mhd_to_conserved => null()
230 procedure(sub_small_values), pointer :: mhd_handle_small_values => null()
231 procedure(sub_get_pthermal), pointer :: mhd_get_pthermal => null()
232 procedure(sub_get_pthermal), pointer :: mhd_get_rfactor => null()
233 procedure(sub_get_pthermal), pointer :: mhd_get_temperature=> null()
234 ! Public methods
235 public :: usr_mask_ambipolar
236 public :: mhd_phys_init
237 public :: mhd_get_pthermal
238 public :: mhd_get_temperature
239 public :: mhd_get_v
240 public :: mhd_get_rho
241 public :: mhd_to_conserved
242 public :: mhd_to_primitive
243 public :: mhd_e_to_ei
244 public :: mhd_ei_to_e
245 public :: mhd_face_to_center
246 public :: get_divb
247 public :: get_current
248 !> needed public if we want to use the ambipolar coefficient in the user file
249 public :: multiplyambicoef
250 public :: get_normalized_divb
252 public :: mhd_mag_en_all
253 {^nooned
255 }
256 ! Begin: following relevant for radiative MHD using FLD
257 ! first four are local and only of interest for mod_usr applications
258 ! where they can be used in diagnostics
259 ! NOTE those with _prim expect primitives on entry
261 public :: mhd_get_csrad2
262 public :: mhd_get_trad
264 ! the following used in FLD module
265 ! as pointer phys_get_Rfactor
266 public :: mhd_get_rfactor
267 ! as pointer phys_get_csrad2
268 public :: mhd_get_csrad2_prim
269 ! the following used in FLD modules
270 ! as pointer phys_get_tgas
272 ! End: following relevant for radiative MHD using FLD
274
275contains
276
277 !> Read this module"s parameters from a file
278 subroutine mhd_read_params(files)
280 use mod_particles, only: particles_eta, particles_etah
281 character(len=*), intent(in) :: files(:)
282 integer :: n
283
284 namelist /mhd_list/ mhd_energy, mhd_n_tracer, mhd_gamma, mhd_adiab,&
288 typedivbdiff, type_ct, divbwave, he_abundance, &
291 particles_eta, particles_etah,has_equi_rho_and_p,mhd_equi_thermal,&
299
300 do n = 1, size(files)
301 open(unitpar, file=trim(files(n)), status="old")
302 read(unitpar, mhd_list, end=111)
303111 close(unitpar)
304 end do
305
306 end subroutine mhd_read_params
307
308 !> Write this module's parameters to a snapsoht
309 subroutine mhd_write_info(fh)
311 integer, intent(in) :: fh
312
313 integer :: er
314 integer, parameter :: n_par = 1
315 double precision :: values(n_par)
316 integer, dimension(MPI_STATUS_SIZE) :: st
317 character(len=name_len) :: names(n_par)
318
319 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
320
321 names(1) = "gamma"
322 values(1) = mhd_gamma
323 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
324 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
325 end subroutine mhd_write_info
326
327 subroutine mhd_phys_init()
332 use mod_gravity, only: gravity_init
337 use mod_cak_force, only: cak_init
339 use mod_geometry
341 {^nooned
343 }
344 use mod_fld
345
346 integer :: itr, idir
347
348 call mhd_read_params(par_files)
349
350 if(mhd_internal_e) then
351 if(mhd_hydrodynamic_e) then
352 mhd_hydrodynamic_e=.false.
353 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_internal_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_internal_e=T'
358 end if
359 end if
360
361 if(mhd_hydrodynamic_e) then
362 if(mhd_internal_e) then
363 mhd_internal_e=.false.
364 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_hydrodynamic_e=T'
365 end if
366 if(b0field) then
367 b0field=.false.
368 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_hydrodynamic_e=T'
369 end if
370 if(has_equi_rho_and_p) then
371 has_equi_rho_and_p=.false.
372 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_hydrodynamic_e=T'
373 end if
374 end if
375
376 if(mhd_semirelativistic) then
377 if(b0field) then
378 b0field=.false.
379 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_semirelativistic=T'
380 endif
381 if(has_equi_rho_and_p) then
382 has_equi_rho_and_p=.false.
383 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_semirelativistic=T'
384 end if
385 if(mhd_hydrodynamic_e) then
386 mhd_hydrodynamic_e=.false.
387 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_semirelativistic=T'
388 end if
389 end if
390
391 if(.not. mhd_energy) then
392 if(mhd_internal_e) then
393 mhd_internal_e=.false.
394 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_energy=F'
395 end if
396 if(mhd_hydrodynamic_e) then
397 mhd_hydrodynamic_e=.false.
398 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_energy=F'
399 end if
402 if(mype==0) write(*,*) 'WARNING: set mhd_thermal_conduction=F when mhd_energy=F'
403 end if
404 if(mhd_hyperbolic_tc) then
405 mhd_hyperbolic_tc=.false.
406 if(mype==0) write(*,*) 'WARNING: set mhd_hyperbolic_tc=F when mhd_energy=F'
407 end if
408 if(mhd_radiative_cooling) then
410 if(mype==0) write(*,*) 'WARNING: set mhd_radiative_cooling=F when mhd_energy=F'
411 end if
412 if(mhd_trac) then
413 mhd_trac=.false.
414 if(mype==0) write(*,*) 'WARNING: set mhd_trac=F when mhd_energy=F'
415 end if
418 if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when mhd_energy=F'
419 end if
420 if(b0field) then
421 b0field=.false.
422 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_energy=F'
423 end if
424 if(has_equi_rho_and_p) then
425 has_equi_rho_and_p=.false.
426 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_energy=F'
427 end if
428 end if
429 if(.not.eq_state_units) then
432 if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when eq_state_units=F'
433 end if
434 end if
435
438 if(mype==0) write(*,*) 'WARNING: set either parabolic TC or hyperbolic TC to F'
439 if(mype==0) write(*,*) 'WARNING: defaulting to only mhd_hyperbolic_tc=T'
440 end if
441 {^ifoned
443 call mpistop("mhd_hyperbolic_tc_use_perp is not supported in 1D")
444 end if
445 }
446
447 physics_type = "mhd"
448 phys_energy=mhd_energy
449 phys_internal_e=mhd_internal_e
452 phys_partial_ionization=mhd_partial_ionization
453
454 phys_gamma = mhd_gamma
456
457 if(mhd_energy) then
459 total_energy=.false.
460 else
462 total_energy=.true.
463 end if
464 else
465 total_energy=.false.
466 end if
467 phys_total_energy=total_energy
468 if(mhd_energy) then
469 if(mhd_internal_e) then
470 gravity_energy=.false.
471 else
472 gravity_energy=.true.
473 end if
474 else
475 gravity_energy=.false.
476 end if
477
478 {^ifoned
479 if(mhd_trac .and. mhd_trac_type .gt. 2) then
481 if(mype==0) write(*,*) 'WARNING: reset mhd_trac_type=1 for 1D simulation'
482 end if
483 }
484 if(mhd_trac .and. mhd_trac_type .le. 4) then
485 mhd_trac_mask=bigdouble
486 if(mype==0) write(*,*) 'WARNING: set mhd_trac_mask==bigdouble for global TRAC method'
487 end if
489
491 if(ndim==1) typedivbfix='none'
492 select case (typedivbfix)
493 case ('none')
494 type_divb = divb_none
495 {^nooned
496 case ('multigrid')
497 if(mhd_radiation_fld) call mpistop('To verify whether mg usage for FLD versus divB can be combined')
498 type_divb = divb_multigrid
499 use_multigrid = .true.
500 mg%operator_type = mg_laplacian
501 phys_global_source_after => mhd_clean_divb_multigrid
502 }
503 case ('glm')
504 mhd_glm = .true.
505 need_global_cmax = .true.
506 type_divb = divb_glm
507 case ('powel', 'powell')
508 type_divb = divb_powel
509 case ('janhunen')
510 type_divb = divb_janhunen
511 case ('linde')
512 type_divb = divb_linde
513 case ('lindejanhunen')
514 type_divb = divb_lindejanhunen
515 case ('lindepowel')
516 type_divb = divb_lindepowel
517 case ('lindeglm')
518 mhd_glm = .true.
519 need_global_cmax = .true.
520 type_divb = divb_lindeglm
521 case ('ct')
522 type_divb = divb_ct
523 stagger_grid = .true.
524 case default
525 call mpistop('Unknown divB fix')
526 end select
527
528
529
530 allocate(start_indices(number_species),stop_indices(number_species))
531 ! set the index of the first flux variable for species 1
532 start_indices(1)=1
533 ! Determine flux variables
534 rho_ = var_set_rho()
535
536 allocate(mom(ndir))
537 mom(:) = var_set_momentum(ndir)
538 m^c_=mom(^c);
539
540 ! Set index of energy variable
541 if (mhd_energy) then
542 nwwave = 8
543 e_ = var_set_energy() ! energy density
544 p_ = e_ ! gas pressure
545 else
546 nwwave = 7
547 e_ = -1
548 p_ = -1
549 end if
550
551 allocate(mag(ndir))
552 mag(:) = var_set_bfield(ndir)
553 b^c_=mag(^c);
554
555 if (mhd_glm) then
556 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
557 else
558 psi_ = -1
559 end if
560
561 if(mhd_hyperbolic_tc) then
562 qpar_ = var_set_fluxvar('q', 'q', need_bc=.false.)
564 qperp_ = var_set_fluxvar('qperp', 'qperp', need_bc=.false.)
565 else
566 qperp_ = -1
567 end if
568 need_global_cmax=.true.
569 else
570 qpar_ = -1
571 qperp_ = -1
572 end if
573
574 if (mhd_fip) then
575 fip_ = var_set_fluxvar('rho_fip', 'fip', need_bc=.false.)
576 else
577 fip_ = -1
578 end if
579
580 allocate(tracer(mhd_n_tracer))
581 ! Set starting index of tracers
582 do itr = 1, mhd_n_tracer
583 tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
584 end do
585
586 if(mhd_radiation_fld)then
587 if(mhd_cak_force)then
588 if(mype==0) then
589 write(*,*)'Warning: CAK force addition together with FLD radiation'
590 endif
591 endif
593 if(mype==0) then
594 write(*,*)'Warning: Optically thin cooling together with FLD radiation'
595 endif
596 endif
597 if(.not.mhd_energy)then
598 call mpistop('using FLD implies the use of an energy equation, set mhd_energy=T')
599 else
601 call mpistop('using FLD not yet with semirelativistic energy formalism')
602 endif
604 call mpistop('using FLD not yet with hydrodynamic or internal energy formalism')
605 endif
606 if(has_equi_rho_and_p)then
607 call mpistop('using FLD not yet with split off rho and p')
608 endif
609 ! Note: so far ok with total energy equation but allow both split or unsplit B0
610 !> set added variable and equation for radiation energy
611 r_e = var_set_radiation_energy()
612 phys_get_tgas => mhd_get_temperature_from_prim
613 phys_get_csrad2 => mhd_get_csrad2_prim
614 !> Initiate radiation-closure module
615 call fld_init(mhd_gamma)
616 endif
617 else
618 r_e=-1
619 endif
620
621 ! set temperature as an auxiliary variable to get ionization degree
623 te_ = var_set_auxvar('Te','Te')
624 else
625 te_ = -1
626 end if
627
628 ! set number of variables which need update ghostcells
629 nwgc=nwflux+nwaux
630
631 ! set the index of the last flux variable for species 1
632 stop_indices(1)=nwflux
633
634 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
635 tweight_ = -1
636 if(mhd_trac) then
637 tcoff_ = var_set_wextra()
638 iw_tcoff=tcoff_
639 if(mhd_trac_type .ge. 3) then
640 tweight_ = var_set_wextra()
641 endif
642 else
643 tcoff_ = -1
644 end if
645
646 ! set indices of equi vars and update number_equi_vars
648 if(has_equi_rho_and_p) then
651 iw_equi_rho = equi_rho0_
654 iw_equi_p = equi_pe0_
655 endif
656 ! determine number of stagger variables
657 nws=ndim
658
659 nvector = 2 ! No. vector vars
660 allocate(iw_vector(nvector))
661 iw_vector(1) = mom(1) - 1
662 iw_vector(2) = mag(1) - 1
663
664 ! Check whether custom flux types have been defined
665 if (.not. allocated(flux_type)) then
666 allocate(flux_type(ndir, nwflux))
667 flux_type = flux_default
668 else if (any(shape(flux_type) /= [ndir, nwflux])) then
669 call mpistop("phys_check error: flux_type has wrong shape")
670 end if
671
672 if(nwflux>mag(ndir)) then
673 ! for flux of tracers, using hll flux
674 flux_type(:,mag(ndir)+1:nwflux)=flux_hll
675 end if
676
677 if(ndim>1) then
678 if(mhd_glm) then
679 flux_type(:,psi_)=flux_special
680 do idir=1,ndir
681 flux_type(idir,mag(idir))=flux_special
682 end do
683 else
684 do idir=1,ndir
685 flux_type(idir,mag(idir))=flux_tvdlf
686 end do
687 end if
688 end if
689
690 phys_get_rho => mhd_get_rho
691 phys_get_dt => mhd_get_dt
692 if(mhd_semirelativistic) then
693 if(mhd_energy) then
694 phys_get_cmax => mhd_get_cmax_semirelati
695 else
696 phys_get_cmax => mhd_get_cmax_semirelati_noe
697 end if
698 else
699 if(mhd_energy) then
700 phys_get_cmax => mhd_get_cmax_origin
701 else
702 phys_get_cmax => mhd_get_cmax_origin_noe
703 end if
704 end if
705 phys_get_tcutoff => mhd_get_tcutoff
706 phys_get_h_speed => mhd_get_h_speed
707 if(has_equi_rho_and_p) then
708 phys_get_cbounds => mhd_get_cbounds_split_rho
709 else if(mhd_semirelativistic) then
710 phys_get_cbounds => mhd_get_cbounds_semirelati
711 else
712 phys_get_cbounds => mhd_get_cbounds
713 end if
714 if(mhd_hydrodynamic_e) then
715 phys_to_primitive => mhd_to_primitive_hde
716 mhd_to_primitive => mhd_to_primitive_hde
717 phys_to_conserved => mhd_to_conserved_hde
718 mhd_to_conserved => mhd_to_conserved_hde
719 else if(mhd_semirelativistic) then
720 if(mhd_energy) then
721 phys_to_primitive => mhd_to_primitive_semirelati
722 mhd_to_primitive => mhd_to_primitive_semirelati
723 phys_to_conserved => mhd_to_conserved_semirelati
724 mhd_to_conserved => mhd_to_conserved_semirelati
725 else
726 phys_to_primitive => mhd_to_primitive_semirelati_noe
727 mhd_to_primitive => mhd_to_primitive_semirelati_noe
728 phys_to_conserved => mhd_to_conserved_semirelati_noe
729 mhd_to_conserved => mhd_to_conserved_semirelati_noe
730 end if
731 else
732 if(has_equi_rho_and_p) then
733 phys_to_primitive => mhd_to_primitive_split_rho
734 mhd_to_primitive => mhd_to_primitive_split_rho
735 phys_to_conserved => mhd_to_conserved_split_rho
736 mhd_to_conserved => mhd_to_conserved_split_rho
737 else if(mhd_internal_e) then
738 phys_to_primitive => mhd_to_primitive_inte
739 mhd_to_primitive => mhd_to_primitive_inte
740 phys_to_conserved => mhd_to_conserved_inte
741 mhd_to_conserved => mhd_to_conserved_inte
742 else if(mhd_energy) then
743 phys_to_primitive => mhd_to_primitive_origin
744 mhd_to_primitive => mhd_to_primitive_origin
745 phys_to_conserved => mhd_to_conserved_origin
746 mhd_to_conserved => mhd_to_conserved_origin
747 else
748 phys_to_primitive => mhd_to_primitive_origin_noe
749 mhd_to_primitive => mhd_to_primitive_origin_noe
750 phys_to_conserved => mhd_to_conserved_origin_noe
751 mhd_to_conserved => mhd_to_conserved_origin_noe
752 end if
753 end if
754 if(mhd_hydrodynamic_e) then
755 phys_get_flux => mhd_get_flux_hde
756 else if(mhd_semirelativistic) then
757 if(mhd_energy) then
758 phys_get_flux => mhd_get_flux_semirelati
759 else
760 phys_get_flux => mhd_get_flux_semirelati_noe
761 end if
762 else
763 if(b0field.or.has_equi_rho_and_p) then
764 phys_get_flux => mhd_get_flux_split
765 else if(mhd_energy) then
766 phys_get_flux => mhd_get_flux
767 else
768 phys_get_flux => mhd_get_flux_noe
769 end if
770 end if
771 phys_get_v => mhd_get_v
772 if(mhd_semirelativistic) then
773 phys_add_source_geom => mhd_add_source_geom_semirelati
774 else if(b0field.or.has_equi_rho_and_p) then
775 phys_add_source_geom => mhd_add_source_geom_split
776 else
777 phys_add_source_geom => mhd_add_source_geom
778 end if
779 phys_add_source => mhd_add_source
780 phys_check_params => mhd_check_params
781 phys_write_info => mhd_write_info
782
783 if(mhd_internal_e) then
784 phys_handle_small_values => mhd_handle_small_values_inte
785 mhd_handle_small_values => mhd_handle_small_values_inte
786 phys_check_w => mhd_check_w_inte
787 else if(mhd_hydrodynamic_e) then
788 phys_handle_small_values => mhd_handle_small_values_hde
789 mhd_handle_small_values => mhd_handle_small_values_hde
790 phys_check_w => mhd_check_w_hde
791 else if(mhd_semirelativistic) then
792 phys_handle_small_values => mhd_handle_small_values_semirelati
793 mhd_handle_small_values => mhd_handle_small_values_semirelati
794 phys_check_w => mhd_check_w_semirelati
795 else if(has_equi_rho_and_p) then
796 phys_handle_small_values => mhd_handle_small_values_split
797 mhd_handle_small_values => mhd_handle_small_values_split
798 phys_check_w => mhd_check_w_split
799 else if(mhd_energy) then
800 phys_handle_small_values => mhd_handle_small_values_origin
801 mhd_handle_small_values => mhd_handle_small_values_origin
802 phys_check_w => mhd_check_w_origin
803 else
804 phys_handle_small_values => mhd_handle_small_values_noe
805 mhd_handle_small_values => mhd_handle_small_values_noe
806 phys_check_w => mhd_check_w_noe
807 end if
808
809 if(mhd_internal_e) then
810 phys_get_pthermal => mhd_get_pthermal_inte
811 mhd_get_pthermal => mhd_get_pthermal_inte
812 else if(mhd_hydrodynamic_e) then
813 phys_get_pthermal => mhd_get_pthermal_hde
814 mhd_get_pthermal => mhd_get_pthermal_hde
815 else if(mhd_semirelativistic) then
816 phys_get_pthermal => mhd_get_pthermal_semirelati
817 mhd_get_pthermal => mhd_get_pthermal_semirelati
818 else if(mhd_energy) then
819 phys_get_pthermal => mhd_get_pthermal_origin
820 mhd_get_pthermal => mhd_get_pthermal_origin
821 else
822 phys_get_pthermal => mhd_get_pthermal_noe
823 mhd_get_pthermal => mhd_get_pthermal_noe
824 end if
825
826 if(number_equi_vars>0) then
827 phys_set_equi_vars => set_equi_vars_grid
828 endif
829
830 if(type_divb==divb_glm) then
831 phys_modify_wlr => mhd_modify_wlr
832 end if
833
834 ! choose Rfactor in ideal gas law
836 mhd_get_rfactor=>rfactor_from_temperature_ionization
837 phys_update_temperature => mhd_update_temperature
838 else if(associated(usr_rfactor)) then
840 else
841 mhd_get_rfactor=>rfactor_from_constant_ionization
842 end if
843
844 phys_get_rfactor=>mhd_get_rfactor
845
847 mhd_get_temperature => mhd_get_temperature_from_te
848 else
849 if(mhd_internal_e) then
850 if(has_equi_rho_and_p) then
851 mhd_get_temperature => mhd_get_temperature_from_eint_with_equi
852 else
853 mhd_get_temperature => mhd_get_temperature_from_eint
854 end if
855 else
857 end if
858 end if
859
860 ! if using ct stagger grid, boundary divb=0 is not done here
861 if(stagger_grid) then
862 select case(type_ct)
863 case('average')
864 transverse_ghost_cells = 1
865 phys_get_ct_velocity => mhd_get_ct_velocity_average
866 phys_update_faces => mhd_update_faces_average
867 case('uct_contact')
868 transverse_ghost_cells = 1
869 phys_get_ct_velocity => mhd_get_ct_velocity_contact
870 phys_update_faces => mhd_update_faces_contact
871 case('uct_hll')
872 transverse_ghost_cells = 2
873 phys_get_ct_velocity => mhd_get_ct_velocity_hll
874 phys_update_faces => mhd_update_faces_hll
875 case default
876 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
877 end select
878 phys_face_to_center => mhd_face_to_center
879 phys_modify_wlr => mhd_modify_wlr
880 else if(ndim>1) then
881 phys_boundary_adjust => mhd_boundary_adjust
882 end if
883
884 {^nooned
885 ! clean initial divb
887 call mpistop('To verify whether mg usage for FLD versus divB can be combined')
888 if(clean_initial_divb) phys_clean_divb => mhd_clean_divb_multigrid
889 }
890
891 ! derive units from basic units
892 call mhd_physical_units()
893
894 if(mhd_hyperbolic_tc) then
895 if(mhd_hyperbolic_tc_kappa==0.d0) then
896 if(si_unit) then
898 else
900 end if
901 else
903 end if
904
906 select case(mhd_hyperbolic_tc_perp_mode)
907 case(1)
909 if(si_unit) then
912 else
915 end if
916 end if
917 case(2)
918 if(mhd_hyperbolic_tc_bmin==0.d0) then
920 end if
921 end select
922 end if
923 end if
924 if(.not. mhd_energy .and. mhd_thermal_conduction) then
925 call mpistop("thermal conduction needs mhd_energy=T")
926 end if
927 if(.not. mhd_energy .and. mhd_hyperbolic_tc) then
928 call mpistop("hyperbolic thermal conduction needs mhd_energy=T")
929 end if
930 if(.not. mhd_energy .and. mhd_radiative_cooling) then
931 call mpistop("radiative cooling needs mhd_energy=T")
932 end if
933
934 if(mhd_equi_thermal)then
935 if((.not.has_equi_rho_and_p).or.(.not.total_energy))then
936 mhd_equi_thermal=.false.
937 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no splitting or total e in use'
938 else
940 if(mype==0) write(*,*) 'Will subtract thermal balance in TC or RC with mhd_equi_thermal=T'
941 else
942 mhd_equi_thermal=.false.
943 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no TC or RC in use'
944 endif
945 endif
946 endif
947
948 ! initialize thermal conduction module
949 if (mhd_thermal_conduction) then
950 call sts_init()
952
953 allocate(tc_fl)
954 call tc_get_mhd_params(tc_fl,tc_params_read_mhd)
955 if(ndim==1) then
956 call add_sts_method(mhd_get_tc_dt_hd,mhd_sts_set_source_tc_hd,e_,1,e_,1,.false.)
957 else
958 call add_sts_method(mhd_get_tc_dt_mhd,mhd_sts_set_source_tc_mhd,e_,1,e_,1,.false.)
959 endif
960 if(mhd_internal_e) then
961 if(has_equi_rho_and_p) then
962 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint_with_equi
963 else
964 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint
965 end if
966 else
967 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_etot
968 end if
969 if(has_equi_rho_and_p) then
970 tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint_with_equi
971 if(mhd_equi_thermal) then
972 tc_fl%subtract_equi = .true.
973 tc_fl%get_temperature_equi => mhd_get_temperature_equi
974 tc_fl%get_rho_equi => mhd_get_rho_equi
975 else
976 tc_fl%subtract_equi = .false.
977 end if
978 else
979 tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint
980 end if
981 if(.not.mhd_internal_e) then
982 if(mhd_hydrodynamic_e) then
983 call set_conversion_methods_to_head(mhd_e_to_ei_hde, mhd_ei_to_e_hde)
984 else if(mhd_semirelativistic) then
985 call set_conversion_methods_to_head(mhd_e_to_ei_semirelati, mhd_ei_to_e_semirelati)
986 else
988 end if
989 end if
990 call set_error_handling_to_head(mhd_tc_handle_small_e)
991 tc_fl%get_rho => mhd_get_rho
992 tc_fl%e_ = e_
993 tc_fl%Tcoff_ = tcoff_
994 end if
995
996 ! Initialize radiative cooling module
997 if (mhd_radiative_cooling) then
999 allocate(rc_fl)
1000 rc_fl%fip_ = fip_
1001 call radiative_cooling_init(rc_fl,rc_params_read)
1002 rc_fl%get_rho => mhd_get_rho
1003 rc_fl%get_pthermal => mhd_get_pthermal
1004 rc_fl%get_var_Rfactor => mhd_get_rfactor
1005 rc_fl%e_ = e_
1006 rc_fl%Tcoff_ = tcoff_
1007 rc_fl%has_equi = has_equi_rho_and_p
1008 if(mhd_equi_thermal) then
1009 rc_fl%subtract_equi = .true.
1010 rc_fl%get_rho_equi => mhd_get_rho_equi
1011 rc_fl%get_pthermal_equi => mhd_get_pe_equi
1012 rc_fl%get_temperature_equi => mhd_get_temperature_equi
1013 else
1014 rc_fl%subtract_equi = .false.
1015 end if
1016 end if
1017
1018{^ifthreed
1019 ! for thermal emission images
1020 allocate(te_fl_mhd)
1021 te_fl_mhd%get_rho=> mhd_get_rho
1022 te_fl_mhd%get_pthermal=> mhd_get_pthermal
1023 te_fl_mhd%get_var_Rfactor => mhd_get_rfactor
1024 phys_te_images => mhd_te_images
1025}
1026
1027 ! consistency check for hyperresistivity implementation
1028 if (mhd_eta_hyper>0.0d0) then
1029 if(mype==0) then
1030 write(*,*) '*****Using hyperresistivity: with mhd_eta_hyper :', mhd_eta_hyper
1031 endif
1032 if(b0field) then
1033 ! hyperresistivity not ok yet with splitting
1034 call mpistop("Must have B0field=F when using hyperresistivity")
1035 end if
1036 endif
1037 if (mhd_eta_hyper<0.0d0) then
1038 call mpistop("Must have mhd_eta_hyper positive when using hyperresistivity")
1039 endif
1040
1041 ! Initialize viscosity module
1042 if (mhd_viscosity) then
1043 call viscosity_init(phys_wider_stencil)
1044 end if
1045
1046 ! Initialize gravity module
1047 if(mhd_gravity) then
1048 call gravity_init()
1049 end if
1050
1051 ! Initialize rotating frame module
1052 if(mhd_rotating_frame) then
1053 if(has_equi_rho_and_p) then
1054 ! mod_rotating_frame does not handle splitting of density
1055 call mpistop("Must have has_equi_rho_and_p=F when mhd_rotating_frame=T")
1056 end if
1057 call rotating_frame_init()
1058 endif
1059
1060
1061 ! initialize magnetofriction module
1062 if(mhd_magnetofriction) then
1064 end if
1065
1066 if(mhd_hall) then
1067 if(mhd_semirelativistic) then
1068 ! semirelativistic does not incorporate hall terms
1069 call mpistop("Must have mhd_hall=F when mhd_semirelativistic=T")
1070 end if
1071 if(coordinate>1)then
1072 ! normal unsplit case or split cases do not have geometric sources for Hall included
1073 call mpistop("Must have Cartesian coordinates for Hall")
1074 endif
1075 ! For Hall, we need one more reconstructed layer since currents are computed
1076 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1077 phys_wider_stencil = 1
1078 end if
1079
1080 if(mhd_ambipolar) then
1081 if(mhd_ambipolar_sts) then
1082 call sts_init()
1084 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mag(1),&
1085 ndir,mag(1),ndir,.true.)
1086 else
1087 ! any total energy or no energy at all case is handled here
1088 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mom(ndir)+1,&
1089 mag(ndir)-mom(ndir),mag(1),ndir,.true.)
1090 end if
1091 else
1092 mhd_ambipolar_exp=.true.
1093 ! For flux ambipolar term, we need one more reconstructed layer since currents are computed
1094 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1095 phys_wider_stencil = 1
1096 end if
1097 end if
1098
1099 ! initialize ionization degree table
1101
1102 ! Initialize CAK radiation force module
1103 if (mhd_cak_force) then
1105 call mpistop("CAK implementation not available in internal or semirelativistic variants")
1106 endif
1107 if(has_equi_rho_and_p) then
1108 call mpistop("CAK force implementation not available for split off pressure and density")
1109 endif
1110 call cak_init(mhd_gamma)
1111 endif
1112
1113 end subroutine mhd_phys_init
1114
1115{^ifthreed
1116 subroutine mhd_te_images
1119
1120 select case(convert_type)
1121 case('EIvtiCCmpi','EIvtuCCmpi')
1123 case('ESvtiCCmpi','ESvtuCCmpi')
1125 case('SIvtiCCmpi','SIvtuCCmpi')
1127 case('WIvtiCCmpi','WIvtuCCmpi')
1129 case default
1130 call mpistop("Error in synthesize emission: Unknown convert_type")
1131 end select
1132 end subroutine mhd_te_images
1133}
1134
1135!!start th cond
1136 ! wrappers for STS functions in thermal_conductivity module
1137 ! which take as argument the tc_fluid (defined in the physics module)
1138 subroutine mhd_sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1142 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1143 double precision, intent(in) :: x(ixi^s,1:ndim)
1144 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1145 double precision, intent(in) :: my_dt
1146 logical, intent(in) :: fix_conserve_at_step
1147 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1148 end subroutine mhd_sts_set_source_tc_mhd
1149
1150 subroutine mhd_sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1154 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1155 double precision, intent(in) :: x(ixi^s,1:ndim)
1156 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1157 double precision, intent(in) :: my_dt
1158 logical, intent(in) :: fix_conserve_at_step
1159 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1160 end subroutine mhd_sts_set_source_tc_hd
1161
1162 function mhd_get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1163 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1164 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1165 !and T=p/rho
1168
1169 integer, intent(in) :: ixi^l, ixo^l
1170 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1171 double precision, intent(in) :: w(ixi^s,1:nw)
1172 double precision :: dtnew
1173
1174 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1175 end function mhd_get_tc_dt_mhd
1176
1177 function mhd_get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1178 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1179 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1180 !and T=p/rho
1183
1184 integer, intent(in) :: ixi^l, ixo^l
1185 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1186 double precision, intent(in) :: w(ixi^s,1:nw)
1187 double precision :: dtnew
1188
1189 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1190 end function mhd_get_tc_dt_hd
1191
1192 subroutine mhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
1194
1195 integer, intent(in) :: ixi^l,ixo^l
1196 double precision, intent(inout) :: w(ixi^s,1:nw)
1197 double precision, intent(in) :: x(ixi^s,1:ndim)
1198 integer, intent(in) :: step
1199 character(len=140) :: error_msg
1200
1201 write(error_msg,"(a,i3)") "Thermal conduction step ", step
1202 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
1203 end subroutine mhd_tc_handle_small_e
1204
1205 ! fill in tc_fluid fields from namelist
1206 subroutine tc_params_read_mhd(fl)
1208 type(tc_fluid), intent(inout) :: fl
1209
1210 double precision :: tc_k_para=0d0
1211 double precision :: tc_k_perp=0d0
1212 integer :: n
1213 ! list parameters
1214 logical :: tc_perpendicular=.false.
1215 logical :: tc_saturate=.false.
1216 character(len=std_len) :: tc_slope_limiter="MC"
1217
1218 namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp
1219
1220 do n = 1, size(par_files)
1221 open(unitpar, file=trim(par_files(n)), status="old")
1222 read(unitpar, tc_list, end=111)
1223111 close(unitpar)
1224 end do
1225
1226 fl%tc_perpendicular = tc_perpendicular
1227 fl%tc_saturate = tc_saturate
1228 fl%tc_k_para = tc_k_para
1229 fl%tc_k_perp = tc_k_perp
1230 select case(tc_slope_limiter)
1231 case ('no','none')
1232 fl%tc_slope_limiter = 0
1233 case ('MC')
1234 ! monotonized central limiter Woodward and Collela limiter (eq.3.51h)
1235 fl%tc_slope_limiter = 1
1236 case('minmod')
1237 ! minmod limiter
1238 fl%tc_slope_limiter = 2
1239 case ('superbee')
1240 ! Roes superbee limiter (eq.3.51i)
1241 fl%tc_slope_limiter = 3
1242 case ('koren')
1243 ! Barry Koren Right variant
1244 fl%tc_slope_limiter = 4
1245 case ('vanleer')
1246 ! van Leer limiter
1247 fl%tc_slope_limiter = 5
1248 case default
1249 call mpistop("Unknown tc_slope_limiter, choose MC, minmod, superbee, koren, vanleer")
1250 end select
1251 end subroutine tc_params_read_mhd
1252!!end th cond
1253
1254!!rad cool
1255 subroutine rc_params_read(fl)
1257 use mod_constants, only: bigdouble
1258 type(rc_fluid), intent(inout) :: fl
1259
1260 !> Lower limit of temperature
1261 double precision :: tlow=bigdouble
1262 double precision :: rad_damp_height=0.5d0
1263 double precision :: rad_damp_scale=0.15d0
1264 integer :: n
1265 ! list parameters
1266 integer :: ncool = 4000
1267 !> Fixed temperature not lower than tlow
1268 logical :: tfix=.false.
1269 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1270 logical :: rc_split=.false.
1271 logical :: rad_damp=.false.
1272 !> Name of cooling curve
1273 character(len=std_len) :: coolcurve='JCcorona'
1274 logical :: rad_newton = .false.
1275 double precision :: rad_newton_trad = 0.006d0
1276 double precision :: rad_newton_rhosurf = 1.d4
1277 double precision :: rad_newton_pthick = 25.d0
1278
1279 namelist /rc_list/ coolcurve, ncool, tlow, tfix, rc_split, &
1280 rad_newton, rad_newton_trad, rad_newton_rhosurf, &
1281 rad_newton_pthick, rad_damp, rad_damp_height, rad_damp_scale
1282
1283 do n = 1, size(par_files)
1284 open(unitpar, file=trim(par_files(n)), status="old")
1285 read(unitpar, rc_list, end=111)
1286111 close(unitpar)
1287 end do
1288
1289 fl%ncool=ncool
1290 fl%coolcurve=coolcurve
1291 fl%tlow=tlow
1292 fl%Tfix=tfix
1293 fl%rc_split=rc_split
1294 fl%rad_damp=rad_damp
1295 fl%rad_damp_height=rad_damp_height
1296 fl%rad_damp_scale=rad_damp_scale
1297 fl%rad_newton=rad_newton
1298 fl%rad_newton_trad=rad_newton_trad
1299 fl%rad_newton_rhosurf=rad_newton_rhosurf
1300 fl%rad_newton_pthick=rad_newton_pthick
1301 end subroutine rc_params_read
1302
1303 !> sets the equilibrium variables
1304 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1306 use mod_usr_methods
1307 integer, intent(in) :: igrid, ixi^l, ixo^l
1308 double precision, intent(in) :: x(ixi^s,1:ndim)
1309
1310 double precision :: delx(ixi^s,1:ndim)
1311 double precision :: xc(ixi^s,1:ndim),xshift^d
1312 integer :: idims, ixc^l, hxo^l, ix, idims2
1313
1314 if(slab_uniform)then
1315 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1316 else
1317 ! for all non-cartesian and stretched cartesian coordinates
1318 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1319 endif
1320
1321 do idims=1,ndim
1322 hxo^l=ixo^l-kr(idims,^d);
1323 if(stagger_grid) then
1324 ! ct needs all transverse cells
1325 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1326 else
1327 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1328 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1329 end if
1330 ! always xshift=0 or 1/2
1331 xshift^d=half*(one-kr(^d,idims));
1332 do idims2=1,ndim
1333 select case(idims2)
1334 {case(^d)
1335 do ix = ixc^lim^d
1336 ! xshift=half: this is the cell center coordinate
1337 ! xshift=0: this is the cell edge i+1/2 coordinate
1338 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1339 end do\}
1340 end select
1341 end do
1342 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1343 end do
1344 end subroutine set_equi_vars_grid_faces
1345
1346 !> sets the equilibrium variables
1347 subroutine set_equi_vars_grid(igrid)
1349 use mod_usr_methods
1350
1351 integer, intent(in) :: igrid
1352
1353 !values at the center
1354 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1355
1356 !values at the interfaces
1357 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1358
1359 end subroutine set_equi_vars_grid
1360
1361 ! w, wnew conserved, add splitted variables back to wnew
1362 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1364 integer, intent(in) :: ixi^l,ixo^l, nwc
1365 double precision, intent(in) :: w(ixi^s, 1:nw)
1366 double precision, intent(in) :: x(ixi^s,1:ndim)
1367 double precision :: wnew(ixo^s, 1:nwc)
1368
1369 if(has_equi_rho_and_p) then
1370 wnew(ixo^s,rho_)=w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0)
1371 else
1372 wnew(ixo^s,rho_)=w(ixo^s,rho_)
1373 endif
1374 wnew(ixo^s,mom(:))=w(ixo^s,mom(:))
1375
1376 if (b0field) then
1377 ! add background magnetic field B0 to B
1378 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
1379 else
1380 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))
1381 end if
1382
1383 if(mhd_energy) then
1384 wnew(ixo^s,e_)=w(ixo^s,e_)
1385 if(has_equi_rho_and_p) then
1386 wnew(ixo^s,e_)=wnew(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
1387 end if
1388 if(b0field .and. total_energy) then
1389 wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1390 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1391 end if
1392 end if
1393
1394 end function convert_vars_splitting
1395
1396 subroutine mhd_check_params
1398 use mod_usr_methods
1399 use mod_geometry, only: coordinate
1401 use mod_particles, only: particles_init, particles_eta, particles_etah
1402 use mod_particles, only: npayload,nusrpayload, &
1403 ngridvars,num_particles,physics_type_particles
1404 use mod_fld
1405
1406 double precision :: a,b,xfrac,yfrac
1407
1408 ! Initialize particles module here, so all extra and user vars are sample
1409 if(mhd_particles) then
1410 call particles_init()
1411 if (particles_eta < zero) particles_eta = mhd_eta
1412 if (particles_etah < zero) particles_eta = mhd_etah
1413 end if
1414
1415 ! after user parameter setting
1416 gamma_1=mhd_gamma-1.d0
1417 if (.not. mhd_energy) then
1418 if (mhd_gamma <= 0.0d0) call mpistop ("Error: mhd_gamma <= 0")
1419 if (mhd_adiab < 0.0d0) call mpistop ("Error: mhd_adiab < 0")
1421 else
1422 if (mhd_gamma <= 0.0d0 .or. mhd_gamma == 1.0d0) &
1423 call mpistop ("Error: mhd_gamma <= 0 or mhd_gamma == 1")
1424 inv_gamma_1=1.d0/gamma_1
1425 small_e = small_pressure * inv_gamma_1
1426 small_r_e = small_pressure*inv_gamma_1
1427 end if
1428
1429 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1430 call mpistop("usr_set_equi_vars has to be implemented in the user file")
1431 endif
1432 if(convert .or. autoconvert) then
1433 if(convert_type .eq. 'dat_generic_mpi') then
1434 if(mhd_dump_full_vars) then
1435 if(mype .eq. 0) print*, " add conversion method: split -> full "
1436 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1437 endif
1438 endif
1439 endif
1440
1441 if(mhd_radiation_fld) then
1442 if(.not.use_imex_scheme)then
1443 call mpistop('select IMEX scheme for FLD radiation use')
1444 endif
1445 if(use_multigrid)then
1446 call phys_set_mg_bounds()
1447 else
1448 if(.not.fld_no_mg)call mpistop('multigrid must have BCs for IMEX and FLD radiation use')
1449 endif
1450 if(mype==0)then
1451 write(*,*)'==FLD SETUP======================'
1452 write(*,*)'Using FLD with settings:'
1453 write(*,*)'Using FLD with settings: mhd_radiation_fld=',mhd_radiation_fld
1454 write(*,*)'Using FLD with settings: fld_fluxlimiter=',fld_fluxlimiter
1455 write(*,*)'Using FLD with settings: fld_interaction_method=',fld_interaction_method
1456 write(*,*)'Using FLD with settings: fld_opacity_law=',fld_opacity_law
1457 write(*,*)'Using FLD with settings: fld_kappa0=',fld_kappa0
1458 write(*,*)'Using FLD with settings: fld_opal_table=',fld_opal_table
1459 write(*,*)'Using FLD with settings: fld_Radforce_split=',fld_radforce_split
1460 write(*,*)'Using FLD with settings: fld_bisect_tol=',fld_bisect_tol
1461 write(*,*)'Using FLD with settings: fld_diff_tol=',fld_diff_tol
1462 write(*,*)'Using FLD with settings: nth_for_diff_mg=',nth_for_diff_mg
1463 write(*,*)' FLD has use_imex_scheme and use_multigrid=',use_imex_scheme,use_multigrid
1464 print *,'const_rad_a =',const_rad_a
1465 print *,'NORMALIZED arad_norm=',arad_norm
1466 print *,'NORMALIZED c_norm=',c_norm
1467 print *,'const_kappae =',const_kappae
1468 if(trim(fld_opacity_law).eq.'const_norm')then
1469 print *,'NORMALIZED fld_kappa0 =',fld_kappa0
1470 print *,'physical value (in cgs or SI) =',fld_kappa0*unit_opacity
1471 endif
1472 if(trim(fld_opacity_law).eq.'const')then
1473 print *,'physical fld_kappa (in cgs or SI) =',fld_kappa0
1474 print *,'NORMALIZED value =',fld_kappa0/unit_opacity
1475 endif
1476 if(fld_gamma/=mhd_gamma)call mpistop("you must set fld_gamma and mhd_gamma equal!")
1477 write(*,*)'===FLD SETUP====================='
1478 endif
1479 endif
1480
1481 if(mype==0)then
1482 write(*,*)'====MHD run with settings===================='
1483 write(*,*)'Using mod_mhd_phys with settings:'
1484 write(*,*)'SI_unit=',si_unit
1485 write(*,*)'Dimensionality :',ndim
1486 write(*,*)'vector components:',ndir
1487 write(*,*)'coordinate set to type,slab:',coordinate,slab
1488 write(*,*)'number of variables nw=',nw
1489 write(*,*)' start index iwstart=',iwstart
1490 write(*,*)'number of vector variables=',nvector
1491 write(*,*)'number of stagger variables nws=',nws
1492 write(*,*)'number of variables with BCs=',nwgc
1493 write(*,*)'number of vars with fluxes=',nwflux
1494 write(*,*)'number of vars with flux + BC=',nwfluxbc
1495 write(*,*)'number of auxiliary variables=',nwaux
1496 write(*,*)'number of extra vars without flux=',nwextra
1497 write(*,*)'number of extra vars for wextra=',nw_extra
1498 write(*,*)'number of auxiliary I/O variables=',nwauxio
1499 write(*,*)'number of mhd_n_tracer=',mhd_n_tracer
1500 write(*,*)' mhd_energy=',mhd_energy,' with total_energy=',total_energy
1501 write(*,*)' mhd_semirelativistic=',mhd_semirelativistic
1502 write(*,*)' mhd_internal_e=',mhd_internal_e
1503 write(*,*)' mhd_hydrodynamic_e=',mhd_hydrodynamic_e
1504 write(*,*)' mhd_gravity=',mhd_gravity
1505 write(*,*)' mhd_eta=',mhd_eta,' nonzero implies resistivity'
1506 write(*,*)' mhd_viscosity=',mhd_viscosity
1507 write(*,*)' mhd_radiative_cooling=',mhd_radiative_cooling
1508 write(*,*)' mhd_cak_force=',mhd_cak_force
1509 write(*,*)' mhd_radiation_fld=',mhd_radiation_fld
1510 write(*,*)' mhd_thermal_conduction=',mhd_thermal_conduction
1511 write(*,*)' mhd_hyperbolic_tc=',mhd_hyperbolic_tc
1512 write(*,*)' mhd_trac=',mhd_trac
1513 write(*,*)' mhd_hall=',mhd_hall
1514 write(*,*)' mhd_ambipolar=',mhd_ambipolar
1515 write(*,*)' mhd_eta_hyper=',mhd_eta_hyper
1516 write(*,*)' mhd_rotating_frame=',mhd_rotating_frame
1517 write(*,*)' mhd_particles=',mhd_particles
1518 if(mhd_particles) then
1519 write(*,*) '*****Using particles: with mhd_eta, mhd_etah :', mhd_eta, mhd_etah
1520 write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
1521 write(*,*) '*****Using particles: npayload,ngridvars :', npayload,ngridvars
1522 write(*,*) '*****Using particles: nusrpayload :', nusrpayload
1523 write(*,*) '*****Using particles: num_particles :', num_particles
1524 write(*,*) '*****Using particles: physics_type_particles=',physics_type_particles
1525 end if
1526 write(*,*)'number of ghostcells=',nghostcells
1527 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
1528 write(*,*)'==========================================='
1529 print *,'========EOS and UNITS==========='
1530 print *,'SI_unit =',si_unit
1531 print *,'gamma=',mhd_gamma
1532 print *,'eq_state_units=',eq_state_units
1533 print *,'He_abundance =',he_abundance
1534 print *,'RR =',rr
1535 print *,'========EOS and UNITS==========='
1536 print *,'unit_time =',unit_time
1537 print *,'unit_length =',unit_length
1538 print *,'unit_velocity =',unit_velocity
1539 print *,'unit_pressure =',unit_pressure
1540 print *,'unit_numberdensity =',unit_numberdensity
1541 print *,'unit_density =',unit_density
1542 print *,'unit_temperature =',unit_temperature
1543 print *,'unit_mass =',unit_mass
1544 print *,'unit_Erad =',unit_erad
1545 print *,'unit_radflux =',unit_radflux
1546 print *,'unit_magneticfield =',unit_magneticfield
1547 if(si_unit)then
1548 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/miu0_si
1549 else
1550 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/(4.0d0*dpi)
1551 endif
1552 print *, 'CHECK that p_u ',unit_pressure,' equals ',unit_density*unit_velocity**2
1553 print *, 'CHECK that L_u ',unit_length,' equals ',unit_velocity*unit_time
1554 print *, 'CHECK that M_u',unit_mass,' equals ',unit_density*unit_length**3
1555 print *, 'density to numberdensity has factor ',unit_density/unit_numberdensity
1556 if(si_unit)then
1557 print *, ' compare this to ',mp_si*(1.d0+4.d0*he_abundance)
1558 else
1559 print *, ' compare this to ',mp_cgs*(1.d0+4.d0*he_abundance)
1560 endif
1561 print *, 'pressure to n T has factor ',unit_pressure/(unit_numberdensity*unit_temperature)
1562 if(si_unit)then
1563 print *, ' compare this to ',kb_si*(2.d0+3.d0*he_abundance)
1566 else
1567 print *, ' compare this to ',kb_cgs*(2.d0+3.d0*he_abundance)
1570 endif
1571 if(eq_state_units)then
1572 print *, 'mean molecular weight mu is =',a/b,' = ', (1.d0+4.d0*he_abundance)/(2.d0+3.d0*he_abundance)
1573 xfrac=1.d0/a
1574 yfrac=4.d0*he_abundance/(1.d0+4.d0*he_abundance)
1575 print *, 'mass fraction hydrogen X is =',1/a,' and this equals ', 1.d0/(1.d0+4.d0*he_abundance)
1576 print *, 'mass fraction helium Y is =',yfrac
1577 print *, ' check that 1/mu', b/a,' is equal to 2X+3Y/4=',2.d0*xfrac+3.d0*yfrac/4.d0
1578 print *, ' ratio n_e/n_p=',1.d0+2.0d0*he_abundance
1579 endif
1580 print *,'========UNITS==========='
1581 endif
1582
1583 end subroutine mhd_check_params
1584
1585 subroutine mhd_physical_units()
1587 double precision :: mp,kb,miu0,c_lightspeed,xfrac,sigma_telectron
1588 double precision :: a,b
1589 ! Derive scaling units
1590 if(si_unit) then
1591 mp=mp_si
1592 kb=kb_si
1593 miu0=miu0_si
1594 const_sigmasb=sigma_sb_si
1595 c_lightspeed=c_si
1596 sigma_telectron=sigma_te_si
1597 else
1598 mp=mp_cgs
1599 kb=kb_cgs
1600 miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
1601 const_sigmasb=sigma_sb_cgs
1602 c_lightspeed=const_c
1603 sigma_telectron=sigma_te_cgs
1604 end if
1605 if(eq_state_units) then
1606 a=1d0+4d0*he_abundance
1607 if(mhd_partial_ionization) then
1609 else
1610 b=2d0+3d0*he_abundance
1611 end if
1612 rr=1d0
1613 xfrac=1.d0/a
1614 else
1615 a=1d0
1616 b=1d0
1617 rr=(1d0+h_ion_fr+he_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0))/(1d0+4d0*he_abundance)
1618 end if
1619 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
1620 if(unit_density/=1.d0) then
1622 else if(unit_numberdensity/=1.d0) then
1624 end if
1625 if(unit_temperature/=1.d0) then
1629 if(unit_length/=1.d0) then
1631 else if(unit_time/=1.d0) then
1633 end if
1634 else if(unit_magneticfield/=1.d0) then
1638 if(unit_length/=1.d0) then
1640 else if(unit_time/=1.d0) then
1642 end if
1643 else if(unit_pressure/=1.d0) then
1647 if(unit_length/=1.d0) then
1649 else if(unit_time/=1.d0) then
1651 end if
1652 else if(unit_velocity/=1.d0) then
1656 if(unit_length/=1.d0) then
1658 else if(unit_time/=1.d0) then
1660 end if
1661 else if(unit_time/=1.d0) then
1666 end if
1667 else if(unit_temperature/=1.d0) then
1668 ! units of temperature and velocity are dependent
1669 if(unit_magneticfield/=1.d0) then
1674 if(unit_length/=1.d0) then
1676 else if(unit_time/=1.d0) then
1678 end if
1679 else if(unit_pressure/=1.d0) then
1684 if(unit_length/=1.d0) then
1686 else if(unit_time/=1.d0) then
1688 end if
1689 end if
1690 else if(unit_magneticfield/=1.d0) then
1691 ! units of magnetic field and pressure are dependent
1692 if(unit_velocity/=1.d0) then
1697 if(unit_length/=1.d0) then
1699 else if(unit_time/=1.d0) then
1701 end if
1702 else if(unit_time/=0.d0) then
1708 end if
1709 else if(unit_pressure/=1.d0) then
1710 if(unit_velocity/=1.d0) then
1715 if(unit_length/=1.d0) then
1717 else if(unit_time/=1.d0) then
1719 end if
1720 else if(unit_time/=0.d0) then
1726 end if
1727 end if
1728 ! Additional units needed for the particles
1729 c_norm=c_lightspeed/unit_velocity
1731 if (.not. si_unit) unit_charge = unit_charge*const_c
1733
1734 if(mhd_semirelativistic) then
1735 if(mhd_reduced_c<1.d0) then
1736 ! dimensionless speed
1737 inv_squared_c0=1.d0
1738 inv_squared_c=1.d0/mhd_reduced_c**2
1739 else
1740 inv_squared_c0=(unit_velocity/c_lightspeed)**2
1741 inv_squared_c=(unit_velocity/mhd_reduced_c)**2
1742 end if
1743 end if
1744
1745 !> Units for radiative flux and opacity as used in FLD
1746 ! this is the radiation constant in either cgs or SI units
1747 const_rad_a=4.d0*const_sigmasb/c_lightspeed
1748 ! this is the dimensionless conversion factor for Erad to Trad
1750 ! This is the Thomson scattering opacity in the correct units
1751 ! note that the hydrogen mass fraction X=1/a in eq_state_units
1752 if(eq_state_units) then
1753 const_kappae=sigma_telectron*(1.d0+xfrac)/(2.0d0*mp)
1754 else
1755 const_kappae=0.34d0 ! specific value in cm^2/g for He=0.1 in cgs
1756 endif
1757 ! these are the units
1761
1762 end subroutine mhd_physical_units
1763
1764 subroutine mhd_check_w_semirelati(primitive,ixI^L,ixO^L,w,flag)
1766
1767 logical, intent(in) :: primitive
1768 logical, intent(inout) :: flag(ixi^s,1:nw)
1769 integer, intent(in) :: ixi^l, ixo^l
1770 double precision, intent(in) :: w(ixi^s,nw)
1771
1772 double precision :: tmp,b(1:ndir),v(1:ndir),factor
1773 integer :: ix^d
1774
1775 flag=.false.
1776 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1777
1778 if(mhd_energy) then
1779 if(primitive) then
1780 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1781 else
1782 if(mhd_internal_e) then
1783 {do ix^db=ixomin^db,ixomax^db \}
1784 if(w(ix^d,e_) < small_e) flag(ix^d,e_) = .true.
1785 {end do\}
1786 else
1787 {do ix^db=ixomin^db,ixomax^db \}
1788 ! Convert momentum to velocity
1789 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
1790 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
1791 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
1792 ! E=Bxv
1793 {^ifthreec
1794 b(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
1795 b(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
1796 b(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1797 }
1798 {^iftwoc
1799 b(1)=zero
1800 ! switch 3 with 2 to allow ^C from 1 to 2
1801 b(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1802 }
1803 {^ifonec
1804 b(1)=zero
1805 }
1806 ! Calculate internal e = e-eK-eB-eE
1807 tmp=w(ix^d,e_)-half*((^c&v(^c)**2+)*w(ix^d,rho_)&
1808 +(^c&w(ix^d,b^c_)**2+)+(^c&b(^c)**2+)*inv_squared_c)
1809 if(tmp<small_e) flag(ix^d,e_)=.true.
1810 {end do\}
1811 end if
1812 end if
1813 end if
1814
1815 end subroutine mhd_check_w_semirelati
1816
1817 subroutine mhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1819
1820 logical, intent(in) :: primitive
1821 integer, intent(in) :: ixi^l, ixo^l
1822 double precision, intent(in) :: w(ixi^s,nw)
1823 logical, intent(inout) :: flag(ixi^s,1:nw)
1824
1825 integer :: ix^d
1826
1827 flag=.false.
1828 {do ix^db=ixomin^db,ixomax^db\}
1829 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1830 if(primitive) then
1831 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1832 else
1833 if(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+&
1834 (^c&w(ix^d,b^c_)**2+))<small_e) flag(ix^d,e_) = .true.
1835 end if
1836 if(mhd_radiation_fld)then
1837 if(w(ix^d,r_e)<small_r_e) flag(ix^d,r_e) = .true.
1838 endif
1839 {end do\}
1840
1841 end subroutine mhd_check_w_origin
1842
1843 subroutine mhd_check_w_split(primitive,ixI^L,ixO^L,w,flag)
1845
1846 logical, intent(in) :: primitive
1847 integer, intent(in) :: ixi^l, ixo^l
1848 double precision, intent(in) :: w(ixi^s,nw)
1849 logical, intent(inout) :: flag(ixi^s,1:nw)
1850
1851 double precision :: tmp
1852 integer :: ix^d
1853
1854 flag=.false.
1855 {do ix^db=ixomin^db,ixomax^db\}
1856 tmp=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1857 if(tmp<small_density) flag(ix^d,rho_) = .true.
1858 if(primitive) then
1859 if(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)<small_pressure) flag(ix^d,e_) = .true.
1860 else
1861 tmp=w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/tmp+(^c&w(ix^d,b^c_)**2+))
1862 if(tmp+block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1<small_e) flag(ix^d,e_) = .true.
1863 end if
1864 {end do\}
1865
1866 end subroutine mhd_check_w_split
1867
1868 subroutine mhd_check_w_noe(primitive,ixI^L,ixO^L,w,flag)
1870
1871 logical, intent(in) :: primitive
1872 integer, intent(in) :: ixi^l, ixo^l
1873 double precision, intent(in) :: w(ixi^s,nw)
1874 logical, intent(inout) :: flag(ixi^s,1:nw)
1875
1876 integer :: ix^d
1877
1878 flag=.false.
1879 {do ix^db=ixomin^db,ixomax^db\}
1880 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1881 {end do\}
1882
1883 end subroutine mhd_check_w_noe
1884
1885 subroutine mhd_check_w_inte(primitive,ixI^L,ixO^L,w,flag)
1887
1888 logical, intent(in) :: primitive
1889 integer, intent(in) :: ixi^l, ixo^l
1890 double precision, intent(in) :: w(ixi^s,nw)
1891 logical, intent(inout) :: flag(ixi^s,1:nw)
1892
1893 integer :: ix^d
1894
1895 flag=.false.
1896 {do ix^db=ixomin^db,ixomax^db\}
1897 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1898 if(primitive) then
1899 if(w(ix^d,p_) < small_pressure) flag(ix^d,e_) = .true.
1900 else
1901 if(w(ix^d,e_)<small_e) flag(ix^d,e_) = .true.
1902 end if
1903 {end do\}
1904
1905 end subroutine mhd_check_w_inte
1906
1907 subroutine mhd_check_w_hde(primitive,ixI^L,ixO^L,w,flag)
1909
1910 logical, intent(in) :: primitive
1911 integer, intent(in) :: ixi^l, ixo^l
1912 double precision, intent(in) :: w(ixi^s,nw)
1913 logical, intent(inout) :: flag(ixi^s,1:nw)
1914
1915 integer :: ix^d
1916
1917 flag=.false.
1918 {do ix^db=ixomin^db,ixomax^db\}
1919 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1920 if(primitive) then
1921 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1922 else
1923 if(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)<small_e) flag(ix^d,e_) = .true.
1924 end if
1925 {end do\}
1926
1927 end subroutine mhd_check_w_hde
1928
1929 subroutine mhd_bound_fip(primitive, ixI^L, ixO^L, w)
1931 logical, intent(in) :: primitive
1932 integer, intent(in) :: ixi^l, ixo^l
1933 double precision, intent(inout) :: w(ixi^s,1:nw)
1934
1935 double precision :: rho_safe(ixi^s), fip_prim(ixi^s)
1936
1937 if (.not. mhd_fip) return
1938
1939 if (primitive) then
1940 w(ixo^s,fip_) = min(maxfip, max(minfip, w(ixo^s,fip_)))
1941 else
1942 if (has_equi_rho_and_p) then
1943 rho_safe(ixo^s) = max(w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i), small_density)
1944 else
1945 rho_safe(ixo^s) = max(w(ixo^s,rho_), small_density)
1946 end if
1947 fip_prim(ixo^s) = w(ixo^s,fip_) / rho_safe(ixo^s)
1948 fip_prim(ixo^s) = min(maxfip, max(minfip, fip_prim(ixo^s)))
1949 w(ixo^s,fip_) = rho_safe(ixo^s) * fip_prim(ixo^s)
1950 end if
1951 end subroutine mhd_bound_fip
1952
1953 !> Transform primitive variables into conservative ones
1954 subroutine mhd_to_conserved_origin(ixI^L,ixO^L,w,x)
1956 integer, intent(in) :: ixi^l, ixo^l
1957 double precision, intent(inout) :: w(ixi^s, nw)
1958 double precision, intent(in) :: x(ixi^s, 1:ndim)
1959
1960 integer :: ix^d
1961
1962 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
1963 {do ix^db=ixomin^db,ixomax^db\}
1964 ! Calculate total energy from pressure, kinetic and magnetic energy
1965 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1966 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
1967 +(^c&w(ix^d,b^c_)**2+))
1968 ! Convert velocity to momentum
1969 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1970 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
1971 {end do\}
1972
1973 end subroutine mhd_to_conserved_origin
1974
1975 !> Transform primitive variables into conservative ones
1976 subroutine mhd_to_conserved_origin_noe(ixI^L,ixO^L,w,x)
1978 integer, intent(in) :: ixi^l, ixo^l
1979 double precision, intent(inout) :: w(ixi^s, nw)
1980 double precision, intent(in) :: x(ixi^s, 1:ndim)
1981
1982 integer :: ix^d
1983
1984 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
1985 {do ix^db=ixomin^db,ixomax^db\}
1986 ! Convert velocity to momentum
1987 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1988 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
1989 {end do\}
1990
1991 end subroutine mhd_to_conserved_origin_noe
1992
1993 !> Transform primitive variables into conservative ones
1994 subroutine mhd_to_conserved_hde(ixI^L,ixO^L,w,x)
1996 integer, intent(in) :: ixi^l, ixo^l
1997 double precision, intent(inout) :: w(ixi^s, nw)
1998 double precision, intent(in) :: x(ixi^s, 1:ndim)
1999
2000 integer :: ix^d
2001
2002 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2003 {do ix^db=ixomin^db,ixomax^db\}
2004 ! Calculate total energy from pressure, kinetic and magnetic energy
2005 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
2006 +half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
2007 ! Convert velocity to momentum
2008 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
2009 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
2010 {end do\}
2011
2012 end subroutine mhd_to_conserved_hde
2013
2014 !> Transform primitive variables into conservative ones
2015 subroutine mhd_to_conserved_inte(ixI^L,ixO^L,w,x)
2017 integer, intent(in) :: ixi^l, ixo^l
2018 double precision, intent(inout) :: w(ixi^s, nw)
2019 double precision, intent(in) :: x(ixi^s, 1:ndim)
2020
2021 integer :: ix^d
2022
2023 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2024 {do ix^db=ixomin^db,ixomax^db\}
2025 ! Calculate total energy from pressure, kinetic and magnetic energy
2026 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1
2027 ! Convert velocity to momentum
2028 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
2029 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
2030 {end do\}
2031
2032 end subroutine mhd_to_conserved_inte
2033
2034 !> Transform primitive variables into conservative ones
2035 subroutine mhd_to_conserved_split_rho(ixI^L,ixO^L,w,x)
2037 integer, intent(in) :: ixi^l, ixo^l
2038 double precision, intent(inout) :: w(ixi^s, nw)
2039 double precision, intent(in) :: x(ixi^s, 1:ndim)
2040
2041 double precision :: rho
2042 integer :: ix^d
2043
2044 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2045 {do ix^db=ixomin^db,ixomax^db\}
2046 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i)
2047 ! Calculate total energy from pressure, kinetic and magnetic energy
2048 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
2049 +half*((^c&w(ix^d,m^c_)**2+)*rho&
2050 +(^c&w(ix^d,b^c_)**2+))
2051 ! Convert velocity to momentum
2052 ^c&w(ix^d,m^c_)=rho*w(ix^d,m^c_)\
2053 if (mhd_fip) w(ix^d,fip_) = rho * w(ix^d,fip_)
2054 {end do\}
2055
2056 end subroutine mhd_to_conserved_split_rho
2057
2058 !> Transform primitive variables into conservative ones
2059 subroutine mhd_to_conserved_semirelati(ixI^L,ixO^L,w,x)
2061 integer, intent(in) :: ixi^l, ixo^l
2062 double precision, intent(inout) :: w(ixi^s, nw)
2063 double precision, intent(in) :: x(ixi^s, 1:ndim)
2064
2065 ! electric field and poynting flux S
2066 double precision :: ef(ixo^s,1:ndir), s(ixo^s,1:ndir)
2067 integer :: ix^d
2068
2069 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2070 {do ix^db=ixomin^db,ixomax^db\}
2071 {^ifthreec
2072 ef(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
2073 ef(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
2074 ef(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2075 s(ix^d,1)=ef(ix^d,2)*w(ix^d,b3_)-ef(ix^d,3)*w(ix^d,b2_)
2076 s(ix^d,2)=ef(ix^d,3)*w(ix^d,b1_)-ef(ix^d,1)*w(ix^d,b3_)
2077 s(ix^d,3)=ef(ix^d,1)*w(ix^d,b2_)-ef(ix^d,2)*w(ix^d,b1_)
2078 }
2079 {^iftwoc
2080 ef(ix^d,1)=zero
2081 ! switch 3 with 2 to add 3 when ^C from 1 to 2
2082 ef(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2083 s(ix^d,1)=-ef(ix^d,2)*w(ix^d,b2_)
2084 s(ix^d,2)=ef(ix^d,2)*w(ix^d,b1_)
2085 }
2086 {^ifonec
2087 ef(ix^d,1)=zero
2088 s(ix^d,1)=zero
2089 }
2090 if(mhd_internal_e) then
2091 ! internal energy
2092 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1
2093 else
2094 ! equation (9)
2095 ! Calculate total energy from internal, kinetic and magnetic energy
2096 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
2097 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
2098 +(^c&w(ix^d,b^c_)**2+)&
2099 +(^c&ef(ix^d,^c)**2+)*inv_squared_c)
2100 end if
2101
2102 ! Convert velocity to momentum, equation (9)
2103 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*inv_squared_c\
2104 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
2105
2106 {end do\}
2107
2108 end subroutine mhd_to_conserved_semirelati
2109
2110 subroutine mhd_to_conserved_semirelati_noe(ixI^L,ixO^L,w,x)
2112 integer, intent(in) :: ixi^l, ixo^l
2113 double precision, intent(inout) :: w(ixi^s, nw)
2114 double precision, intent(in) :: x(ixi^s, 1:ndim)
2115
2116 double precision :: e(ixo^s,1:ndir), s(ixo^s,1:ndir)
2117 integer :: ix^d
2118
2119 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2120 {do ix^db=ixomin^db,ixomax^db\}
2121 {^ifthreec
2122 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
2123 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
2124 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2125 s(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
2126 s(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
2127 s(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
2128 }
2129 {^iftwoc
2130 e(ix^d,1)=zero
2131 ! switch 3 with 2 to add 3 when ^C from 1 to 2
2132 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2133 s(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
2134 s(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
2135 }
2136 {^ifonec
2137 s(ix^d,1)=zero
2138 }
2139 ! Convert velocity to momentum, equation (9)
2140 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*inv_squared_c\
2141 if (mhd_fip) w(ix^d,fip_) = w(ix^d,rho_) * w(ix^d,fip_)
2142 {end do\}
2143 end subroutine mhd_to_conserved_semirelati_noe
2144
2145 !> Transform conservative variables into primitive ones
2146 subroutine mhd_to_primitive_origin(ixI^L,ixO^L,w,x)
2148 integer, intent(in) :: ixi^l, ixo^l
2149 double precision, intent(inout) :: w(ixi^s, nw)
2150 double precision, intent(in) :: x(ixi^s, 1:ndim)
2151
2152 double precision :: inv_rho
2153 integer :: ix^d
2154
2155 if (fix_small_values) then
2156 ! fix small values preventing NaN numbers in the following converting
2157 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin')
2158 end if
2159
2160 {do ix^db=ixomin^db,ixomax^db\}
2161 inv_rho = 1.d0/w(ix^d,rho_)
2162 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) * inv_rho
2163 ! Convert momentum to velocity
2164 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2165 ! Calculate pressure = (gamma-1) * (e-ek-eb)
2166 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2167 -half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)&
2168 +(^c&w(ix^d,b^c_)**2+)))
2169 {end do\}
2170 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2171 end subroutine mhd_to_primitive_origin
2172
2173 !> Transform conservative variables into primitive ones
2174 subroutine mhd_to_primitive_origin_noe(ixI^L,ixO^L,w,x)
2176 integer, intent(in) :: ixi^l, ixo^l
2177 double precision, intent(inout) :: w(ixi^s, nw)
2178 double precision, intent(in) :: x(ixi^s, 1:ndim)
2179
2180 double precision :: inv_rho
2181 integer :: ix^d
2182
2183 if (fix_small_values) then
2184 ! fix small values preventing NaN numbers in the following converting
2185 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin_noe')
2186 end if
2187
2188 {do ix^db=ixomin^db,ixomax^db\}
2189 inv_rho = 1.d0/w(ix^d,rho_)
2190 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) * inv_rho
2191 ! Convert momentum to velocity
2192 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2193 {end do\}
2194 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2195 end subroutine mhd_to_primitive_origin_noe
2196
2197 !> Transform conservative variables into primitive ones
2198 subroutine mhd_to_primitive_hde(ixI^L,ixO^L,w,x)
2200 integer, intent(in) :: ixi^l, ixo^l
2201 double precision, intent(inout) :: w(ixi^s, nw)
2202 double precision, intent(in) :: x(ixi^s, 1:ndim)
2203
2204 double precision :: inv_rho
2205 integer :: ix^d
2206
2207 if (fix_small_values) then
2208 ! fix small values preventing NaN numbers in the following converting
2209 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_hde')
2210 end if
2211
2212 {do ix^db=ixomin^db,ixomax^db\}
2213 inv_rho = 1d0/w(ix^d,rho_)
2214 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) * inv_rho
2215 ! Convert momentum to velocity
2216 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2217 ! Calculate pressure = (gamma-1) * (e-ek)
2218 w(ix^d,p_)=gamma_1*(w(ix^d,e_)-half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+))
2219 {end do\}
2220 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2221 end subroutine mhd_to_primitive_hde
2222
2223 !> Transform conservative variables into primitive ones
2224 subroutine mhd_to_primitive_inte(ixI^L,ixO^L,w,x)
2226 integer, intent(in) :: ixi^l, ixo^l
2227 double precision, intent(inout) :: w(ixi^s, nw)
2228 double precision, intent(in) :: x(ixi^s, 1:ndim)
2229
2230 double precision :: inv_rho
2231 integer :: ix^d
2232
2233 if (fix_small_values) then
2234 ! fix small values preventing NaN numbers in the following converting
2235 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_inte')
2236 end if
2237
2238 {do ix^db=ixomin^db,ixomax^db\}
2239 ! Calculate pressure = (gamma-1) * e_internal
2240 w(ix^d,p_)=w(ix^d,e_)*gamma_1
2241 ! Convert momentum to velocity
2242 inv_rho = 1.d0/w(ix^d,rho_)
2243 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) * inv_rho
2244 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2245 {end do\}
2246 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2247 end subroutine mhd_to_primitive_inte
2248
2249 !> Transform conservative variables into primitive ones
2250 subroutine mhd_to_primitive_split_rho(ixI^L,ixO^L,w,x)
2252 integer, intent(in) :: ixi^l, ixo^l
2253 double precision, intent(inout) :: w(ixi^s, nw)
2254 double precision, intent(in) :: x(ixi^s, 1:ndim)
2255
2256 double precision :: inv_rho
2257 integer :: ix^d
2258
2259 if (fix_small_values) then
2260 ! fix small values preventing NaN numbers in the following converting
2261 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_split_rho')
2262 end if
2263
2264 {do ix^db=ixomin^db,ixomax^db\}
2265 inv_rho=1.d0/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2266 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) * inv_rho
2267 ! Convert momentum to velocity
2268 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2269 ! Calculate pressure = (gamma-1) * (e-ek-eb)
2270 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2271 -half*((w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))*&
2272 (^c&w(ix^d,m^c_)**2+)+(^c&w(ix^d,b^c_)**2+)))
2273 {end do\}
2274 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2275 end subroutine mhd_to_primitive_split_rho
2276
2277 !> Transform conservative variables into primitive ones
2278 subroutine mhd_to_primitive_semirelati(ixI^L,ixO^L,w,x)
2280 integer, intent(in) :: ixi^l, ixo^l
2281 double precision, intent(inout) :: w(ixi^s, nw)
2282 double precision, intent(in) :: x(ixi^s, 1:ndim)
2283
2284 double precision :: e(1:ndir), tmp, factor
2285 integer :: ix^d
2286
2287 if (fix_small_values) then
2288 ! fix small values preventing NaN numbers in the following converting
2289 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati')
2290 end if
2291
2292 {do ix^db=ixomin^db,ixomax^db\}
2293 ! Convert momentum to velocity
2294 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2295 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2296 ^c&w(ix^d,m^c_)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2297 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) / w(ix^d,rho_)
2298
2299 if(mhd_internal_e) then
2300 ! internal energy to pressure
2301 w(ix^d,p_)=gamma_1*w(ix^d,e_)
2302 else
2303 ! E=Bxv
2304 {^ifthreec
2305 e(1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
2306 e(2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
2307 e(3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2308 }
2309 {^iftwoc
2310 e(1)=zero
2311 e(2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2312 }
2313 {^ifonec
2314 e(1)=zero
2315 }
2316 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2317 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2318 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
2319 +(^c&w(ix^d,b^c_)**2+)&
2320 +(^c&e(^c)**2+)*inv_squared_c))
2321 end if
2322 {end do\}
2323 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2324 end subroutine mhd_to_primitive_semirelati
2325
2326 !> Transform conservative variables into primitive ones
2327 subroutine mhd_to_primitive_semirelati_noe(ixI^L,ixO^L,w,x)
2329 integer, intent(in) :: ixi^l, ixo^l
2330 double precision, intent(inout) :: w(ixi^s, nw)
2331 double precision, intent(in) :: x(ixi^s, 1:ndim)
2332
2333 double precision :: tmp, factor
2334 integer :: ix^d
2335
2336 if (fix_small_values) then
2337 ! fix small values preventing NaN numbers in the following converting
2338 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati_noe')
2339 end if
2340
2341 {do ix^db=ixomin^db,ixomax^db\}
2342 ! Convert momentum to velocity
2343 if (mhd_fip) w(ix^d,fip_) = w(ix^d,fip_) / w(ix^d,rho_)
2344 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2345 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2346 ^c&w(ix^d,m^c_)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2347 {end do\}
2348 if (mhd_fip) call mhd_bound_fip(.true., ixi^l, ixo^l, w)
2349 end subroutine mhd_to_primitive_semirelati_noe
2350
2351 !> Transform internal energy to total energy
2352 subroutine mhd_ei_to_e(ixI^L,ixO^L,w,x)
2354 integer, intent(in) :: ixi^l, ixo^l
2355 double precision, intent(inout) :: w(ixi^s, nw)
2356 double precision, intent(in) :: x(ixi^s, 1:ndim)
2357
2358 integer :: ix^d
2359
2360 if(has_equi_rho_and_p) then
2361 {do ix^db=ixomin^db,ixomax^db\}
2362 ! Calculate e = ei + ek + eb
2363 w(ix^d,e_)=w(ix^d,e_)&
2364 +half*((^c&w(ix^d,m^c_)**2+)/&
2365 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2366 +(^c&w(ix^d,b^c_)**2+))
2367 {end do\}
2368 else
2369 {do ix^db=ixomin^db,ixomax^db\}
2370 ! Calculate e = ei + ek + eb
2371 w(ix^d,e_)=w(ix^d,e_)&
2372 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2373 +(^c&w(ix^d,b^c_)**2+))
2374 {end do\}
2375 end if
2376 end subroutine mhd_ei_to_e
2377
2378 !> Transform internal energy to hydrodynamic energy
2379 subroutine mhd_ei_to_e_hde(ixI^L,ixO^L,w,x)
2381 integer, intent(in) :: ixi^l, ixo^l
2382 double precision, intent(inout) :: w(ixi^s, nw)
2383 double precision, intent(in) :: x(ixi^s, 1:ndim)
2384
2385 integer :: ix^d
2386
2387 {do ix^db=ixomin^db,ixomax^db\}
2388 ! Calculate e = ei + ek
2389 w(ix^d,e_)=w(ix^d,e_)&
2390 +half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2391 {end do\}
2392
2393 end subroutine mhd_ei_to_e_hde
2394
2395 !> Transform internal energy to total energy and velocity to momentum
2396 subroutine mhd_ei_to_e_semirelati(ixI^L,ixO^L,w,x)
2398 integer, intent(in) :: ixi^l, ixo^l
2399 double precision, intent(inout) :: w(ixi^s, nw)
2400 double precision, intent(in) :: x(ixi^s, 1:ndim)
2401
2402 w(ixo^s,p_)=w(ixo^s,e_)*gamma_1
2403 call mhd_to_conserved_semirelati(ixi^l,ixo^l,w,x)
2404
2405 end subroutine mhd_ei_to_e_semirelati
2406
2407 !> Transform total energy to internal energy
2408 subroutine mhd_e_to_ei(ixI^L,ixO^L,w,x)
2410 integer, intent(in) :: ixi^l, ixo^l
2411 double precision, intent(inout) :: w(ixi^s, nw)
2412 double precision, intent(in) :: x(ixi^s, 1:ndim)
2413
2414 integer :: ix^d
2415
2416 if(has_equi_rho_and_p) then
2417 {do ix^db=ixomin^db,ixomax^db\}
2418 ! Calculate ei = e - ek - eb
2419 w(ix^d,e_)=w(ix^d,e_)&
2420 -half*((^c&w(ix^d,m^c_)**2+)/&
2421 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2422 +(^c&w(ix^d,b^c_)**2+))
2423 {end do\}
2424 else
2425 {do ix^db=ixomin^db,ixomax^db\}
2426 ! Calculate ei = e - ek - eb
2427 w(ix^d,e_)=w(ix^d,e_)&
2428 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2429 +(^c&w(ix^d,b^c_)**2+))
2430 {end do\}
2431 end if
2432
2433 if(fix_small_values) then
2434 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei')
2435 end if
2436
2437 end subroutine mhd_e_to_ei
2438
2439 !> Transform hydrodynamic energy to internal energy
2440 subroutine mhd_e_to_ei_hde(ixI^L,ixO^L,w,x)
2442 integer, intent(in) :: ixi^l, ixo^l
2443 double precision, intent(inout) :: w(ixi^s, nw)
2444 double precision, intent(in) :: x(ixi^s, 1:ndim)
2445
2446 integer :: ix^d
2447
2448 {do ix^db=ixomin^db,ixomax^db\}
2449 ! Calculate ei = e - ek
2450 w(ix^d,e_)=w(ix^d,e_)&
2451 -half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2452 {end do\}
2453
2454 if(fix_small_values) then
2455 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei_hde')
2456 end if
2457
2458 end subroutine mhd_e_to_ei_hde
2459
2460 !> Transform total energy to internal energy and momentum to velocity
2461 subroutine mhd_e_to_ei_semirelati(ixI^L,ixO^L,w,x)
2463 integer, intent(in) :: ixi^l, ixo^l
2464 double precision, intent(inout) :: w(ixi^s, nw)
2465 double precision, intent(in) :: x(ixi^s, 1:ndim)
2466
2467 call mhd_to_primitive_semirelati(ixi^l,ixo^l,w,x)
2468 w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1
2469
2470 end subroutine mhd_e_to_ei_semirelati
2471
2472 subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixI^L, ixO^L, subname)
2475 logical, intent(in) :: primitive
2476 integer, intent(in) :: ixi^l,ixo^l
2477 double precision, intent(inout) :: w(ixi^s,1:nw)
2478 double precision, intent(in) :: x(ixi^s,1:ndim)
2479 character(len=*), intent(in) :: subname
2480
2481 double precision :: e(ixi^s,1:ndir), pressure(ixi^s), v(ixi^s,1:ndir)
2482 double precision :: tmp, factor
2483 integer :: ix^d
2484 logical :: flag(ixi^s,1:nw)
2485
2486 flag=.false.
2487 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
2488
2489 if(mhd_energy) then
2490 if(primitive) then
2491 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
2492 else
2493 {do ix^db=ixomin^db,ixomax^db\}
2494 ! Convert momentum to velocity
2495 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2496 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2497 ^c&v(ix^d,^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2498 ! E=Bxv
2499 {^ifthreec
2500 e(ix^d,1)=w(ix^d,b2_)*v(ix^d,3)-w(ix^d,b3_)*v(ix^d,2)
2501 e(ix^d,2)=w(ix^d,b3_)*v(ix^d,1)-w(ix^d,b1_)*v(ix^d,3)
2502 e(ix^d,3)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2503 }
2504 {^iftwoc
2505 e(ix^d,1)=zero
2506 e(ix^d,2)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2507 }
2508 {^ifonec
2509 e(ix^d,1)=zero
2510 }
2511 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2512 pressure(ix^d)=gamma_1*(w(ix^d,e_)&
2513 -half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2514 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c))
2515 if(pressure(ix^d) < small_pressure) flag(ix^d,p_) = .true.
2516 {end do\}
2517 end if
2518 end if
2519
2520 if(any(flag)) then
2521 select case (small_values_method)
2522 case ("replace")
2523 {do ix^db=ixomin^db,ixomax^db\}
2524 if(flag(ix^d,rho_)) then
2525 w(ix^d,rho_) = small_density
2526 ^c&w(ix^d,m^c_)=0.d0\
2527 end if
2528 if(mhd_energy) then
2529 if(primitive) then
2530 if(flag(ix^d,e_)) w(ix^d,p_) = small_pressure
2531 else
2532 if(flag(ix^d,e_)) then
2533 w(ix^d,e_)=small_pressure*inv_gamma_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2534 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2535 end if
2536 end if
2537 end if
2538 {end do\}
2539 case ("average")
2540 ! do averaging of density
2541 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2542 if(mhd_energy) then
2543 if(primitive) then
2544 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2545 else
2546 w(ixo^s,e_)=pressure(ixo^s)
2547 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2548 {do ix^db=ixomin^db,ixomax^db\}
2549 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2550 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2551 {end do\}
2552 end if
2553 end if
2554 case default
2555 if(.not.primitive) then
2556 ! change to primitive variables
2557 w(ixo^s,mom(1:ndir))=v(ixo^s,1:ndir)
2558 if(mhd_energy) w(ixo^s,e_)=pressure(ixo^s)
2559 end if
2560 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2561 end select
2562 end if
2563 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2564 end subroutine mhd_handle_small_values_semirelati
2565
2566 subroutine mhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
2569 logical, intent(in) :: primitive
2570 integer, intent(in) :: ixi^l,ixo^l
2571 double precision, intent(inout) :: w(ixi^s,1:nw)
2572 double precision, intent(in) :: x(ixi^s,1:ndim)
2573 character(len=*), intent(in) :: subname
2574
2575 integer :: ix^d
2576 logical :: flag(ixi^s,1:nw)
2577
2578 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2579
2580 if(any(flag)) then
2581 select case (small_values_method)
2582 case ("replace")
2583 {do ix^db=ixomin^db,ixomax^db\}
2584 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2585 {
2586 if(small_values_fix_iw(m^c_)) then
2587 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2588 end if
2589 \}
2590 if(primitive) then
2591 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2592 else
2593 if(flag(ix^d,e_)) &
2594 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+))
2595 end if
2596 if(mhd_radiation_fld)then
2597 if(small_values_fix_iw(r_e)) then
2598 if(flag(ix^d,r_e)) w(ix^d,r_e)=small_r_e
2599 endif
2600 endif
2601 {end do\}
2602 case ("average")
2603 ! do averaging of density
2604 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2605 if(primitive)then
2606 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2607 else
2608 ! do averaging of internal energy
2609 {do ix^db=iximin^db,iximax^db\}
2610 w(ix^d,e_)=w(ix^d,e_)&
2611 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2612 {end do\}
2613 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2614 ! convert back
2615 {do ix^db=iximin^db,iximax^db\}
2616 w(ix^d,e_)=w(ix^d,e_)&
2617 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2618 {end do\}
2619 end if
2620 if(mhd_radiation_fld) then
2621 call small_values_average(ixi^l, ixo^l, w, x, flag, r_e)
2622 endif
2623 case default
2624 if(.not.primitive) then
2625 !convert w to primitive
2626 {do ix^db=ixomin^db,ixomax^db\}
2627 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2628 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2629 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)))
2630 {end do\}
2631 end if
2632 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2633 end select
2634 end if
2635 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2636 end subroutine mhd_handle_small_values_origin
2637
2638 subroutine mhd_handle_small_values_split(primitive, w, x, ixI^L, ixO^L, subname)
2641 logical, intent(in) :: primitive
2642 integer, intent(in) :: ixi^l,ixo^l
2643 double precision, intent(inout) :: w(ixi^s,1:nw)
2644 double precision, intent(in) :: x(ixi^s,1:ndim)
2645 character(len=*), intent(in) :: subname
2646
2647 double precision :: rho
2648 integer :: ix^d
2649 logical :: flag(ixi^s,1:nw)
2650
2651 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2652
2653 if(any(flag)) then
2654 select case (small_values_method)
2655 case ("replace")
2656 {do ix^db=ixomin^db,ixomax^db\}
2657 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2658 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density-block%equi_vars(ix^d,equi_rho0_,0)
2659 {
2660 if(small_values_fix_iw(m^c_)) then
2661 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2662 end if
2663 \}
2664 if(primitive) then
2665 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure-block%equi_vars(ix^d,equi_pe0_,0)
2666 else
2667 if(flag(ix^d,e_)) &
2668 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))&
2669 -block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1
2670 end if
2671 {end do\}
2672 case ("average")
2673 ! do averaging of density
2674 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2675 if(primitive)then
2676 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2677 else
2678 ! do averaging of internal energy
2679 {do ix^db=iximin^db,iximax^db\}
2680 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2681 w(ix^d,e_)=w(ix^d,e_)&
2682 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2683 {end do\}
2684 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2685 ! convert back
2686 {do ix^db=iximin^db,iximax^db\}
2687 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2688 w(ix^d,e_)=w(ix^d,e_)&
2689 +half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2690 {end do\}
2691 end if
2692 case default
2693 if(.not.primitive) then
2694 !convert w to primitive
2695 {do ix^db=ixomin^db,ixomax^db\}
2696 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2697 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/rho\
2698 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2699 -half*((^c&w(ix^d,m^c_)**2+)*rho+(^c&w(ix^d,b^c_)**2+)))
2700 {end do\}
2701 end if
2702 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2703 end select
2704 end if
2705 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2706 end subroutine mhd_handle_small_values_split
2707
2708 subroutine mhd_handle_small_values_inte(primitive, w, x, ixI^L, ixO^L, subname)
2711 logical, intent(in) :: primitive
2712 integer, intent(in) :: ixi^l,ixo^l
2713 double precision, intent(inout) :: w(ixi^s,1:nw)
2714 double precision, intent(in) :: x(ixi^s,1:ndim)
2715 character(len=*), intent(in) :: subname
2716
2717 integer :: ix^d
2718 logical :: flag(ixi^s,1:nw)
2719
2720 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2721
2722 if(any(flag)) then
2723 select case (small_values_method)
2724 case ("replace")
2725 {do ix^db=ixomin^db,ixomax^db\}
2726 if(flag(ix^d,rho_)) then
2727 w(ix^d,rho_)=small_density
2728 ^c&w(ix^d,m^c_)=0.d0\
2729 end if
2730 if(primitive) then
2731 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2732 else
2733 if(flag(ix^d,e_)) w(ix^d,e_)=small_e
2734 end if
2735 {end do\}
2736 case ("average")
2737 ! do averaging of density
2738 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2739 ! do averaging of internal energy
2740 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2741 case default
2742 if(.not.primitive) then
2743 !convert w to primitive
2744 {do ix^db=ixomin^db,ixomax^db\}
2745 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2746 w(ix^d,p_)=gamma_1*w(ix^d,e_)
2747 {end do\}
2748 end if
2749 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2750 end select
2751 end if
2752 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2753 end subroutine mhd_handle_small_values_inte
2754
2755 subroutine mhd_handle_small_values_noe(primitive, w, x, ixI^L, ixO^L, subname)
2758 logical, intent(in) :: primitive
2759 integer, intent(in) :: ixi^l,ixo^l
2760 double precision, intent(inout) :: w(ixi^s,1:nw)
2761 double precision, intent(in) :: x(ixi^s,1:ndim)
2762 character(len=*), intent(in) :: subname
2763
2764 integer :: ix^d
2765 logical :: flag(ixi^s,1:nw)
2766
2767 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2768
2769 if(any(flag)) then
2770 select case (small_values_method)
2771 case ("replace")
2772 {do ix^db=ixomin^db,ixomax^db\}
2773 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2774 {
2775 if(small_values_fix_iw(m^c_)) then
2776 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2777 end if
2778 \}
2779 {end do\}
2780 case ("average")
2781 ! do averaging of density
2782 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2783 case default
2784 if(.not.primitive) then
2785 !convert w to primitive
2786 {do ix^db=ixomin^db,ixomax^db\}
2787 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2788 {end do\}
2789 end if
2790 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2791 end select
2792 end if
2793 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2794 end subroutine mhd_handle_small_values_noe
2795
2796 subroutine mhd_handle_small_values_hde(primitive, w, x, ixI^L, ixO^L, subname)
2799 logical, intent(in) :: primitive
2800 integer, intent(in) :: ixi^l,ixo^l
2801 double precision, intent(inout) :: w(ixi^s,1:nw)
2802 double precision, intent(in) :: x(ixi^s,1:ndim)
2803 character(len=*), intent(in) :: subname
2804
2805 integer :: ix^d
2806 logical :: flag(ixi^s,1:nw)
2807
2808 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2809
2810 if(any(flag)) then
2811 select case (small_values_method)
2812 case ("replace")
2813 {do ix^db=ixomin^db,ixomax^db\}
2814 if(flag(ix^d,rho_)) then
2815 w(ix^d,rho_)=small_density
2816 ^c&w(ix^d,m^c_)=0.d0\
2817 end if
2818 if(primitive) then
2819 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2820 else
2821 if(flag(ix^d,e_)) w(ix^d,e_)=small_e+half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2822 end if
2823 {end do\}
2824 case ("average")
2825 ! do averaging of density
2826 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2827 ! do averaging of energy
2828 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2829 case default
2830 if(.not.primitive) then
2831 !convert w to primitive
2832 {do ix^db=ixomin^db,ixomax^db\}
2833 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2834 w(ix^d,p_)=gamma_1*(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_))
2835 {end do\}
2836 end if
2837 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2838 end select
2839 end if
2840 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2841 end subroutine mhd_handle_small_values_hde
2842
2843 !> Calculate v vector
2844 subroutine mhd_get_v(w,x,ixI^L,ixO^L,v)
2846
2847 integer, intent(in) :: ixi^l, ixo^l
2848 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
2849 double precision, intent(out) :: v(ixi^s,ndir)
2850
2851 double precision :: rho(ixi^s)
2852 integer :: idir
2853
2854 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2855
2856 rho(ixo^s)=1.d0/rho(ixo^s)
2857 ! Convert momentum to velocity
2858 do idir = 1, ndir
2859 v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
2860 end do
2861
2862 end subroutine mhd_get_v
2863
2864 !> Calculate csound**2 within ixO^L
2865 subroutine mhd_get_csound2(w,x,ixI^L,ixO^L,cs2)
2867
2868 integer, intent(in) :: ixi^l, ixo^l
2869 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2870 double precision, intent(inout) :: cs2(ixi^s)
2871
2872 double precision :: rho, inv_rho, ploc
2873 integer :: ix^d
2874
2875 {do ix^db=ixomin^db,ixomax^db \}
2876 if(has_equi_rho_and_p) then
2877 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))
2878 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0))
2879 else
2880 rho=w(ix^d,rho_)
2881 ploc=w(ix^d,p_)
2882 end if
2883 inv_rho=1.d0/rho
2884 ! sound speed**2
2885 cs2(ix^d)=mhd_gamma*ploc*inv_rho
2886 {end do\}
2887 end subroutine mhd_get_csound2
2888
2889 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2890 subroutine mhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
2892
2893 integer, intent(in) :: ixi^l, ixo^l, idim
2894 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2895 double precision, intent(inout) :: cmax(ixi^s)
2896
2897 double precision :: rho, inv_rho, ploc, cfast2, avmincs2, b2, kmax
2898 integer :: ix^d
2899
2900 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2901
2902 if(b0field) then
2903 {do ix^db=ixomin^db,ixomax^db \}
2904 if(has_equi_rho_and_p) then
2905 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2906 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2907 else
2908 rho=w(ix^d,rho_)
2909 ploc=w(ix^d,p_)
2910 end if
2911 inv_rho=1.d0/rho
2912 ! sound speed**2
2913 cmax(ix^d)=mhd_gamma*ploc*inv_rho
2914 ! store |B|^2
2915 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
2916 cfast2=b2*inv_rho+cmax(ix^d)
2917 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2918 if(avmincs2<zero) avmincs2=zero
2919 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2920 if(mhd_hall) then
2921 ! take the Hall velocity into account: most simple estimate, high k limit:
2922 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2923 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2924 end if
2925 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2926 {end do\}
2927 else
2928 {do ix^db=ixomin^db,ixomax^db \}
2929 if(has_equi_rho_and_p) then
2930 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2931 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2932 else
2933 rho=w(ix^d,rho_)
2934 ploc=w(ix^d,p_)
2935 end if
2936 inv_rho=1.d0/rho
2937 ! sound speed**2
2938 cmax(ix^d)=mhd_gamma*ploc*inv_rho
2939 ! store |B|^2
2940 b2=(^c&w(ix^d,b^c_)**2+)
2941 cfast2=b2*inv_rho+cmax(ix^d)
2942 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2943 if(avmincs2<zero) avmincs2=zero
2944 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2945 if(mhd_hall) then
2946 ! take the Hall velocity into account: most simple estimate, high k limit:
2947 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2948 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2949 end if
2950 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2951 {end do\}
2952 end if
2953
2954 end subroutine mhd_get_cmax_origin
2955
2956 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2957 subroutine mhd_get_cmax_origin_noe(w,x,ixI^L,ixO^L,idim,cmax)
2960
2961 integer, intent(in) :: ixi^l, ixo^l, idim
2962 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2963 double precision, intent(inout) :: cmax(ixi^s)
2964
2965 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
2966 double precision :: adiabs(ixi^s), gammas(ixi^s)
2967 integer :: ix^d
2968
2969 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2970
2971 if(associated(usr_set_adiab)) then
2972 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
2973 else
2974 adiabs=mhd_adiab
2975 end if
2976 if(associated(usr_set_gamma)) then
2977 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
2978 else
2979 gammas=mhd_gamma
2980 end if
2981 {do ix^db=ixomin^db,ixomax^db \}
2982 rho=w(ix^d,rho_)
2983 inv_rho=1.d0/rho
2984 ! sound speed**2
2985 cmax(ix^d)=gammas(ix^d)*adiabs(ix^d)*rho**(gammas(ix^d)-1.d0)
2986 ! store |B|^2 in v
2987 b2=(^c&w(ix^d,b^c_)**2+)
2988 cfast2=b2*inv_rho+cmax(ix^d)
2989 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2990 if(avmincs2<zero) avmincs2=zero
2991 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2992 if(mhd_hall) then
2993 ! take the Hall velocity into account: most simple estimate, high k limit:
2994 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2995 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2996 end if
2997 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2998 {end do\}
2999
3000 end subroutine mhd_get_cmax_origin_noe
3001
3002 !> Calculate cmax_idim for semirelativistic MHD
3003 subroutine mhd_get_cmax_semirelati(w,x,ixI^L,ixO^L,idim,cmax)
3005
3006 integer, intent(in) :: ixi^l, ixo^l, idim
3007 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3008 double precision, intent(inout):: cmax(ixi^s)
3009
3010 double precision :: csound, avmincs2, idim_alfven_speed2
3011 double precision :: inv_rho, alfven_speed2, gamma2
3012 integer :: ix^d
3013
3014 {do ix^db=ixomin^db,ixomax^db \}
3015 inv_rho=1.d0/w(ix^d,rho_)
3016 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3017 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3018 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
3019 ! squared sound speed
3020 csound=mhd_gamma*w(ix^d,p_)*inv_rho
3021 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3022 ! Va_hat^2+a_hat^2 equation (57)
3023 ! equation (69)
3024 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
3025 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
3026 if(avmincs2<zero) avmincs2=zero
3027 ! equation (68) fast magnetosonic wave speed
3028 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
3029 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
3030 {end do\}
3031
3032 end subroutine mhd_get_cmax_semirelati
3033
3034 !> Calculate cmax_idim for semirelativistic MHD
3035 subroutine mhd_get_cmax_semirelati_noe(w,x,ixI^L,ixO^L,idim,cmax)
3038
3039 integer, intent(in) :: ixi^l, ixo^l, idim
3040 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3041 double precision, intent(inout):: cmax(ixi^s)
3042
3043 double precision :: adiabs(ixi^s), gammas(ixi^s)
3044 double precision :: csound, avmincs2, idim_alfven_speed2
3045 double precision :: inv_rho, alfven_speed2, gamma2
3046 integer :: ix^d
3047
3048 if(associated(usr_set_adiab)) then
3049 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3050 else
3051 adiabs=mhd_adiab
3052 end if
3053 if(associated(usr_set_gamma)) then
3054 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3055 else
3056 gammas=mhd_gamma
3057 end if
3058
3059 {do ix^db=ixomin^db,ixomax^db \}
3060 inv_rho=1.d0/w(ix^d,rho_)
3061 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3062 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3063 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
3064 csound=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3065 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3066 ! Va_hat^2+a_hat^2 equation (57)
3067 ! equation (69)
3068 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
3069 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
3070 if(avmincs2<zero) avmincs2=zero
3071 ! equation (68) fast magnetosonic wave speed
3072 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
3073 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
3074 {end do\}
3075
3076 end subroutine mhd_get_cmax_semirelati_noe
3077
3078 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
3079 subroutine mhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
3081 use mod_geometry
3082 integer, intent(in) :: ixi^l,ixo^l
3083 double precision, intent(in) :: x(ixi^s,1:ndim)
3084 ! in primitive form
3085 double precision, intent(inout) :: w(ixi^s,1:nw)
3086 double precision, intent(out) :: tco_local,tmax_local
3087
3088 double precision, parameter :: trac_delta=0.25d0
3089 double precision :: te(ixi^s),lts(ixi^s)
3090 double precision, dimension(1:ndim) :: bdir, bunitvec
3091 double precision, dimension(ixI^S,1:ndim) :: gradt
3092 double precision :: ltrc,ltrp,altr
3093 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
3094 integer :: jxp^l,hxp^l,ixp^l,ixq^l
3095
3096 if(mhd_partial_ionization) then
3097 call mhd_get_temperature_from_te(w,x,ixi^l,ixi^l,te)
3098 else
3099 call mhd_get_rfactor(w,x,ixi^l,ixi^l,te)
3100 te(ixi^s)=w(ixi^s,p_)/(te(ixi^s)*w(ixi^s,rho_))
3101 end if
3102 tco_local=zero
3103 tmax_local=maxval(te(ixo^s))
3104
3105 {^ifoned
3106 select case(mhd_trac_type)
3107 case(0)
3108 !> test case, fixed cutoff temperature
3109 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
3110 case(1)
3111 do ix1=ixomin1,ixomax1
3112 lts(ix1)=0.5d0*abs(te(ix1+1)-te(ix1-1))/te(ix1)
3113 if(lts(ix1)>trac_delta) then
3114 tco_local=max(tco_local,te(ix1))
3115 end if
3116 end do
3117 case(2)
3118 !> iijima et al. 2021, LTRAC method
3119 ltrc=1.5d0
3120 ltrp=4.d0
3121 ixp^l=ixo^l^ladd1;
3122 hxo^l=ixo^l-1;
3123 jxo^l=ixo^l+1;
3124 hxp^l=ixp^l-1;
3125 jxp^l=ixp^l+1;
3126 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
3127 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
3128 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
3129 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
3130 case default
3131 call mpistop("mhd_trac_type not allowed for 1D simulation")
3132 end select
3133 }
3134 {^nooned
3135 select case(mhd_trac_type)
3136 case(0)
3137 !> test case, fixed cutoff temperature
3138 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
3139 case(1,4,6)
3140 ! temperature gradient at cell centers
3141 do idims=1,ndim
3142 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
3143 end do
3144 if(mhd_trac_type .gt. 1) then
3145 ! B direction at block center
3146 bdir=zero
3147 if(b0field) then
3148 {do ixa^d=0,1\}
3149 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3150 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))+block%B0(ixb^d,1:ndim,0)
3151 {end do\}
3152 else
3153 {do ixa^d=0,1\}
3154 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3155 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))
3156 {end do\}
3157 end if
3158 {^iftwod
3159 if(bdir(1)/=0.d0) then
3160 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3161 else
3162 block%special_values(3)=0.d0
3163 end if
3164 if(bdir(2)/=0.d0) then
3165 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3166 else
3167 block%special_values(4)=0.d0
3168 end if
3169 }
3170 {^ifthreed
3171 if(bdir(1)/=0.d0) then
3172 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+&
3173 (bdir(3)/bdir(1))**2)
3174 else
3175 block%special_values(3)=0.d0
3176 end if
3177 if(bdir(2)/=0.d0) then
3178 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+&
3179 (bdir(3)/bdir(2))**2)
3180 else
3181 block%special_values(4)=0.d0
3182 end if
3183 if(bdir(3)/=0.d0) then
3184 block%special_values(5)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+&
3185 (bdir(2)/bdir(3))**2)
3186 else
3187 block%special_values(5)=0.d0
3188 end if
3189 }
3190 end if
3191 ! b unit vector: magnetic field direction vector
3192 block%special_values(1)=zero
3193 {do ix^db=ixomin^db,ixomax^db\}
3194 if(b0field) then
3195 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3196 else
3197 ^d&bdir(^d)=w({ix^d},iw_mag(^d))\
3198 end if
3199 {^iftwod
3200 if(bdir(1)/=0.d0) then
3201 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3202 else
3203 bunitvec(1)=0.d0
3204 end if
3205 if(bdir(2)/=0.d0) then
3206 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3207 else
3208 bunitvec(2)=0.d0
3209 end if
3210 ! temperature length scale inversed
3211 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
3212 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3213 }
3214 {^ifthreed
3215 if(bdir(1)/=0.d0) then
3216 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3217 else
3218 bunitvec(1)=0.d0
3219 end if
3220 if(bdir(2)/=0.d0) then
3221 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3222 else
3223 bunitvec(2)=0.d0
3224 end if
3225 if(bdir(3)/=0.d0) then
3226 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3227 else
3228 bunitvec(3)=0.d0
3229 end if
3230 ! temperature length scale inversed
3231 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
3232 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3233 }
3234 if(lts(ix^d)>trac_delta) then
3235 block%special_values(1)=max(block%special_values(1),te(ix^d))
3236 end if
3237 {end do\}
3238 block%special_values(2)=tmax_local
3239 case(2)
3240 !> iijima et al. 2021, LTRAC method
3241 ltrc=1.5d0
3242 ltrp=4.d0
3243 ixp^l=ixo^l^ladd2;
3244 ! temperature gradient at cell centers
3245 do idims=1,ndim
3246 ixq^l=ixp^l;
3247 hxp^l=ixp^l;
3248 jxp^l=ixp^l;
3249 select case(idims)
3250 {case(^d)
3251 ixqmin^d=ixqmin^d+1
3252 ixqmax^d=ixqmax^d-1
3253 hxpmax^d=ixpmin^d
3254 jxpmin^d=ixpmax^d
3255 \}
3256 end select
3257 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
3258 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
3259 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
3260 end do
3261 ! b unit vector: magnetic field direction vector
3262 if(b0field) then
3263 {do ix^db=ixpmin^db,ixpmax^db\}
3264 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3265 {^iftwod
3266 if(bdir(1)/=0.d0) then
3267 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3268 else
3269 bunitvec(1)=0.d0
3270 end if
3271 if(bdir(2)/=0.d0) then
3272 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3273 else
3274 bunitvec(2)=0.d0
3275 end if
3276 }
3277 {^ifthreed
3278 if(bdir(1)/=0.d0) then
3279 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3280 else
3281 bunitvec(1)=0.d0
3282 end if
3283 if(bdir(2)/=0.d0) then
3284 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3285 else
3286 bunitvec(2)=0.d0
3287 end if
3288 if(bdir(3)/=0.d0) then
3289 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3290 else
3291 bunitvec(3)=0.d0
3292 end if
3293 }
3294 ! temperature length scale inversed
3295 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3296 ! fraction of cells size to temperature length scale
3297 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3298 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3299 {end do\}
3300 else
3301 {do ix^db=ixpmin^db,ixpmax^db\}
3302 {^iftwod
3303 if(w(ix^d,iw_mag(1))/=0.d0) then
3304 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)
3305 else
3306 bunitvec(1)=0.d0
3307 end if
3308 if(w(ix^d,iw_mag(2))/=0.d0) then
3309 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)
3310 else
3311 bunitvec(2)=0.d0
3312 end if
3313 }
3314 {^ifthreed
3315 if(w(ix^d,iw_mag(1))/=0.d0) then
3316 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+&
3317 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
3318 else
3319 bunitvec(1)=0.d0
3320 end if
3321 if(w(ix^d,iw_mag(2))/=0.d0) then
3322 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+&
3323 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
3324 else
3325 bunitvec(2)=0.d0
3326 end if
3327 if(w(ix^d,iw_mag(3))/=0.d0) then
3328 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+&
3329 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
3330 else
3331 bunitvec(3)=0.d0
3332 end if
3333 }
3334 ! temperature length scale inversed
3335 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3336 ! fraction of cells size to temperature length scale
3337 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3338 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3339 {end do\}
3340 end if
3341
3342 ! need one ghost layer for thermal conductivity
3343 ixp^l=ixo^l^ladd1;
3344 {do ix^db=ixpmin^db,ixpmax^db\}
3345 {^iftwod
3346 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*bunitvec(1)**2+&
3347 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*bunitvec(2)**2)
3348 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3349 }
3350 {^ifthreed
3351 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*bunitvec(1)**2+&
3352 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*bunitvec(2)**2+&
3353 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*bunitvec(3)**2)
3354 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3355 }
3356 {end do\}
3357 case(3,5)
3358 !> do nothing here
3359 case default
3360 call mpistop("unknown mhd_trac_type")
3361 end select
3362 }
3363 end subroutine mhd_get_tcutoff
3364
3365 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
3366 subroutine mhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
3368
3369 integer, intent(in) :: ixi^l, ixo^l, idim
3370 double precision, intent(in) :: wprim(ixi^s, nw)
3371 double precision, intent(in) :: x(ixi^s,1:ndim)
3372 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
3373
3374 double precision :: csound(ixi^s,ndim)
3375 double precision, allocatable :: tmp(:^d&)
3376 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
3377
3378 hspeed=0.d0
3379 ixa^l=ixo^l^ladd1;
3380 allocate(tmp(ixa^s))
3381 do id=1,ndim
3382 if(has_equi_rho_and_p) then
3383 call mhd_get_csound_prim_split(wprim,x,ixi^l,ixa^l,id,tmp)
3384 else
3385 call mhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
3386 endif
3387 csound(ixa^s,id)=tmp(ixa^s)
3388 end do
3389 ixcmax^d=ixomax^d;
3390 ixcmin^d=ixomin^d+kr(idim,^d)-1;
3391 jxcmax^d=ixcmax^d+kr(idim,^d);
3392 jxcmin^d=ixcmin^d+kr(idim,^d);
3393 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))
3394
3395 do id=1,ndim
3396 if(id==idim) cycle
3397 ixamax^d=ixcmax^d+kr(id,^d);
3398 ixamin^d=ixcmin^d+kr(id,^d);
3399 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)))
3400 ixamax^d=ixcmax^d-kr(id,^d);
3401 ixamin^d=ixcmin^d-kr(id,^d);
3402 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)))
3403 end do
3404
3405 do id=1,ndim
3406 if(id==idim) cycle
3407 ixamax^d=jxcmax^d+kr(id,^d);
3408 ixamin^d=jxcmin^d+kr(id,^d);
3409 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)))
3410 ixamax^d=jxcmax^d-kr(id,^d);
3411 ixamin^d=jxcmin^d-kr(id,^d);
3412 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)))
3413 end do
3414 deallocate(tmp)
3415
3416 end subroutine mhd_get_h_speed
3417
3418 !> Estimating bounds for the minimum and maximum signal velocities without split
3419 subroutine mhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3421
3422 integer, intent(in) :: ixi^l, ixo^l, idim
3423 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3424 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3425 double precision, intent(in) :: x(ixi^s,1:ndim)
3426 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3427 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3428 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3429
3430 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3431 double precision :: umean, dmean, tmp1, tmp2, tmp3
3432 integer :: ix^d
3433
3434 select case (boundspeed)
3435 case (1)
3436 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3437 ! Methods for Fluid Dynamics" by Toro.
3438 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3439 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3440 if(present(cmin)) then
3441 {do ix^db=ixomin^db,ixomax^db\}
3442 tmp1=sqrt(wlp(ix^d,rho_))
3443 tmp2=sqrt(wrp(ix^d,rho_))
3444 tmp3=1.d0/(tmp1+tmp2)
3445 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3446 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3447 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3448 cmin(ix^d,1)=umean-dmean
3449 cmax(ix^d,1)=umean+dmean
3450 {end do\}
3451 if(h_correction) then
3452 {do ix^db=ixomin^db,ixomax^db\}
3453 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3454 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3455 {end do\}
3456 end if
3457 else
3458 {do ix^db=ixomin^db,ixomax^db\}
3459 tmp1=sqrt(wlp(ix^d,rho_))
3460 tmp2=sqrt(wrp(ix^d,rho_))
3461 tmp3=1.d0/(tmp1+tmp2)
3462 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3463 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3464 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3465 cmax(ix^d,1)=abs(umean)+dmean
3466 {end do\}
3467 end if
3468 case (2)
3469 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3470 call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
3471 if(present(cmin)) then
3472 {do ix^db=ixomin^db,ixomax^db\}
3473 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3474 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3475 {end do\}
3476 if(h_correction) then
3477 {do ix^db=ixomin^db,ixomax^db\}
3478 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3479 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3480 {end do\}
3481 end if
3482 else
3483 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3484 end if
3485 case (3)
3486 ! Miyoshi 2005 JCP 208, 315 equation (67)
3487 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3488 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3489 if(present(cmin)) then
3490 {do ix^db=ixomin^db,ixomax^db\}
3491 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3492 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3493 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3494 {end do\}
3495 if(h_correction) then
3496 {do ix^db=ixomin^db,ixomax^db\}
3497 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3498 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3499 {end do\}
3500 end if
3501 else
3502 {do ix^db=ixomin^db,ixomax^db\}
3503 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3504 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3505 {end do\}
3506 end if
3507 end select
3508
3509 end subroutine mhd_get_cbounds
3510
3511 !> Estimating bounds for the minimum and maximum signal velocities without split
3512 subroutine mhd_get_cbounds_semirelati(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3514
3515 integer, intent(in) :: ixi^l, ixo^l, idim
3516 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3517 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3518 double precision, intent(in) :: x(ixi^s,1:ndim)
3519 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3520 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3521 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3522
3523 double precision, dimension(ixO^S) :: csoundl, csoundr, gamma2l, gamma2r
3524 integer :: ix^d
3525
3526 ! Miyoshi 2005 JCP 208, 315 equation (67)
3527 if(mhd_energy) then
3528 call mhd_get_csound_semirelati(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3529 call mhd_get_csound_semirelati(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3530 else
3531 call mhd_get_csound_semirelati_noe(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3532 call mhd_get_csound_semirelati_noe(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3533 end if
3534 if(present(cmin)) then
3535 {do ix^db=ixomin^db,ixomax^db\}
3536 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3537 cmin(ix^d,1)=min(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))-csoundl(ix^d)
3538 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3539 {end do\}
3540 else
3541 {do ix^db=ixomin^db,ixomax^db\}
3542 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3543 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3544 {end do\}
3545 end if
3546
3547 end subroutine mhd_get_cbounds_semirelati
3548
3549 !> Estimating bounds for the minimum and maximum signal velocities with rho split
3550 subroutine mhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3552
3553 integer, intent(in) :: ixi^l, ixo^l, idim
3554 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3555 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3556 double precision, intent(in) :: x(ixi^s,1:ndim)
3557 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3558 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3559 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3560
3561 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3562 double precision :: umean, dmean, tmp1, tmp2, tmp3
3563 integer :: ix^d
3564
3565 select case (boundspeed)
3566 case (1)
3567 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3568 ! Methods for Fluid Dynamics" by Toro.
3569 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3570 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3571 if(present(cmin)) then
3572 {do ix^db=ixomin^db,ixomax^db\}
3573 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3574 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3575 tmp3=1.d0/(tmp1+tmp2)
3576 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3577 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3578 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3579 cmin(ix^d,1)=umean-dmean
3580 cmax(ix^d,1)=umean+dmean
3581 {end do\}
3582 if(h_correction) then
3583 {do ix^db=ixomin^db,ixomax^db\}
3584 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3585 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3586 {end do\}
3587 end if
3588 else
3589 {do ix^db=ixomin^db,ixomax^db\}
3590 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3591 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3592 tmp3=1.d0/(tmp1+tmp2)
3593 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3594 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3595 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3596 cmax(ix^d,1)=abs(umean)+dmean
3597 {end do\}
3598 end if
3599 case (2)
3600 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3601 call mhd_get_csound_prim_split(wmean,x,ixi^l,ixo^l,idim,csoundr)
3602 if(present(cmin)) then
3603 {do ix^db=ixomin^db,ixomax^db\}
3604 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3605 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3606 {end do\}
3607 if(h_correction) then
3608 {do ix^db=ixomin^db,ixomax^db\}
3609 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3610 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3611 {end do\}
3612 end if
3613 else
3614 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3615 end if
3616 case (3)
3617 ! Miyoshi 2005 JCP 208, 315 equation (67)
3618 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3619 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3620 if(present(cmin)) then
3621 {do ix^db=ixomin^db,ixomax^db\}
3622 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3623 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3624 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3625 {end do\}
3626 if(h_correction) then
3627 {do ix^db=ixomin^db,ixomax^db\}
3628 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3629 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3630 {end do\}
3631 end if
3632 else
3633 {do ix^db=ixomin^db,ixomax^db\}
3634 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3635 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3636 {end do\}
3637 end if
3638 end select
3639
3640 end subroutine mhd_get_cbounds_split_rho
3641
3642 !> prepare velocities for ct methods
3643 subroutine mhd_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3645
3646 integer, intent(in) :: ixi^l, ixo^l, idim
3647 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3648 double precision, intent(in) :: cmax(ixi^s)
3649 double precision, intent(in), optional :: cmin(ixi^s)
3650 type(ct_velocity), intent(inout):: vcts
3651
3652 end subroutine mhd_get_ct_velocity_average
3653
3654 subroutine mhd_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3656
3657 integer, intent(in) :: ixi^l, ixo^l, idim
3658 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3659 double precision, intent(in) :: cmax(ixi^s)
3660 double precision, intent(in), optional :: cmin(ixi^s)
3661 type(ct_velocity), intent(inout):: vcts
3662
3663 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
3664 ! get average normal velocity at cell faces
3665 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
3666
3667 end subroutine mhd_get_ct_velocity_contact
3668
3669 subroutine mhd_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3671
3672 integer, intent(in) :: ixi^l, ixo^l, idim
3673 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3674 double precision, intent(in) :: cmax(ixi^s)
3675 double precision, intent(in), optional :: cmin(ixi^s)
3676 type(ct_velocity), intent(inout):: vcts
3677
3678 integer :: idime,idimn
3679
3680 if(.not.allocated(vcts%vbarC)) then
3681 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
3682 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
3683 end if
3684 ! Store magnitude of characteristics
3685 if(present(cmin)) then
3686 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
3687 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3688 else
3689 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3690 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
3691 end if
3692
3693 idimn=mod(idim,ndir)+1 ! 'Next' direction
3694 idime=mod(idim+1,ndir)+1 ! Electric field direction
3695 ! Store velocities
3696 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
3697 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
3698 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
3699 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3700 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3701
3702 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
3703 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
3704 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
3705 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3706 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3707
3708 end subroutine mhd_get_ct_velocity_hll
3709
3710 !> Calculate modified squared sound speed for FLD
3711 !> NOTE: only for diagnostic purposes, unused subroutine
3712 subroutine mhd_get_csrad2(w,x,ixI^L,ixO^L,csound)
3714
3715 integer, intent(in) :: ixi^l, ixo^l
3716 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3717 double precision, intent(out):: csound(ixi^s)
3718
3719 double precision :: wprim(ixi^s, nw)
3720
3721 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
3722 call mhd_to_primitive(ixi^l,ixo^l,wprim,x)
3723 call mhd_get_csrad2_prim(wprim,x,ixi^l,ixo^l,csound)
3724
3725 end subroutine mhd_get_csrad2
3726
3727
3728 !> Calculate modified squared fast wave speed for FLD
3729 !> NOTE: w is primitive on entry here!
3730 !> NOTE: used in FLD module as phys_get_csrad2
3731 subroutine mhd_get_csrad2_prim(w,x,ixI^L,ixO^L,csound)
3733
3734 integer, intent(in) :: ixi^l, ixo^l
3735 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3736 double precision, intent(out):: csound(ixi^s)
3737
3738 double precision :: inv_rho, b2
3739 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
3740 double precision :: prad_max(ixi^s)
3741 integer :: ix^d
3742
3743 call mhd_get_pradiation_from_prim(w, x, ixi^l, ixo^l, prad_tensor)
3744
3745 if(b0field) then
3746 {do ix^db=ixomin^db,ixomax^db \}
3747 inv_rho=1.d0/w(ix^d,rho_)
3748 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3749 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3750 csound(ix^d)=(mhd_gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3751 {end do\}
3752 else
3753 {do ix^db=ixomin^db,ixomax^db \}
3754 inv_rho=1.d0/w(ix^d,rho_)
3755 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3756 b2=(^c&w(ix^d,b^c_)**2+)
3757 csound(ix^d)=(mhd_gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3758 {end do\}
3759 end if
3760
3761 if(minval(csound(ixo^s))<smalldouble)then
3762 print *,'issue with squared speed and rad pressure'
3763 print *,minval(csound(ixo^s))
3764 print *,minval(prad_max(ixo^s))
3765 call mpistop("negative squared speed in get_csrad2 for dt")
3766 endif
3767
3768 end subroutine mhd_get_csrad2_prim
3769
3770 !> Calculate fast magnetosonic wave speed
3771 subroutine mhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
3774
3775 integer, intent(in) :: ixi^l, ixo^l, idim
3776 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3777 double precision, intent(out):: csound(ixo^s)
3778
3779 double precision :: adiabs(ixi^s), gammas(ixi^s)
3780 double precision :: inv_rho, cfast2, avmincs2, b2, kmax
3781 integer :: ix^d
3782
3783 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3784
3785 if(.not.mhd_energy) then
3786 if(associated(usr_set_adiab)) then
3787 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3788 else
3789 adiabs=mhd_adiab
3790 end if
3791 if(associated(usr_set_gamma)) then
3792 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3793 else
3794 gammas=mhd_gamma
3795 end if
3796 end if
3797
3798 ! store |B|^2 in v
3799 if(b0field) then
3800 {do ix^db=ixomin^db,ixomax^db \}
3801 inv_rho=1.d0/w(ix^d,rho_)
3802 if(mhd_energy) then
3803 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3804 else
3805 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3806 end if
3807 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3808 cfast2=b2*inv_rho+csound(ix^d)
3809 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3810 block%B0(ix^d,idim,b0i))**2*inv_rho
3811 if(avmincs2<zero) avmincs2=zero
3812 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3813 if(mhd_hall) then
3814 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3815 end if
3816 {end do\}
3817 else
3818 {do ix^db=ixomin^db,ixomax^db \}
3819 inv_rho=1.d0/w(ix^d,rho_)
3820 if(mhd_energy) then
3821 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3822 else
3823 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3824 end if
3825 b2=(^c&w(ix^d,b^c_)**2+)
3826 cfast2=b2*inv_rho+csound(ix^d)
3827 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3828 if(avmincs2<zero) avmincs2=zero
3829 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3830 if(mhd_hall) then
3831 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3832 end if
3833 {end do\}
3834 end if
3835
3836 end subroutine mhd_get_csound_prim
3837
3838 !> Calculate fast magnetosonic wave speed when rho and p are split
3839 !> hence has_equi_rho_and_p=T
3840 subroutine mhd_get_csound_prim_split(w,x,ixI^L,ixO^L,idim,csound)
3842
3843 integer, intent(in) :: ixi^l, ixo^l, idim
3844 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3845 double precision, intent(out):: csound(ixo^s)
3846
3847 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
3848 integer :: ix^d
3849
3850 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3851
3852 ! store |B|^2 in v
3853 if(b0field) then
3854 {do ix^db=ixomin^db,ixomax^db \}
3855 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3856 inv_rho=1.d0/rho
3857 csound(ix^d)=mhd_gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3858 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3859 cfast2=b2*inv_rho+csound(ix^d)
3860 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3861 block%B0(ix^d,idim,b0i))**2*inv_rho
3862 if(avmincs2<zero) avmincs2=zero
3863 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3864 if(mhd_hall) then
3865 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3866 end if
3867 {end do\}
3868 else
3869 {do ix^db=ixomin^db,ixomax^db \}
3870 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3871 inv_rho=1.d0/rho
3872 csound(ix^d)=mhd_gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3873 b2=(^c&w(ix^d,b^c_)**2+)
3874 cfast2=b2*inv_rho+csound(ix^d)
3875 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3876 if(avmincs2<zero) avmincs2=zero
3877 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3878 if(mhd_hall) then
3879 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3880 end if
3881 {end do\}
3882 end if
3883
3884 end subroutine mhd_get_csound_prim_split
3885
3886 !> Calculate cmax_idim for semirelativistic MHD
3887 subroutine mhd_get_csound_semirelati(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3889
3890 integer, intent(in) :: ixi^l, ixo^l, idim
3891 ! here w is primitive variables
3892 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3893 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3894
3895 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3896 integer :: ix^d
3897
3898 {do ix^db=ixomin^db,ixomax^db\}
3899 inv_rho = 1.d0/w(ix^d,rho_)
3900 ! squared sound speed
3901 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3902 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3903 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3904 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3905 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3906 ! Va_hat^2+a_hat^2 equation (57)
3907 ! equation (69)
3908 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3909 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3910 if(avmincs2<zero) avmincs2=zero
3911 ! equation (68) fast magnetosonic speed
3912 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3913 {end do\}
3914
3915 end subroutine mhd_get_csound_semirelati
3916
3917 !> Calculate cmax_idim for semirelativistic MHD
3918 subroutine mhd_get_csound_semirelati_noe(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3921
3922 integer, intent(in) :: ixi^l, ixo^l, idim
3923 ! here w is primitive variables
3924 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3925 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3926
3927 double precision :: adiabs(ixi^s), gammas(ixi^s)
3928 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3929 integer :: ix^d
3930
3931 if(associated(usr_set_adiab)) then
3932 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3933 else
3934 adiabs=mhd_adiab
3935 end if
3936 if(associated(usr_set_gamma)) then
3937 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3938 else
3939 gammas=mhd_gamma
3940 end if
3941 {do ix^db=ixomin^db,ixomax^db\}
3942 inv_rho = 1.d0/w(ix^d,rho_)
3943 ! squared sound speed
3944 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3945 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3946 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3947 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3948 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3949 ! Va_hat^2+a_hat^2 equation (57)
3950 ! equation (69)
3951 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3952 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3953 if(avmincs2<zero) avmincs2=zero
3954 ! equation (68) fast magnetosonic speed
3955 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3956 {end do\}
3957
3958 end subroutine mhd_get_csound_semirelati_noe
3959
3960 !> Calculate thermal pressure from polytropic closure
3961 subroutine mhd_get_pthermal_noe(w,x,ixI^L,ixO^L,pth)
3964
3965 integer, intent(in) :: ixi^l, ixo^l
3966 double precision, intent(in) :: w(ixi^s,nw)
3967 double precision, intent(in) :: x(ixi^s,1:ndim)
3968 double precision, intent(out):: pth(ixi^s)
3969
3970 double precision :: adiabs(ixi^s), gammas(ixi^s)
3971 integer :: ix^d
3972
3973 if(associated(usr_set_adiab)) then
3974 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3975 else
3976 adiabs=mhd_adiab
3977 end if
3978 if(associated(usr_set_gamma)) then
3979 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3980 else
3981 gammas=mhd_gamma
3982 end if
3983 {do ix^db=ixomin^db,ixomax^db\}
3984 pth(ix^d)=adiabs(ix^d)*w(ix^d,rho_)**gammas(ix^d)
3985 {end do\}
3986
3987 end subroutine mhd_get_pthermal_noe
3988
3989 !> Calculate thermal pressure from internal energy
3990 subroutine mhd_get_pthermal_inte(w,x,ixI^L,ixO^L,pth)
3993
3994 integer, intent(in) :: ixi^l, ixo^l
3995 double precision, intent(in) :: w(ixi^s,nw)
3996 double precision, intent(in) :: x(ixi^s,1:ndim)
3997 double precision, intent(out):: pth(ixi^s)
3998
3999 integer :: iw, ix^d
4000
4001 {do ix^db= ixomin^db,ixomax^db\}
4002 pth(ix^d)=gamma_1*w(ix^d,e_)
4003 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
4004 {end do\}
4005
4006 if(check_small_values.and..not.fix_small_values) then
4007 {do ix^db= ixomin^db,ixomax^db\}
4008 if(pth(ix^d)<small_pressure) then
4009 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
4010 " encountered when call mhd_get_pthermal_inte"
4011 write(*,*) "Iteration: ", it, " Time: ", global_time
4012 write(*,*) "Location: ", x(ix^d,:)
4013 write(*,*) "Cell number: ", ix^d
4014 do iw=1,nw
4015 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4016 end do
4017 ! use erroneous arithmetic operation to crash the run
4018 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4019 write(*,*) "Saving status at the previous time step"
4020 crash=.true.
4021 end if
4022 {end do\}
4023 end if
4024
4025 end subroutine mhd_get_pthermal_inte
4026
4027 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L
4028 subroutine mhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
4031
4032 integer, intent(in) :: ixi^l, ixo^l
4033 double precision, intent(in) :: w(ixi^s,nw)
4034 double precision, intent(in) :: x(ixi^s,1:ndim)
4035 double precision, intent(out):: pth(ixi^s)
4036
4037 integer :: iw, ix^d
4038
4039 {do ix^db=ixomin^db,ixomax^db\}
4040 if(has_equi_rho_and_p) then
4041 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
4042 +(^c&w(ix^d,b^c_)**2+))) +block%equi_vars(ix^d,equi_pe0_,0)
4043 else
4044 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
4045 +(^c&w(ix^d,b^c_)**2+)))
4046 end if
4047 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
4048 {end do\}
4049
4050 if(check_small_values.and..not.fix_small_values) then
4051 {do ix^db=ixomin^db,ixomax^db\}
4052 if(pth(ix^d)<small_pressure) then
4053 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
4054 " encountered when call mhd_get_pthermal"
4055 write(*,*) "Iteration: ", it, " Time: ", global_time
4056 write(*,*) "Location: ", x(ix^d,:)
4057 write(*,*) "Cell number: ", ix^d
4058 do iw=1,nw
4059 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4060 end do
4061 ! use erroneous arithmetic operation to crash the run
4062 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4063 write(*,*) "Saving status at the previous time step"
4064 crash=.true.
4065 end if
4066 {end do\}
4067 end if
4068
4069 end subroutine mhd_get_pthermal_origin
4070
4071 !> Calculate thermal pressure
4072 subroutine mhd_get_pthermal_semirelati(w,x,ixI^L,ixO^L,pth)
4075
4076 integer, intent(in) :: ixi^l, ixo^l
4077 double precision, intent(in) :: w(ixi^s,nw)
4078 double precision, intent(in) :: x(ixi^s,1:ndim)
4079 double precision, intent(out):: pth(ixi^s)
4080
4081 double precision :: e(1:ndir), v(1:ndir), tmp, factor
4082 integer :: iw, ix^d
4083
4084 {do ix^db=ixomin^db,ixomax^db\}
4085 ! Convert momentum to velocity
4086 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
4087 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
4088 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
4089
4090 ! E=Bxv
4091 {^ifthreec
4092 e(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
4093 e(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
4094 e(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
4095 }
4096 {^iftwoc
4097 e(1)=zero
4098 e(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
4099 }
4100 {^ifonec
4101 e(1)=zero
4102 }
4103 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
4104 pth(ix^d)=gamma_1*(w(ix^d,e_)&
4105 -half*((^c&v(^c)**2+)*w(ix^d,rho_)&
4106 +(^c&w(ix^d,b^c_)**2+)+(^c&e(^c)**2+)*inv_squared_c))
4107 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
4108 {end do\}
4109
4110 if(check_small_values.and..not.fix_small_values) then
4111 {do ix^db=ixomin^db,ixomax^db\}
4112 if(pth(ix^d)<small_pressure) then
4113 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
4114 " encountered when call mhd_get_pthermal_semirelati"
4115 write(*,*) "Iteration: ", it, " Time: ", global_time
4116 write(*,*) "Location: ", x(ix^d,:)
4117 write(*,*) "Cell number: ", ix^d
4118 do iw=1,nw
4119 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4120 end do
4121 ! use erroneous arithmetic operation to crash the run
4122 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4123 write(*,*) "Saving status at the previous time step"
4124 crash=.true.
4125 end if
4126 {end do\}
4127 end if
4128
4129 end subroutine mhd_get_pthermal_semirelati
4130
4131 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho) within ixO^L
4132 subroutine mhd_get_pthermal_hde(w,x,ixI^L,ixO^L,pth)
4135
4136 integer, intent(in) :: ixi^l, ixo^l
4137 double precision, intent(in) :: w(ixi^s,nw)
4138 double precision, intent(in) :: x(ixi^s,1:ndim)
4139 double precision, intent(out):: pth(ixi^s)
4140
4141 integer :: iw, ix^d
4142
4143 {do ix^db= ixomin^db,ixomax^db\}
4144 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)))
4145 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
4146 {end do\}
4147 if(check_small_values.and..not.fix_small_values) then
4148 {do ix^db= ixomin^db,ixomax^db\}
4149 if(pth(ix^d)<small_pressure) then
4150 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
4151 " encountered when call mhd_get_pthermal_hde"
4152 write(*,*) "Iteration: ", it, " Time: ", global_time
4153 write(*,*) "Location: ", x(ix^d,:)
4154 write(*,*) "Cell number: ", ix^d
4155 do iw=1,nw
4156 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4157 end do
4158 ! use erroneous arithmetic operation to crash the run
4159 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4160 write(*,*) "Saving status at the previous time step"
4161 crash=.true.
4162 end if
4163 {end do\}
4164 end if
4165
4166 end subroutine mhd_get_pthermal_hde
4167
4168 !> copy temperature from stored Te variable
4169 subroutine mhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
4171 integer, intent(in) :: ixi^l, ixo^l
4172 double precision, intent(in) :: w(ixi^s, 1:nw)
4173 double precision, intent(in) :: x(ixi^s, 1:ndim)
4174 double precision, intent(out):: res(ixi^s)
4175 res(ixo^s) = w(ixo^s, te_)
4176 end subroutine mhd_get_temperature_from_te
4177
4178 !> Calculate temperature=p/rho when in e_ the internal energy is stored
4179 subroutine mhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
4181 integer, intent(in) :: ixi^l, ixo^l
4182 double precision, intent(in) :: w(ixi^s, 1:nw)
4183 double precision, intent(in) :: x(ixi^s, 1:ndim)
4184 double precision, intent(out):: res(ixi^s)
4185
4186 double precision :: r(ixi^s)
4187
4188 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4189 res(ixo^s) = gamma_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
4190 end subroutine mhd_get_temperature_from_eint
4191
4192 !> Calculate temperature=p/rho when in e_ the pressure p_ (primitive) is stored
4193 subroutine mhd_get_temperature_from_prim(w, x, ixI^L, ixO^L, res)
4195 integer, intent(in) :: ixi^l, ixo^l
4196 double precision, intent(in) :: w(ixi^s, 1:nw)
4197 double precision, intent(in) :: x(ixi^s, 1:ndim)
4198 double precision, intent(out):: res(ixi^s)
4199
4200 double precision :: r(ixi^s)
4201
4202 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4203 res(ixo^s) = w(ixo^s, p_)/(w(ixo^s,rho_)*r(ixo^s))
4204 end subroutine mhd_get_temperature_from_prim
4205
4206 !> Calculate temperature=p/rho from total energy
4207 subroutine mhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
4209 integer, intent(in) :: ixi^l, ixo^l
4210 double precision, intent(in) :: w(ixi^s, 1:nw)
4211 double precision, intent(in) :: x(ixi^s, 1:ndim)
4212 double precision, intent(out):: res(ixi^s)
4213
4214 double precision :: r(ixi^s),rho(ixi^s),pth(ixi^s)
4215
4216 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4217 call mhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
4218 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
4219 res(ixo^s)=pth(ixo^s)/(r(ixo^s)*rho(ixo^s))
4220
4221 end subroutine mhd_get_temperature_from_etot
4222
4223 subroutine mhd_get_temperature_from_eint_with_equi(w, x, ixI^L, ixO^L, res)
4225 integer, intent(in) :: ixi^l, ixo^l
4226 double precision, intent(in) :: w(ixi^s, 1:nw)
4227 double precision, intent(in) :: x(ixi^s, 1:ndim)
4228 double precision, intent(out):: res(ixi^s)
4229
4230 double precision :: r(ixi^s)
4231
4232 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4233 res(ixo^s) = (gamma_1 * w(ixo^s, e_) + block%equi_vars(ixo^s,equi_pe0_,b0i)) /&
4234 ((w(ixo^s,rho_) +block%equi_vars(ixo^s,equi_rho0_,b0i))*r(ixo^s))
4235
4236 end subroutine mhd_get_temperature_from_eint_with_equi
4237
4238 subroutine mhd_get_temperature_equi(w,x, ixI^L, ixO^L, res)
4240 integer, intent(in) :: ixi^l, ixo^l
4241 double precision, intent(in) :: w(ixi^s, 1:nw)
4242 double precision, intent(in) :: x(ixi^s, 1:ndim)
4243 double precision, intent(out):: res(ixi^s)
4244
4245 double precision :: r(ixi^s)
4246
4247 !!! somewhat inconsistent: R from w itself, while only equilibrium needed !!!
4248 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4249 res(ixo^s)= block%equi_vars(ixo^s,equi_pe0_,b0i)/(block%equi_vars(ixo^s,equi_rho0_,b0i)*r(ixo^s))
4250
4251 end subroutine mhd_get_temperature_equi
4252
4253 subroutine mhd_get_rho_equi(w, x, ixI^L, ixO^L, res)
4255 integer, intent(in) :: ixi^l, ixo^l
4256 double precision, intent(in) :: w(ixi^s, 1:nw)
4257 double precision, intent(in) :: x(ixi^s, 1:ndim)
4258 double precision, intent(out):: res(ixi^s)
4259 res(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i)
4260 end subroutine mhd_get_rho_equi
4261
4262 subroutine mhd_get_pe_equi(w,x, ixI^L, ixO^L, res)
4264 integer, intent(in) :: ixi^l, ixo^l
4265 double precision, intent(in) :: w(ixi^s, 1:nw)
4266 double precision, intent(in) :: x(ixi^s, 1:ndim)
4267 double precision, intent(out):: res(ixi^s)
4268 res(ixo^s) = block%equi_vars(ixo^s,equi_pe0_,b0i)
4269 end subroutine mhd_get_pe_equi
4270
4271 !> Calculate radiation pressure within ixO^L
4272 subroutine mhd_get_pradiation_from_prim(w, x, ixI^L, ixO^L, prad)
4274 use mod_fld
4275 integer, intent(in) :: ixi^l, ixo^l
4276 double precision, intent(in) :: w(ixi^s, 1:nw)
4277 double precision, intent(in) :: x(ixi^s, 1:ndim)
4278 double precision, intent(out):: prad(ixi^s, 1:ndim, 1:ndim)
4279
4280 call fld_get_radpress(w, x, ixi^l, ixo^l, prad)
4281
4282 end subroutine mhd_get_pradiation_from_prim
4283
4284 !> Calculates the sum of the gas pressure and the max Prad tensor element
4285 subroutine mhd_get_pthermal_plus_pradiation(w, x, ixI^L, ixO^L, pth_plus_prad)
4287 integer, intent(in) :: ixi^l, ixo^l
4288 double precision, intent(in) :: w(ixi^s, 1:nw)
4289 double precision, intent(in) :: x(ixi^s, 1:ndim)
4290 double precision, intent(out) :: pth_plus_prad(ixi^s)
4291
4292 double precision :: wprim(ixi^s, 1:nw)
4293 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
4294 double precision :: prad_max(ixi^s)
4295 integer :: ix^d
4296
4297 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
4298 call mhd_to_primitive(ixi^l,ixo^l,wprim,x)
4299 call mhd_get_pradiation_from_prim(wprim, x, ixi^l, ixo^l, prad_tensor)
4300 {do ix^d = ixomin^d,ixomax^d\}
4301 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
4302 {enddo\}
4303 pth_plus_prad(ixo^s) = wprim(ixo^s,p_) + prad_max(ixo^s)
4305
4306 !> Calculates radiation temperature
4307 subroutine mhd_get_trad(w, x, ixI^L, ixO^L, trad)
4309 use mod_constants
4310
4311 integer, intent(in) :: ixi^l, ixo^l
4312 double precision, intent(in) :: w(ixi^s, 1:nw)
4313 double precision, intent(in) :: x(ixi^s, 1:ndim)
4314 double precision, intent(out):: trad(ixi^s)
4315
4316 trad(ixi^s) = (w(ixi^s,r_e)/arad_norm)**(1.d0/4.d0)
4317
4318 end subroutine mhd_get_trad
4319
4320 !> Calculate fluxes within ixO^L without any splitting
4321 subroutine mhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
4323 use mod_geometry
4324
4325 integer, intent(in) :: ixi^l, ixo^l, idim
4326 ! conservative w
4327 double precision, intent(in) :: wc(ixi^s,nw)
4328 ! primitive w
4329 double precision, intent(in) :: w(ixi^s,nw)
4330 double precision, intent(in) :: x(ixi^s,1:ndim)
4331 double precision,intent(out) :: f(ixi^s,nwflux)
4332
4333 double precision :: vhall(ixi^s,1:ndir)
4334 double precision :: ptotal
4335 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4336 double precision :: bvec(ixi^s,1:ndir)
4337 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4338 double precision :: nperp(ixi^s,1:ndir)
4339 logical :: use_perp_flux
4340 integer :: iw, ix^d, idir
4341
4342 if(mhd_internal_e) then
4343 {do ix^db=ixomin^db,ixomax^db\}
4344 ! Get flux of density
4345 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4346 ! f_i[m_k]=v_i*m_k-b_k*b_i
4347 ^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_)\
4348 ! normal one includes total pressure
4349 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4350 ! Get flux of internal energy
4351 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4352 ! f_i[b_k]=v_i*b_k-v_k*b_i
4353 ^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_)\
4354 {end do\}
4355 else
4356 {do ix^db=ixomin^db,ixomax^db\}
4357 ! Get flux of density
4358 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4359 ! f_i[m_k]=v_i*m_k-b_k*b_i
4360 ^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_)\
4361 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4362 ! normal one includes total pressure
4363 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4364 ! Get flux of total energy
4365 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4366 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4367 -w(ix^d,mag(idim))*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4368 ! f_i[b_k]=v_i*b_k-v_k*b_i
4369 ^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_)\
4370 {end do\}
4371 end if
4372 if(mhd_hall) then
4373 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4374 {do ix^db=ixomin^db,ixomax^db\}
4375 if(total_energy) then
4376 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4377 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)**2+)&
4378 -w(ix^d,mag(idim))*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4379 end if
4380 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4381 ^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))\
4382 {end do\}
4383 end if
4384
4385 if(mhd_glm) then
4386 {do ix^db=ixomin^db,ixomax^db\}
4387 f(ix^d,mag(idim))=w(ix^d,psi_)
4388 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4389 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4390 {end do\}
4391 end if
4392
4393 if(mhd_radiation_fld) then
4394 {do ix^db=ixomin^db,ixomax^db\}
4395 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4396 {end do\}
4397 endif
4398
4399 if (mhd_fip) then
4400 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4401 end if
4402 ! Get flux of tracer
4403 do iw=1,mhd_n_tracer
4404 {do ix^db=ixomin^db,ixomax^db\}
4405 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4406 {end do\}
4407 end do
4408
4410 if(use_perp_flux) then
4411 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4412 call mhd_get_rfactor(w,x,ixi^l,ixi^l,r)
4413 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4414 {do ix^db=ixomin^db,ixomax^db\}
4415 do idir=1,ndir
4416 bvec(ix^d,idir)=w(ix^d,mag(idir))
4417 end do
4418 {end do\}
4419 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4420 end if
4421
4422 if(mhd_hyperbolic_tc) then
4423 {do ix^db=ixomin^db,ixomax^db\}
4424 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)
4425 f(ix^d,qpar_)=zero
4426 if(use_perp_flux) then
4427 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4428 f(ix^d,qperp_)=zero
4429 end if
4430 {end do\}
4431 end if
4432 end subroutine mhd_get_flux
4433
4434 !> Calculate fluxes within ixO^L for case without energy equation, hence without splitting
4435 !> and assuming polytropic closure
4436 subroutine mhd_get_flux_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4438 use mod_geometry
4440
4441 integer, intent(in) :: ixi^l, ixo^l, idim
4442 ! conservative w
4443 double precision, intent(in) :: wc(ixi^s,nw)
4444 ! primitive w
4445 double precision, intent(in) :: w(ixi^s,nw)
4446 double precision, intent(in) :: x(ixi^s,1:ndim)
4447 double precision,intent(out) :: f(ixi^s,nwflux)
4448
4449 double precision :: vhall(ixi^s,1:ndir)
4450 double precision :: adiabs(ixi^s), gammas(ixi^s)
4451 integer :: iw, ix^d
4452
4453 if(associated(usr_set_adiab)) then
4454 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4455 else
4456 adiabs=mhd_adiab
4457 end if
4458 if(associated(usr_set_gamma)) then
4459 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4460 else
4461 gammas=mhd_gamma
4462 end if
4463 {do ix^db=ixomin^db,ixomax^db\}
4464 ! Get flux of density
4465 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4466 ! f_i[m_k]=v_i*m_k-b_k*b_i
4467 ^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_)\
4468 ! normal one includes total pressure
4469 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+)
4470 ! f_i[b_k]=v_i*b_k-v_k*b_i
4471 ^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_)\
4472 {end do\}
4473 if(mhd_hall) then
4474 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4475 {do ix^db=ixomin^db,ixomax^db\}
4476 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4477 ^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))\
4478 {end do\}
4479 end if
4480 if(mhd_glm) then
4481 {do ix^db=ixomin^db,ixomax^db\}
4482 f(ix^d,mag(idim))=w(ix^d,psi_)
4483 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4484 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4485 {end do\}
4486 end if
4487 if (mhd_fip) then
4488 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4489 end if
4490 ! Get flux of tracer
4491 do iw=1,mhd_n_tracer
4492 {do ix^db=ixomin^db,ixomax^db\}
4493 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4494 {end do\}
4495 end do
4496 end subroutine mhd_get_flux_noe
4497
4498 !> Calculate fluxes with hydrodynamic energy equation
4499 subroutine mhd_get_flux_hde(wC,w,x,ixI^L,ixO^L,idim,f)
4501 use mod_geometry
4502
4503 integer, intent(in) :: ixi^l, ixo^l, idim
4504 ! conservative w
4505 double precision, intent(in) :: wc(ixi^s,nw)
4506 ! primitive w
4507 double precision, intent(in) :: w(ixi^s,nw)
4508 double precision, intent(in) :: x(ixi^s,1:ndim)
4509 double precision,intent(out) :: f(ixi^s,nwflux)
4510
4511 double precision :: vhall(ixi^s,1:ndir)
4512 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4513 double precision :: bvec(ixi^s,1:ndir)
4514 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4515 double precision :: nperp(ixi^s,1:ndir)
4516 logical :: use_perp_flux
4517 integer :: iw, ix^d, idir
4518
4519 {do ix^db=ixomin^db,ixomax^db\}
4520 ! Get flux of density
4521 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4522 ! f_i[m_k]=v_i*m_k-b_k*b_i
4523 ^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_)\
4524 ! normal one includes total pressure
4525 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4526 ! Get flux of energy
4527 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+w(ix^d,p_))
4528 ! f_i[b_k]=v_i*b_k-v_k*b_i
4529 ^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_)\
4530 {end do\}
4531 if(mhd_hall) then
4532 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4533 {do ix^db=ixomin^db,ixomax^db\}
4534 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4535 ^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))\
4536 {end do\}
4537 end if
4538 if(mhd_glm) then
4539 {do ix^db=ixomin^db,ixomax^db\}
4540 f(ix^d,mag(idim))=w(ix^d,psi_)
4541 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4542 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4543 {end do\}
4544 end if
4545 if (mhd_fip) then
4546 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4547 end if
4548 ! Get flux of tracer
4549 do iw=1,mhd_n_tracer
4550 {do ix^db=ixomin^db,ixomax^db\}
4551 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4552 {end do\}
4553 end do
4555 if(use_perp_flux) then
4556 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4557 call mhd_get_rfactor(w,x,ixi^l,ixi^l,r)
4558 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4559 {do ix^db=ixomin^db,ixomax^db\}
4560 do idir=1,ndir
4561 bvec(ix^d,idir)=w(ix^d,mag(idir))
4562 end do
4563 {end do\}
4564 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4565 end if
4566 if(mhd_hyperbolic_tc) then
4567 {do ix^db=ixomin^db,ixomax^db\}
4568 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)
4569 f(ix^d,qpar_)=zero
4570 if(use_perp_flux) then
4571 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4572 f(ix^d,qperp_)=zero
4573 end if
4574 {end do\}
4575 end if
4576 end subroutine mhd_get_flux_hde
4577
4578 !> Calculate fluxes within ixO^L with possible splitting
4579 !> this covers four cases: B0field=T and mhd_internal_e=T (where has_equi_rho_and_p=F)
4580 !> B0field=T and has_equi_rho_and_p=F for total_energy=T
4581 !> B0field=F and has_equi_rho_and_p=T for total_energy=T
4582 !> B0field=T and has_equi_rho_and_p=T for total_energy=T
4583 subroutine mhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
4585 use mod_geometry
4586
4587 integer, intent(in) :: ixi^l, ixo^l, idim
4588 ! conservative w
4589 double precision, intent(in) :: wc(ixi^s,nw)
4590 ! primitive w
4591 double precision, intent(in) :: w(ixi^s,nw)
4592 double precision, intent(in) :: x(ixi^s,1:ndim)
4593 double precision,intent(out) :: f(ixi^s,nwflux)
4594
4595 double precision :: vhall(ixi^s,1:ndir)
4596 double precision :: ptotal, btotal(ixo^s,1:ndir)
4597 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4598 double precision :: bvec(ixi^s,1:ndir)
4599 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4600 double precision :: nperp(ixi^s,1:ndir)
4601 logical :: use_perp_flux
4602 integer :: iw, ix^d, idir
4603
4604 {do ix^db=ixomin^db,ixomax^db\}
4605 ! Get flux of density
4606 if(has_equi_rho_and_p) then
4607 f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
4608 else
4609 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4610 end if
4611
4612 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4613
4614 if(b0field) then
4615 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)+block%B0(ix^d,^c,idim)\
4616 ptotal=ptotal+(^c&w(ix^d,b^c_)*block%B0(ix^d,^c,idim)+)
4617 ! Get flux of momentum and magnetic field
4618 ! f_i[m_k]=v_i*m_k-b_k*b_i
4619 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-&
4620 btotal(ix^d,idim)*w(ix^d,b^c_)-w(ix^d,mag(idim))*block%B0(ix^d,^c,idim)\
4621 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4622 else
4623 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)\
4624 ! Get flux of momentum and magnetic field
4625 ! f_i[m_k]=v_i*m_k-b_k*b_i
4626 ^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_)\
4627 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4628 end if
4629 ! f_i[b_k]=v_i*b_k-v_k*b_i
4630 ^c&f(ix^d,b^c_)=w(ix^d,mom(idim))*btotal(ix^d,^c)-btotal(ix^d,idim)*w(ix^d,m^c_)\
4631
4632 ! Get flux of energy
4633 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4634 if(mhd_internal_e) then
4635 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4636 else
4637 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4638 -btotal(ix^d,idim)*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4639 end if
4640 {end do\}
4641
4642 if(mhd_glm) then
4643 {do ix^db=ixomin^db,ixomax^db\}
4644 f(ix^d,mag(idim))=w(ix^d,psi_)
4645 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4646 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4647 {end do\}
4648 end if
4649
4650 if(mhd_radiation_fld) then
4651 {do ix^db=ixomin^db,ixomax^db\}
4652 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4653 {end do\}
4654 endif
4655
4656 if(mhd_hall) then
4657 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4658 {do ix^db=ixomin^db,ixomax^db\}
4659 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4660 ^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)\
4661 if(total_energy) then
4662 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4663 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)*btotal(ix^d,^c)+)&
4664 -btotal(ix^d,idim)*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4665 end if
4666 {end do\}
4667 end if
4668 if (mhd_fip) then
4669 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4670 end if
4671 ! Get flux of tracer
4672 do iw=1,mhd_n_tracer
4673 {do ix^db=ixomin^db,ixomax^db\}
4674 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4675 {end do\}
4676 end do
4678 if(use_perp_flux) then
4679 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4680 call mhd_get_rfactor(w,x,ixi^l,ixi^l,r)
4681 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4682 {do ix^db=ixomin^db,ixomax^db\}
4683 do idir=1,ndir
4684 bvec(ix^d,idir)=btotal(ix^d,idir)
4685 end do
4686 {end do\}
4687 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4688 end if
4689 if(mhd_hyperbolic_tc) then
4690 {do ix^db=ixomin^db,ixomax^db\}
4691 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*btotal(ix^d,idim)/(dsqrt(^c&btotal(ix^d,^c)**2+)+smalldouble)
4692 f(ix^d,qpar_)=zero
4693 if(use_perp_flux) then
4694 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4695 f(ix^d,qperp_)=zero
4696 end if
4697 {end do\}
4698 end if
4699 end subroutine mhd_get_flux_split
4700
4701 !> Calculate semirelativistic fluxes within ixO^L without any splitting
4702 subroutine mhd_get_flux_semirelati(wC,w,x,ixI^L,ixO^L,idim,f)
4704 use mod_geometry
4705
4706 integer, intent(in) :: ixi^l, ixo^l, idim
4707 ! conservative w
4708 double precision, intent(in) :: wc(ixi^s,nw)
4709 ! primitive w
4710 double precision, intent(in) :: w(ixi^s,nw)
4711 double precision, intent(in) :: x(ixi^s,1:ndim)
4712 double precision,intent(out) :: f(ixi^s,nwflux)
4713 double precision :: sa(ixo^s,1:ndir),e(ixo^s,1:ndir),e2
4714 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4715 double precision :: bvec(ixi^s,1:ndir)
4716 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4717 double precision :: nperp(ixi^s,1:ndir)
4718 logical :: use_perp_flux
4719 integer :: iw, ix^d, idir
4720
4721 {do ix^db=ixomin^db,ixomax^db\}
4722 ! Get flux of density
4723 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4724 ! E=Bxv
4725 {^ifthreec
4726 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4727 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4728 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4729 }
4730 {^iftwoc
4731 e(ix^d,1)=zero
4732 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4733 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4734 }
4735 {^ifonec
4736 e(ix^d,1)=zero
4737 }
4738 e2=(^c&e(ix^d,^c)**2+)
4739 if(mhd_internal_e) then
4740 ! Get flux of internal energy
4741 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4742 else
4743 ! S=ExB
4744 {^ifthreec
4745 sa(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
4746 sa(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
4747 sa(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
4748 }
4749 {^iftwoc
4750 sa(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
4751 sa(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
4752 ! set E2 back to 0, after e^2 is stored
4753 e(ix^d,2)=zero
4754 }
4755 {^ifonec
4756 sa(ix^d,1)=zero
4757 }
4758 ! Get flux of total energy
4759 f(ix^d,e_)=w(ix^d,mom(idim))*(half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)+&
4760 mhd_gamma*w(ix^d,p_)*inv_gamma_1)+sa(ix^d,idim)
4761 end if
4762 ! Get flux of momentum
4763 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4764 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4765 ! gas pressure + magnetic pressure + electric pressure
4766 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)
4767 ! compute flux of magnetic field
4768 ! f_i[b_k]=v_i*b_k-v_k*b_i
4769 ^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_)\
4770 {end do\}
4771
4772 if(mhd_glm) then
4773 {do ix^db=ixomin^db,ixomax^db\}
4774 f(ix^d,mag(idim))=w(ix^d,psi_)
4775 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4776 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4777 {end do\}
4778 end if
4779 if (mhd_fip) then
4780 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4781 end if
4782 ! Get flux of tracer
4783 do iw=1,mhd_n_tracer
4784 {do ix^db=ixomin^db,ixomax^db\}
4785 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4786 {end do\}
4787 end do
4789 if(use_perp_flux) then
4790 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4791 call mhd_get_rfactor(w,x,ixi^l,ixi^l,r)
4792 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4793 {do ix^db=ixomin^db,ixomax^db\}
4794 do idir=1,ndir
4795 bvec(ix^d,idir)=w(ix^d,mag(idir))
4796 end do
4797 {end do\}
4798 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4799 end if
4800 if(mhd_hyperbolic_tc) then
4801 {do ix^db=ixomin^db,ixomax^db\}
4802 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)
4803 f(ix^d,qpar_)=zero
4804 if(use_perp_flux) then
4805 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4806 f(ix^d,qperp_)=zero
4807 end if
4808 {end do\}
4809 end if
4810 end subroutine mhd_get_flux_semirelati
4811
4812 subroutine mhd_get_flux_semirelati_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4814 use mod_geometry
4816
4817 integer, intent(in) :: ixi^l, ixo^l, idim
4818 ! conservative w
4819 double precision, intent(in) :: wc(ixi^s,nw)
4820 ! primitive w
4821 double precision, intent(in) :: w(ixi^s,nw)
4822 double precision, intent(in) :: x(ixi^s,1:ndim)
4823 double precision,intent(out) :: f(ixi^s,nwflux)
4824
4825 double precision :: adiabs(ixi^s), gammas(ixi^s)
4826 double precision :: e(ixo^s,1:ndir),e2
4827 integer :: iw, ix^d
4828
4829 if(associated(usr_set_adiab)) then
4830 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4831 else
4832 adiabs=mhd_adiab
4833 end if
4834 if(associated(usr_set_gamma)) then
4835 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4836 else
4837 gammas=mhd_gamma
4838 end if
4839 {do ix^db=ixomin^db,ixomax^db\}
4840 ! Get flux of density
4841 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4842 ! E=Bxv
4843 {^ifthreec
4844 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4845 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4846 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4847 e2=(^c&e(ix^d,^c)**2+)
4848 }
4849 {^iftwoc
4850 e(ix^d,1)=zero
4851 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4852 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4853 e2=e(ix^d,2)**2
4854 e(ix^d,2)=zero
4855 }
4856 {^ifonec
4857 e(ix^d,1)=zero
4858 e2=zero
4859 }
4860 ! Get flux of momentum
4861 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4862 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4863 ! gas pressure + magnetic pressure + electric pressure
4864 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)
4865 ! compute flux of magnetic field
4866 ! f_i[b_k]=v_i*b_k-v_k*b_i
4867 ^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_)\
4868 {end do\}
4869
4870 if(mhd_glm) then
4871 {do ix^db=ixomin^db,ixomax^db\}
4872 f(ix^d,mag(idim))=w(ix^d,psi_)
4873 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4874 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4875 {end do\}
4876 end if
4877 if (mhd_fip) then
4878 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4879 end if
4880 ! Get flux of tracer
4881 do iw=1,mhd_n_tracer
4882 {do ix^db=ixomin^db,ixomax^db\}
4883 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4884 {end do\}
4885 end do
4886 end subroutine mhd_get_flux_semirelati_noe
4887
4888 !> Source term J.E_ambi in internal energy
4889 !> For the ambipolar electric field we have E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4890 !> and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4891 !> the source term J.E_ambi = eta_A * B^2 * J_perpB^2 = eta_A * [(JxB)xB]^2/B^2
4892 !> note that J_perpB= - (JxB)xB/B^2
4893 !> multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4894 subroutine add_source_ambipolar_internal_energy(qdt,ixI^L,ixO^L,wCT,w,x)
4896 integer, intent(in) :: ixi^l, ixo^l
4897 double precision, intent(in) :: qdt
4898 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4899 double precision, intent(inout) :: w(ixi^s,1:nw)
4900
4901 double precision :: tmp(ixi^s),btot2(ixi^s)
4902 double precision :: jxbxb(ixi^s,1:3)
4903
4904 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,jxbxb)
4905 ! avoiding nulls here
4906 btot2(ixo^s)=mhd_mag_en_all(wct,ixi^l,ixo^l)
4907 where (btot2(ixo^s)>smalldouble )
4908 tmp(ixo^s) = sum(jxbxb(ixo^s,1:3)**2,dim=ndim+1) / btot2(ixo^s)
4909 elsewhere
4910 tmp(ixo^s) = zero
4911 endwhere
4912 call multiplyambicoef(ixi^l,ixo^l,tmp,wct,x)
4913 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4914 ! hence minus sign here
4915 w(ixo^s,e_)=w(ixo^s,e_)- qdt*tmp(ixo^s)
4916
4917 end subroutine add_source_ambipolar_internal_energy
4918
4919 !> this subroutine computes -J_perpB= (J x B) x B= B(J.B) - J B^2
4920 subroutine mhd_get_jxbxb(w,x,ixI^L,ixO^L,res)
4922
4923 integer, intent(in) :: ixi^l, ixo^l
4924 double precision, intent(in) :: w(ixi^s,nw)
4925 double precision, intent(in) :: x(ixi^s,1:ndim)
4926 double precision, intent(out) :: res(ixi^s,1:3)
4927
4928 double precision :: btot(ixi^s,1:3)
4929 double precision :: current(ixi^s,7-2*ndir:3)
4930 double precision :: tmp(ixi^s),b2(ixi^s)
4931 integer :: idir, idirmin
4932
4933 res=0.d0
4934 ! Calculate current density and idirmin
4935 ! current has nonzero values only for components in the range idirmin, 3
4936 call get_current(w,ixi^l,ixo^l,idirmin,current)
4937
4938 btot=0.d0
4939 if(b0field) then
4940 do idir=1,ndir
4941 btot(ixo^s, idir) = w(ixo^s,mag(idir)) + block%B0(ixo^s,idir,b0i)
4942 enddo
4943 else
4944 do idir=1,ndir
4945 btot(ixo^s, idir) = w(ixo^s,mag(idir))
4946 enddo
4947 endif
4948
4949 tmp(ixo^s)= sum(current(ixo^s,idirmin:3)*btot(ixo^s,idirmin:3),dim=ndim+1) !J.B
4950 b2(ixo^s) = sum(btot(ixo^s,1:3)**2,dim=ndim+1) !B^2
4951 do idir=1,idirmin-1
4952 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s)
4953 enddo
4954 do idir=idirmin,3
4955 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s) - current(ixo^s,idir) * b2(ixo^s)
4956 enddo
4957
4958 ! avoid possible issues at nulls
4959 do idir=1,3
4960 where (b2(ixo^s)<smalldouble )
4961 res(ixo^s,idir) = zero
4962 endwhere
4963 enddo
4964 end subroutine mhd_get_jxbxb
4965
4966 !> Sets the sources for the ambipolar terms for the STS method
4967 !> The sources are added directly (instead of fluxes as in the explicit)
4968 !> at the corresponding indices
4969 !> store_flux_var is explicitly called for each of the fluxes one by one
4970 subroutine sts_set_source_ambipolar(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
4973
4974 integer, intent(in) :: ixi^l,ixo^l,igrid,nflux
4975 double precision, intent(in) :: x(ixi^s,1:ndim)
4976 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
4977 double precision, intent(in) :: my_dt
4978 logical, intent(in) :: fix_conserve_at_step
4979
4980 double precision, dimension(ixI^S,1:3) :: tmp,ff
4981 double precision :: fluxall(ixi^s,1:nflux,1:ndim)
4982 double precision :: fe(ixi^s,sdim:3)
4983 double precision :: btot(ixi^s,1:3),tmp2(ixi^s)
4984 integer :: i, ixa^l, ie_
4985
4986 ixa^l=ixo^l^ladd1;
4987
4988 fluxall=zero
4989
4990 ! here we compute (JxB)xB= - B^2 J_perpB
4991 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,tmp)
4992
4993 ! set ambipolar electric field in tmp: E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4994 ! and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4995 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4996 do i=1,3
4997 call multiplyambicoef(ixi^l,ixa^l,tmp(ixi^s,i),w,x)
4998 enddo
4999
5000 ! Note: internal energy case is handled through add_source_internal_e
5001 ! Note: hydrodynamic energy case is handled through add_source_hydrodynamic_e
5002 ! both of the above use add_source_ambipolar_internal_energy
5003 !
5004 ! Note: total energy case without B0field split is ok here and adds div(BxE_ambi)
5005 ! Note: total energy case in semirelativistic variant (hence no B0field split) is ok here
5006 ! Note: total energy with B0field=T here adds div(B_1xE_ambi) which needs correction in add_source_B0split
5007 if(mhd_energy .and. .not.(mhd_internal_e.or.mhd_hydrodynamic_e)) then
5008 btot(ixa^s,1:3) = 0.d0
5009 ! HERE: only uses B_1 if split, otherwise this is B
5010 btot(ixa^s,1:ndir) = w(ixa^s,mag(1:ndir))
5011 ! compute ff= E_ambi x B (where B can be B_1 if B0field=T)
5012 call cross_product(ixi^l,ixa^l,tmp,btot,ff)
5013 ! compute actual cell face fluxes in ff and their divergence in tmp2
5014 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5015 if(fix_conserve_at_step) fluxall(ixi^s,1,1:ndim)=ff(ixi^s,1:ndim)
5016 ! - sign as the source is actually div(BxE_ambi) and we have div(E_ambi x B) in tmp2
5017 wres(ixo^s,e_)=-tmp2(ixo^s)
5018 endif
5019
5020 if(stagger_grid) then
5021 ! always 2D or more (2.5/3D)
5022 if(ndir>ndim) then
5023 !!!Bz
5024 ff(ixa^s,1) = tmp(ixa^s,2)
5025 ff(ixa^s,2) = -tmp(ixa^s,1)
5026 ff(ixa^s,3) = 0.d0
5027 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5028 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
5029 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
5030 end if
5031 fe=0.d0
5032 call update_faces_ambipolar(ixi^l,ixo^l,w,x,tmp,fe,btot)
5033 ixamax^d=ixomax^d;
5034 ixamin^d=ixomin^d-1;
5035 wres(ixa^s,mag(1:ndim))=-btot(ixa^s,1:ndim)
5036 else
5037 !write curl(ele) as the divergence
5038 !m1={0,ele[[3]],-ele[[2]]}
5039 !m2={-ele[[3]],0,ele[[1]]}
5040 !m3={ele[[2]],-ele[[1]],0}
5041
5042 {^ifoned
5043 !!!Bx
5044 ff(ixa^s,1) = 0.d0
5045 ff(ixa^s,2) = tmp(ixa^s,3)
5046 ff(ixa^s,3) = -tmp(ixa^s,2)
5047 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5048 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
5049 !flux divergence is a source now
5050 wres(ixo^s,mag(1))=-tmp2(ixo^s)
5051 if(ndir==2.or.ndir==3)then
5052 !!!By
5053 ff(ixa^s,1) = -tmp(ixa^s,3)
5054 ff(ixa^s,2) = 0.d0
5055 ff(ixa^s,3) = tmp(ixa^s,1)
5056 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5057 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
5058 wres(ixo^s,mag(2))=-tmp2(ixo^s)
5059 endif
5060 }
5061 {^nooned
5062 !!!Bx
5063 ff(ixa^s,1) = 0.d0
5064 ff(ixa^s,2) = tmp(ixa^s,3)
5065 ff(ixa^s,3) = -tmp(ixa^s,2)
5066 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5067 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
5068 !flux divergence is a source now
5069 wres(ixo^s,mag(1))=-tmp2(ixo^s)
5070 !!!By
5071 ff(ixa^s,1) = -tmp(ixa^s,3)
5072 ff(ixa^s,2) = 0.d0
5073 ff(ixa^s,3) = tmp(ixa^s,1)
5074 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5075 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
5076 wres(ixo^s,mag(2))=-tmp2(ixo^s)
5077 }
5078
5079 if(ndir==3) then
5080 !!!Bz
5081 ff(ixa^s,1) = tmp(ixa^s,2)
5082 ff(ixa^s,2) = -tmp(ixa^s,1)
5083 ff(ixa^s,3) = 0.d0
5084 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
5085 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
5086 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
5087 end if
5088
5089 end if
5090
5091 if(fix_conserve_at_step) then
5092 fluxall=my_dt*fluxall
5093 call store_flux(igrid,fluxall,1,ndim,nflux)
5094 if(stagger_grid) then
5095 call store_edge(igrid,ixi^l,my_dt*fe,1,ndim)
5096 end if
5097 end if
5098
5099 end subroutine sts_set_source_ambipolar
5100
5101 !> get ambipolar electric field and the integrals around cell faces
5102 subroutine update_faces_ambipolar(ixI^L,ixO^L,w,x,ECC,fE,circ)
5104
5105 integer, intent(in) :: ixi^l, ixo^l
5106 double precision, intent(in) :: w(ixi^s,1:nw)
5107 double precision, intent(in) :: x(ixi^s,1:ndim)
5108 ! amibipolar electric field at cell centers
5109 double precision, intent(in) :: ecc(ixi^s,1:3)
5110 double precision, intent(out) :: fe(ixi^s,sdim:3)
5111 double precision, intent(out) :: circ(ixi^s,1:ndim)
5112
5113 integer :: hxc^l,ixc^l,ixa^l
5114 integer :: idim1,idim2,idir,ix^d
5115
5116 fe=zero
5117 ! calculate ambipolar electric field on cell edges from cell centers
5118 do idir=sdim,3
5119 ixcmax^d=ixomax^d;
5120 ixcmin^d=ixomin^d+kr(idir,^d)-1;
5121 {do ix^db=0,1\}
5122 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
5123 ixamin^d=ixcmin^d+ix^d;
5124 ixamax^d=ixcmax^d+ix^d;
5125 fe(ixc^s,idir)=fe(ixc^s,idir)+ecc(ixa^s,idir)
5126 {end do\}
5127 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0*block%dsC(ixc^s,idir)
5128 end do
5129
5130 ! Calculate circulation on each face to get value of line integral of
5131 ! electric field in the positive idir direction.
5132 ixcmax^d=ixomax^d;
5133 ixcmin^d=ixomin^d-1;
5134
5135 circ=zero
5136 do idim1=1,ndim ! Coordinate perpendicular to face
5137 do idim2=1,ndim
5138 do idir=sdim,3 ! Direction of line integral
5139 ! Assemble indices
5140 hxc^l=ixc^l-kr(idim2,^d);
5141 ! Add line integrals in direction idir
5142 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5143 +lvc(idim1,idim2,idir)&
5144 *(fe(ixc^s,idir)&
5145 -fe(hxc^s,idir))
5146 end do
5147 end do
5148 circ(ixc^s,idim1)=circ(ixc^s,idim1)/block%surfaceC(ixc^s,idim1)
5149 end do
5150
5151 end subroutine update_faces_ambipolar
5152
5153 !> use cell-center flux vector to get cell-face flux vector
5154 !> which will be used to add the source term as the divergence of the flux
5155 !> we return fluxes at all faces as well as the divergence of the flux
5156 !> Note that for ndir>ndim, we do not modify the input cell center flux
5157 subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
5159
5160 integer, intent(in) :: ixi^l, ixo^l
5161 double precision, dimension(ixI^S,1:3), intent(inout) :: ff
5162 double precision, intent(out) :: src(ixi^s)
5163
5164 double precision :: ffc(ixi^s,1:ndim)
5165 double precision :: dxinv(ndim)
5166 integer :: idims, ix^d, ixa^l, ixb^l, ixc^l
5167
5168 ixa^l=ixo^l^ladd1;
5169 dxinv=1.d0/dxlevel
5170 ! cell corner flux in ffc
5171 ! TO BE GENERALIZED FOR NON-UNIFORM NON-CARTESIAN MESH
5172 if (slab_uniform)then
5173 ffc=0.d0
5174 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
5175 {do ix^db=0,1\}
5176 ixbmin^d=ixcmin^d+ix^d;
5177 ixbmax^d=ixcmax^d+ix^d;
5178 ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
5179 {end do\}
5180 ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
5181 else
5182 call mpistop("to generalize using volume averaging")
5183 endif
5184 ! now get flux at cell face from corner fluxes in fcc
5185 ff(ixi^s,1:ndim)=0.d0
5186 do idims=1,ndim
5187 ixb^l=ixo^l-kr(idims,^d);
5188 ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
5189 {do ix^db=0,1 \}
5190 if({ ix^d==0 .and. ^d==idims | .or.}) then
5191 ixbmin^d=ixcmin^d-ix^d;
5192 ixbmax^d=ixcmax^d-ix^d;
5193 ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
5194 end if
5195 {end do\}
5196 ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
5197 end do
5198 src=0.d0
5199 if(slab_uniform) then
5200 do idims=1,ndim
5201 ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
5202 ixb^l=ixo^l-kr(idims,^d);
5203 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
5204 end do
5205 else
5206 do idims=1,ndim
5207 ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
5208 ixb^l=ixo^l-kr(idims,^d);
5209 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
5210 end do
5211 src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
5212 end if
5213 end subroutine get_flux_on_cell_face
5214
5215 !> Calculates the explicit dt for the ambipolar term
5216 !> This function is used by both explicit scheme and STS method
5217 function get_ambipolar_dt(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
5219
5220 integer, intent(in) :: ixi^l, ixo^l
5221 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
5222 double precision, intent(in) :: w(ixi^s,1:nw)
5223 double precision :: dtnew
5224
5225 double precision :: coef
5226 double precision :: dxarr(ndim)
5227 double precision :: tmp(ixi^s)
5228
5229 ^d&dxarr(^d)=dx^d;
5230 tmp(ixo^s) = mhd_mag_en_all(w, ixi^l, ixo^l)
5231 call multiplyambicoef(ixi^l,ixo^l,tmp,w,x)
5232 ! now we have -mhd_eta_ambi B^2 /rho^2 in tmp
5233 coef = maxval(dabs(tmp(ixo^s)))
5234 if(coef/=0.d0) then
5235 coef=1.d0/coef
5236 else
5237 coef=bigdouble
5238 end if
5239 if(slab_uniform) then
5240 dtnew=minval(dxarr(1:ndim))**2.0d0*coef
5241 else
5242 dtnew=minval(block%ds(ixo^s,1:ndim))**2.0d0*coef
5243 end if
5244
5245 end function get_ambipolar_dt
5246
5247 !> multiply res by the ambipolar coefficient
5248 !> The ambipolar coefficient is calculated as -mhd_eta_ambi/rho^2
5249 !> The user may mask its value in the user file
5250 !> by implementing usr_mask_ambipolar subroutine
5251 subroutine multiplyambicoef(ixI^L,ixO^L,res,w,x)
5253 integer, intent(in) :: ixi^l, ixo^l
5254 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
5255 double precision, intent(inout) :: res(ixi^s)
5256 double precision :: tmp(ixi^s)
5257 double precision :: rho(ixi^s)
5258
5259 call mhd_get_rho(w,x,ixi^l,ixi^l,rho)
5260 tmp(ixi^s)=-mhd_eta_ambi/rho(ixi^s)**2
5261 if (associated(usr_mask_ambipolar)) then
5262 call usr_mask_ambipolar(ixi^l,ixo^l,w,x,tmp)
5263 end if
5264 res(ixo^s) = tmp(ixo^s) * res(ixo^s)
5265
5266 end subroutine multiplyambicoef
5267
5268 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
5269 subroutine mhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5274 use mod_cak_force, only: cak_add_source
5275
5276 integer, intent(in) :: ixi^l, ixo^l
5277 double precision, intent(in) :: qdt,dtfactor
5278 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
5279 double precision, intent(inout) :: w(ixi^s,1:nw)
5280 logical, intent(in) :: qsourcesplit
5281 logical, intent(inout) :: active
5282
5283 !TODO local_timestep support is only added for splitting
5284 ! but not for other nonideal terms such gravity, RC, viscosity,..
5285 ! it will also only work for divbfix 'linde', which does not require
5286 ! modification as it does not use dt in the update
5287
5288 if (.not. qsourcesplit) then
5289 if(mhd_internal_e) then
5290 ! Source for solving internal energy
5291 active = .true.
5292 call add_source_internal_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5293 else
5294 if(has_equi_rho_and_p) then
5295 active = .true.
5296 call add_equi_terms(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5297 end if
5298 end if
5299
5300 if(mhd_hyperbolic_tc) then
5301 active = .true.
5302 call add_hyperbolic_tc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5303 end if
5304
5305 ! Source for B0 splitting
5306 if (b0field) then
5307 active = .true.
5308 ! this adds source to momentum of type J0 x B0 and to energy equation
5309 ! latter always + J0 * E (electric field being E_ideal, E_hall, E_ambi)
5310 ! used for total energy variants
5311 call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5312 end if
5313
5314 ! Sources for resistivity in eqs. for e, B1, B2 and B3
5315 if (abs(mhd_eta)>smalldouble)then
5316 active = .true.
5317 call add_source_res_exp(qdt,ixi^l,ixo^l,wct,w,x)
5318 end if
5319
5320 if (mhd_ambipolar_exp)then
5321 active = .true.
5322 call add_source_ambi_exp(qdt,ixi^l,ixo^l,wct,w,x)
5323 end if
5324
5325 if (mhd_eta_hyper>0.d0)then
5326 active = .true.
5327 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
5328 end if
5329
5330 if(mhd_hydrodynamic_e) then
5331 ! Source for solving hydrodynamic energy
5332 active = .true.
5333 call add_source_hydrodynamic_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5334 else if (mhd_semirelativistic) then
5335 ! add sources for semirelativistic MHD
5336 active = .true.
5337 call add_source_semirelativistic(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5338 end if
5339 end if
5340
5341 {^nooned
5342 if(source_split_divb .eqv. qsourcesplit) then
5343 ! Sources related to div B
5344 select case (type_divb)
5345 case (divb_ct)
5346 continue ! Do nothing
5347 case (divb_linde)
5348 active = .true.
5349 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5350 case (divb_glm)
5351 active = .true.
5352 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5353 case (divb_powel)
5354 active = .true.
5355 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5356 case (divb_janhunen)
5357 active = .true.
5358 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5359 case (divb_lindejanhunen)
5360 active = .true.
5361 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5362 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5363 case (divb_lindepowel)
5364 active = .true.
5365 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5366 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5367 case (divb_lindeglm)
5368 active = .true.
5369 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5370 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5371 case (divb_multigrid)
5372 continue ! Do nothing
5373 case (divb_none)
5374 ! Do nothing
5375 case default
5376 call mpistop('Unknown divB fix')
5377 end select
5378 end if
5379 }
5380
5381 if(mhd_radiative_cooling) then
5382 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5383 w,x,qsourcesplit,active, rc_fl)
5384 end if
5385
5386 if(mhd_viscosity) then
5387 call viscosity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5388 w,x,mhd_energy,qsourcesplit,active)
5389 end if
5390
5391 if(mhd_gravity) then
5392 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5393 w,x,gravity_energy,qsourcesplit,active)
5394 end if
5395
5396 if (mhd_cak_force) then
5397 call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,mhd_energy,qsourcesplit,active)
5398 end if
5399
5400 ! This is where the radiation force and heating/cooling are added
5401 if (mhd_radiation_fld) then
5402 call mhd_add_radiation_source(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
5403 endif
5404
5405 ! update temperature from new pressure, density, and old ionization degree
5406 if(mhd_partial_ionization) then
5407 if(.not.qsourcesplit) then
5408 active = .true.
5409 call mhd_update_temperature(ixi^l,ixo^l,wct,w,x)
5410 end if
5411 end if
5412
5413 end subroutine mhd_add_source
5414
5415 subroutine mhd_add_radiation_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5416 use mod_constants
5418 use mod_usr_methods
5419 use mod_fld
5420
5421 integer, intent(in) :: ixi^l, ixo^l
5422 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
5423 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
5424 double precision, intent(inout) :: w(ixi^s,1:nw)
5425 logical, intent(in) :: qsourcesplit
5426 logical, intent(inout) :: active
5427
5428 ! add radiation force and work done by it, changes momentum and gas energy
5429 ! handle photon tiring, heating and cooling exchange between gas and radiation field
5430 call add_fld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
5431
5432 end subroutine mhd_add_radiation_source
5433
5434 !> add some source terms to total energy related to has_equi_rho_and_p=T
5435 subroutine add_equi_terms(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5437 use mod_geometry
5438 use mod_usr_methods
5439
5440 integer, intent(in) :: ixi^l, ixo^l
5441 double precision, intent(in) :: qdt,dtfactor
5442 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5443 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5444 double precision, intent(inout) :: w(ixi^s,1:nw)
5445
5446 double precision :: divv(ixi^s)
5447 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5448 double precision :: gravity_field(ixi^s,1:ndim)
5449 integer :: idir
5450
5451 if(slab_uniform) then
5452 if(nghostcells .gt. 2) then
5453 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,3)
5454 else
5455 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,2)
5456 end if
5457 else
5458 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv)
5459 end if
5460 divv(ixo^s)=divv(ixo^s)*mhd_gamma*inv_gamma_1
5461 if(local_timestep) then
5462 w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5463 else
5464 w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5465 end if
5466 if(b0field)then
5467 if(b0field_forcefree.and.mhd_gravity)then
5468 ! add -v dot(rho_0 g)/(gamma-1)
5469 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5470 do idir=1,ndim
5471 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*inv_gamma_1
5472 enddo
5473 else
5474 a=0.d0
5475 b=0.d0
5476 ! store B0 magnetic field in b
5477 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5478 ! store J0 current in a
5479 do idir=7-2*ndir,3
5480 a(ixo^s,idir)=block%J0(ixo^s,idir)
5481 end do
5482 call cross_product(ixi^l,ixo^l,a,b,axb)
5483 ! add -v dot(rho_0 g + J0 x B_0)/(gamma-1)
5484 do idir=1,ndir
5485 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*axb(ixo^s,idir)*inv_gamma_1
5486 enddo
5487 if(mhd_gravity)then
5488 ! add -v dot(rho_0 g)/(gamma-1)
5489 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5490 do idir=1,ndim
5491 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)*inv_gamma_1
5492 enddo
5493 endif
5494 endif
5495 else
5496 if(mhd_gravity)then
5497 ! add -v dot(rho_0 g)/(gamma-1)
5498 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5499 do idir=1,ndim
5500 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)*inv_gamma_1
5501 enddo
5502 endif
5503 endif
5504 end subroutine add_equi_terms
5505
5506 subroutine mhd_get_hyperbolic_tc_geometry(ixI^L,ixO^L,Te,Bvec,bgradT,gradTperp_mag,nperp)
5508 use mod_geometry, only: gradient
5509 integer, intent(in) :: ixi^l,ixo^l
5510 double precision, intent(in) :: te(ixi^s)
5511 double precision, intent(in) :: bvec(ixi^s,1:ndir)
5512 double precision, intent(out) :: bgradt(ixi^s), gradtperp_mag(ixi^s)
5513 double precision, intent(out) :: nperp(ixi^s,1:ndir)
5514
5515 double precision :: bmag, bunitvec(ndir), gradt(ndir), gradt_perp(ndir)
5516 double precision :: gradt_cell(ixi^s,1:ndir)
5517 integer :: ix^d, idir
5518
5519 gradt_cell=zero
5520 if(.not. slab_uniform) then
5521 do idir=1,ndim
5522 call gradient(te,ixi^l,ixo^l,idir,gradt_cell(ixi^s,idir))
5523 end do
5524 end if
5525
5526 {^iftwod
5527 do ix2=ixomin2,ixomax2
5528 do ix1=ixomin1,ixomax1
5529 bmag=zero
5530 do idir=1,ndir
5531 bmag=bmag+bvec(ix^d,idir)**2
5532 end do
5533 bmag=dsqrt(bmag)
5534
5535 if(bmag>smalldouble) then
5536 do idir=1,ndir
5537 bunitvec(idir)=bvec(ix^d,idir)/bmag
5538 end do
5539 else
5540 do idir=1,ndir
5541 bunitvec(idir)=zero
5542 end do
5543 end if
5544 if(slab_uniform) then
5545 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)
5546 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)
5547 if(ndir>2) gradt(3)=zero
5548 else
5549 do idir=1,ndir
5550 gradt(idir)=gradt_cell(ix^d,idir)
5551 end do
5552 end if
5553
5554 bgradt(ix^d)=zero
5555 do idir=1,ndir
5556 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
5557 end do
5558
5559 do idir=1,ndir
5560 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
5561 end do
5562
5563 gradtperp_mag(ix^d)=zero
5564 do idir=1,ndir
5565 gradtperp_mag(ix^d)=gradtperp_mag(ix^d)+gradt_perp(idir)**2
5566 end do
5567 gradtperp_mag(ix^d)=dsqrt(gradtperp_mag(ix^d))
5568
5569 if(gradtperp_mag(ix^d)>smalldouble) then
5570 do idir=1,ndir
5571 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
5572 end do
5573 else
5574 gradtperp_mag(ix^d)=zero
5575 do idir=1,ndir
5576 nperp(ix^d,idir)=zero
5577 end do
5578 end if
5579 end do
5580 end do
5581 }
5582 {^ifthreed
5583 do ix3=ixomin3,ixomax3
5584 do ix2=ixomin2,ixomax2
5585 do ix1=ixomin1,ixomax1
5586 bmag=dsqrt(bvec(ix^d,1)**2+bvec(ix^d,2)**2+bvec(ix^d,3)**2)
5587 if(bmag>smalldouble) then
5588 bunitvec(1)=bvec(ix^d,1)/bmag
5589 bunitvec(2)=bvec(ix^d,2)/bmag
5590 bunitvec(3)=bvec(ix^d,3)/bmag
5591 else
5592 bunitvec(1)=zero
5593 bunitvec(2)=zero
5594 bunitvec(3)=zero
5595 end if
5596
5597 if(slab_uniform) then
5598 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)
5599 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)
5600 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)
5601 else
5602 do idir=1,ndir
5603 gradt(idir)=gradt_cell(ix^d,idir)
5604 end do
5605 end if
5606
5607 bgradt(ix^d)=zero
5608 do idir=1,ndir
5609 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
5610 end do
5611
5612 do idir=1,ndir
5613 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
5614 end do
5615
5616 gradtperp_mag(ix^d)=dsqrt(gradt_perp(1)**2+gradt_perp(2)**2+gradt_perp(3)**2)
5617 if(gradtperp_mag(ix^d)>smalldouble) then
5618 do idir=1,ndir
5619 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
5620 end do
5621 else
5622 gradtperp_mag(ix^d)=zero
5623 do idir=1,ndir
5624 nperp(ix^d,idir)=zero
5625 end do
5626 end if
5627 end do
5628 end do
5629 end do
5630 }
5631 end subroutine mhd_get_hyperbolic_tc_geometry
5632
5633 subroutine add_hyperbolic_tc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5635 use mod_geometry, only: gradient
5636 integer, intent(in) :: ixi^l,ixo^l
5637 double precision, intent(in) :: qdt
5638 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
5639 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
5640 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
5641
5642 double precision, dimension(ixI^S) :: r,te,rho_loc,pth_loc
5643 double precision, dimension(ixI^S,1:ndir) :: bvec
5644 double precision, dimension(ixI^S) :: bgradt, gradtperp_mag
5645 double precision, dimension(ixI^S,1:ndir) :: nperp
5646 double precision, dimension(ixI^S) :: gradt_geom
5647 double precision, parameter :: lnlambda_perp = 20.d0
5648 double precision, parameter :: xe_prefac_cgs = 4.753567596681522d6
5649 double precision :: kappa_t5,kappa_t5_perp,kappa_t5_perp_eff
5650 double precision :: kappa_t7,f_sat,kappat5_bgradt,kappat5_gradtperp,tau,b2,fb,gradt1
5651 double precision :: bmag_loc,tloc,tcond,nloc_code,cchi,chi
5652 double precision :: cmax(ndim),c2,cfast2,avmincs2(ndim),inv_rho
5653 logical :: use_perp_source
5654 integer :: ix^d,idir
5655
5656 cchi = 0.823d0*(xe_prefac_cgs/lnlambda_perp) * &
5658 call mhd_get_rfactor(wct,x,ixi^l,ixi^l,r)
5659 {do ix^db=iximin^db,iximax^db\}
5660 if(has_equi_rho_and_p) then
5661 rho_loc(ix^d)=wctprim(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
5662 pth_loc(ix^d)=wctprim(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)
5663 else
5664 rho_loc(ix^d)=wctprim(ix^d,rho_)
5665 pth_loc(ix^d)=wctprim(ix^d,p_)
5666 end if
5667 te(ix^d)=pth_loc(ix^d)/(r(ix^d)*rho_loc(ix^d))
5668 {end do\}
5670 if(b0field) then
5671 {do ix^db=ixomin^db,ixomax^db\}
5672 do idir=1,ndir
5673 bvec(ix^d,idir)=wct(ix^d,mag(idir))+block%B0(ix^d,idir,0)
5674 end do
5675 {end do\}
5676 else
5677 {do ix^db=ixomin^db,ixomax^db\}
5678 do idir=1,ndir
5679 bvec(ix^d,idir)=wct(ix^d,mag(idir))
5680 end do
5681 {end do\}
5682 end if
5683 {^nooned
5684 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
5685 }
5686 {^ifoned
5687 gradt_geom=zero
5688 if(.not.slab_uniform) then
5689 call gradient(te,ixi^l,ixo^l,1,gradt_geom)
5690 end if
5691 do ix1=ixomin1,ixomax1
5694 kappa_t7=kappa_t5*te(ix1)
5695 else
5696 tcond = te(ix1)
5697 if(mhd_trac) then
5698 tcond = max(tcond, block%wextra(ix1,tcoff_))
5699 end if
5700 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5701 kappa_t7=kappa_t5*tcond
5702 end if
5703 if(slab_uniform) then
5704 gradt1=((8.d0*(te(ix1+1)-te(ix1-1))-te(ix1+2)+te(ix1-2))/12.d0)/block%ds(ix1,1)
5705 else
5706 gradt1=gradt_geom(ix1)
5707 end if
5708 b2=zero
5709 do idir=1,ndir
5710 b2=b2+bvec(ix1,idir)**2
5711 end do
5712 if(b2>smalldouble**2) then
5713 bgradt(ix1)=bvec(ix1,1)*gradt1/dsqrt(b2)
5714 else
5715 bgradt(ix1)=zero
5716 end if
5717 kappat5_bgradt=kappa_t5*bgradt(ix1)
5718 inv_rho=1.d0/rho_loc(ix1)
5719 c2=mhd_gamma*pth_loc(ix1)*inv_rho
5720 cfast2 = b2*inv_rho + c2
5721 avmincs2(1) = cfast2**2 - 4.0d0*c2*bvec(ix1,1)**2*inv_rho
5722 cmax(1) = sqrt(half*(cfast2 + sqrt(dabs(avmincs2(1)))))
5723 if(mhd_hyperbolic_tc_sat) then
5724 f_sat=one/(one+dabs(kappat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5725 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*cmax(1)**2))
5726 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5727 else
5728 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/&
5729 max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*cmax(1)**2))
5730 end if
5731 end do
5732 }
5733 {^iftwod
5734 do ix2=ixomin2,ixomax2
5735 do ix1=ixomin1,ixomax1
5738 kappa_t7=kappa_t5*te(ix^d)
5739 else
5740 tcond=te(ix^d)
5741 if(mhd_trac) then
5742 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5743 end if
5744 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5745 kappa_t7 = kappa_t5*tcond
5746 end if
5747 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5748 b2 = zero
5749 do idir = 1, ndir
5750 b2 = b2 + bvec(ix^d,idir)**2
5751 end do
5752 if(use_perp_source) then
5753 select case(mhd_hyperbolic_tc_perp_mode)
5754 case(1)
5755 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5756 case(2)
5757 if(mhd_hyperbolic_tc_bmin>zero) then
5758 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5759 else
5760 fb=one
5761 end if
5762 kappa_t5_perp_eff=(one-fb)*kappa_t5
5763 kappa_t5_perp=kappa_t5_perp_eff
5764 case(3)
5765 bmag_loc = dsqrt(b2)
5766 tloc = max(te(ix^d), smalldouble)
5767 nloc_code = max(rho_loc(ix^d), smalldouble)
5768 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5769 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5770 kappa_t5_perp = kappa_t5_perp_eff
5771 case default
5772 kappa_t5_perp=zero
5773 end select
5774 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5775 end if
5776 inv_rho=1.d0/rho_loc(ix^d)
5777 c2=mhd_gamma*pth_loc(ix^d)*inv_rho
5778 cfast2 = b2*inv_rho + c2
5779 do idir=1,ndim
5780 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5781 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5782 end do
5783 if(mhd_hyperbolic_tc_sat) then
5784 f_sat=one/(one+dabs(kappat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5785 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5786 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5787 if(use_perp_source) then
5788 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5789 end if
5790 else
5791 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5792 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5793 if(use_perp_source) then
5794 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5795 end if
5796 end if
5797 end do
5798 end do
5799 }
5800 {^ifthreed
5801 do ix3=ixomin3,ixomax3
5802 do ix2=ixomin2,ixomax2
5803 do ix1=ixomin1,ixomax1
5806 kappa_t7=kappa_t5*te(ix^d)
5807 else
5808 tcond=te(ix^d)
5809 if(mhd_trac) then
5810 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5811 end if
5812 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5813 kappa_t7 = kappa_t5*tcond
5814 end if
5815 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5816 b2 = zero
5817 do idir = 1, ndir
5818 b2 = b2 + bvec(ix^d,idir)**2
5819 end do
5820 if(use_perp_source) then
5821 select case(mhd_hyperbolic_tc_perp_mode)
5822 case(1)
5823 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5824 case(2)
5825 if(mhd_hyperbolic_tc_bmin>zero) then
5826 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5827 else
5828 fb=one
5829 end if
5830 kappa_t5_perp_eff=(one-fb)*kappa_t5
5831 kappa_t5_perp=kappa_t5_perp_eff
5832 case(3)
5833 bmag_loc = dsqrt(b2)
5834 tloc = max(te(ix^d), smalldouble)
5835 nloc_code = max(rho_loc(ix^d), smalldouble)
5836 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5837 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5838 kappa_t5_perp = kappa_t5_perp_eff
5839 case default
5840 kappa_t5_perp=zero
5841 end select
5842 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5843 end if
5844 inv_rho=1.d0/rho_loc(ix^d)
5845 c2=mhd_gamma*pth_loc(ix^d)*inv_rho
5846 cfast2 = b2*inv_rho + c2
5847 do idir = 1, ndim
5848 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5849 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5850 end do
5851 if(mhd_hyperbolic_tc_sat) then
5852 f_sat=one/(one+dabs(kappat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5853 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5854 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5855 if(use_perp_source) then
5856 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5857 end if
5858 else
5859 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5860 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5861 if(use_perp_source) then
5862 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5863 end if
5864 end if
5865 end do
5866 end do
5867 end do
5868 }
5869 end subroutine add_hyperbolic_tc_source
5870
5871 !> Compute the Lorentz force (JxB) Note: Unused subroutine
5872 !> perhaps useful for post-processing when made public
5873 subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
5875 integer, intent(in) :: ixi^l, ixo^l
5876 double precision, intent(in) :: w(ixi^s,1:nw)
5877 double precision, intent(inout) :: jxb(ixi^s,3)
5878 double precision :: a(ixi^s,3), b(ixi^s,3)
5879 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5880 double precision :: current(ixi^s,7-2*ndir:3)
5881 integer :: idir, idirmin
5882
5883 b=0.0d0
5884 if(b0field) then
5885 do idir = 1, ndir
5886 b(ixo^s, idir) = w(ixo^s,mag(idir))+block%B0(ixo^s,idir,0)
5887 end do
5888 else
5889 do idir = 1, ndir
5890 b(ixo^s, idir) = w(ixo^s,mag(idir))
5891 end do
5892 end if
5893
5894 ! store J current in a
5895 call get_current(w,ixi^l,ixo^l,idirmin,current)
5896
5897 a=0.0d0
5898 do idir=7-2*ndir,3
5899 a(ixo^s,idir)=current(ixo^s,idir)
5900 end do
5901
5902 call cross_product(ixi^l,ixo^l,a,b,jxb)
5903 end subroutine get_lorentz_force
5904
5905 subroutine mhd_get_rho(w,x,ixI^L,ixO^L,rho)
5907 integer, intent(in) :: ixi^l, ixo^l
5908 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
5909 double precision, intent(out) :: rho(ixi^s)
5910
5911 if(has_equi_rho_and_p) then
5912 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
5913 else
5914 rho(ixo^s) = w(ixo^s,rho_)
5915 endif
5916
5917 end subroutine mhd_get_rho
5918
5919 !> handle small or negative internal energy
5920 subroutine mhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
5923 integer, intent(in) :: ixi^l,ixo^l, ie
5924 double precision, intent(inout) :: w(ixi^s,1:nw)
5925 double precision, intent(in) :: x(ixi^s,1:ndim)
5926 character(len=*), intent(in) :: subname
5927
5928 double precision :: rho(ixi^s)
5929 integer :: idir
5930 logical :: flag(ixi^s,1:nw)
5931
5932 flag=.false.
5933 if(has_equi_rho_and_p) then
5934 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1<small_e)&
5935 flag(ixo^s,ie)=.true.
5936 else
5937 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
5938 endif
5939 if(any(flag(ixo^s,ie))) then
5940 select case (small_values_method)
5941 case ("replace")
5942 if(has_equi_rho_and_p) then
5943 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
5944 block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
5945 else
5946 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
5947 endif
5948 case ("average")
5949 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
5950 case default
5951 ! small values error shows primitive variables
5952 w(ixo^s,e_)=w(ixo^s,e_)*gamma_1
5953 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
5954 do idir = 1, ndir
5955 w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
5956 end do
5957 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
5958 end select
5959 end if
5960
5961 end subroutine mhd_handle_small_ei
5962
5963 subroutine mhd_update_temperature(ixI^L,ixO^L,wCT,w,x)
5966
5967 integer, intent(in) :: ixi^l, ixo^l
5968 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5969 double precision, intent(inout) :: w(ixi^s,1:nw)
5970
5971 double precision :: iz_h(ixo^s),iz_he(ixo^s), pth(ixi^s)
5972
5973 call ionization_degree_from_temperature(ixi^l,ixo^l,wct(ixi^s,te_),iz_h,iz_he)
5974
5975 call mhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
5976
5977 w(ixo^s,te_)=(2.d0+3.d0*he_abundance)*pth(ixo^s)/(w(ixo^s,rho_)*(1.d0+iz_h(ixo^s)+&
5978 he_abundance*(iz_he(ixo^s)*(iz_he(ixo^s)+1.d0)+1.d0)))
5979
5980 end subroutine mhd_update_temperature
5981
5982 !> Source terms after split off time-independent magnetic field
5983 subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5985
5986 integer, intent(in) :: ixi^l, ixo^l
5987 double precision, intent(in) :: qdt, dtfactor,wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5988 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5989 double precision, intent(inout) :: w(ixi^s,1:nw)
5990
5991 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5992 integer :: idir
5993
5994 a=0.d0
5995 b=0.d0
5996 ! for force-free field J0xB0 =0
5997 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) then
5998 ! store B0 magnetic field in b
5999 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
6000
6001 ! store J0 current in a
6002 do idir=7-2*ndir,3
6003 a(ixo^s,idir)=block%J0(ixo^s,idir)
6004 end do
6005 call cross_product(ixi^l,ixo^l,a,b,axb)
6006 if(local_timestep) then
6007 do idir=1,3
6008 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
6009 enddo
6010 else
6011 axb(ixo^s,:)=axb(ixo^s,:)*qdt
6012 endif
6013 ! add J0xB0 source term in momentum equations
6014 w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
6015 end if
6016
6017 if(total_energy) then
6018 a=0.d0
6019 ! for free-free field -(vxB0) dot J0 =0
6020 b(ixo^s,:)=wctprim(ixo^s,mag(:))
6021 ! store full magnetic field B0+B1 in b
6022 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
6023 ! store velocity in a
6024 a(ixi^s,1:ndir)=wctprim(ixi^s,mom(1:ndir))
6025 ! -E = a x b
6026 call cross_product(ixi^l,ixo^l,a,b,axb)
6027 if(local_timestep) then
6028 do idir=1,3
6029 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
6030 enddo
6031 else
6032 axb(ixo^s,:)=axb(ixo^s,:)*qdt
6033 endif
6034 ! add -(vxB) dot J0 source term in energy equation
6035 ! where it is adding -J0 dot (vxB_1) when appropriate
6036 do idir=7-2*ndir,3
6037 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
6038 end do
6039 if(mhd_hall) then
6040 ! store hall velocity in a, only partial current is needed
6041 call mhd_getv_hall(wct,x,ixi^l,ixo^l,a,.true.)
6042 ! -E = a x b
6043 call cross_product(ixi^l,ixo^l,a,b,axb)
6044 if(local_timestep) then
6045 do idir=1,3
6046 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
6047 enddo
6048 else
6049 axb(ixo^s,:)=axb(ixo^s,:)*qdt
6050 endif
6051 ! add -(vxB) dot J0 source term in energy equation
6052 do idir=7-2*ndir,3
6053 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
6054 end do
6055 endif
6056 if(mhd_ambipolar_sts) then
6057 ! in STS variant of ambipolar, we added for split B the term div(B_1xE_ambi)
6058 ! hence needs to add J_0 dot E_ambi
6059 ! to get finally the term etaA (J_perpB)^/B^2-B_1 dot (curl Eambi)
6060 !reuse axb
6061 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,axb)
6062 ! source J0 * E
6063 do idir=sdim,3
6064 !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
6065 call multiplyambicoef(ixi^l,ixo^l,axb(ixi^s,idir),wct,x)
6066 w(ixo^s,e_)=w(ixo^s,e_)+qdt*axb(ixo^s,idir)*block%J0(ixo^s,idir)
6067 enddo
6068 endif
6069 end if
6070
6071
6072 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
6073
6074 end subroutine add_source_b0split
6075
6076 !> Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176
6077 subroutine add_source_semirelativistic(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6079 use mod_geometry
6080
6081 integer, intent(in) :: ixi^l, ixo^l
6082 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6083 double precision, intent(inout) :: w(ixi^s,1:nw)
6084 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
6085
6086 double precision :: e(ixi^s,1:3),curle(ixi^s,1:3),dive(ixi^s)
6087 integer :: idir, idirmin, ix^d
6088
6089 ! if ndir<3 the source is zero
6090 {^ifthreec
6091 {do ix^db=iximin^db,iximax^db\}
6092 ! E=Bxv
6093 e(ix^d,1)=w(ix^d,b2_)*wctprim(ix^d,m3_)-w(ix^d,b3_)*wctprim(ix^d,m2_)
6094 e(ix^d,2)=w(ix^d,b3_)*wctprim(ix^d,m1_)-w(ix^d,b1_)*wctprim(ix^d,m3_)
6095 e(ix^d,3)=w(ix^d,b1_)*wctprim(ix^d,m2_)-w(ix^d,b2_)*wctprim(ix^d,m1_)
6096 {end do\}
6097 call divvector(e,ixi^l,ixo^l,dive)
6098 ! curl E
6099 call curlvector(e,ixi^l,ixo^l,curle,idirmin,1,3)
6100 ! add source term in momentum equations (1/c0^2-1/c^2)(E divE - E x curlE)
6101 ! equation (26) and (27)
6102 {do ix^db=ixomin^db,ixomax^db\}
6103 w(ix^d,m1_)=w(ix^d,m1_)+qdt*(inv_squared_c0-inv_squared_c)*&
6104 (e(ix^d,1)*dive(ix^d)-e(ix^d,2)*curle(ix^d,3)+e(ix^d,3)*curle(ix^d,2))
6105 w(ix^d,m2_)=w(ix^d,m2_)+qdt*(inv_squared_c0-inv_squared_c)*&
6106 (e(ix^d,2)*dive(ix^d)-e(ix^d,3)*curle(ix^d,1)+e(ix^d,1)*curle(ix^d,3))
6107 w(ix^d,m3_)=w(ix^d,m3_)+qdt*(inv_squared_c0-inv_squared_c)*&
6108 (e(ix^d,3)*dive(ix^d)-e(ix^d,1)*curle(ix^d,2)+e(ix^d,2)*curle(ix^d,1) )
6109 {end do\}
6110 }
6111
6112 end subroutine add_source_semirelativistic
6113
6114 !> Source terms for internal energy version of MHD
6115 subroutine add_source_internal_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6117 use mod_geometry
6118
6119 integer, intent(in) :: ixi^l, ixo^l
6120 double precision, intent(in) :: qdt
6121 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6122 double precision, intent(inout) :: w(ixi^s,1:nw)
6123 double precision, intent(in) :: wctprim(ixi^s,1:nw)
6124
6125 double precision :: divv(ixi^s), tmp
6126 integer :: ix^d
6127
6128 if(slab_uniform) then
6129 if(nghostcells .gt. 2) then
6130 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,3)
6131 else
6132 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,2)
6133 end if
6134 else
6135 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv)
6136 end if
6137 {do ix^db=ixomin^db,ixomax^db\}
6138 tmp=w(ix^d,e_)
6139 w(ix^d,e_)=w(ix^d,e_)-qdt*wctprim(ix^d,p_)*divv(ix^d)
6140 if(w(ix^d,e_)<small_e) then
6141 w(ix^d,e_)=tmp
6142 end if
6143 {end do\}
6144 if(mhd_ambipolar_sts)then
6145 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
6146 end if
6147
6148 if(fix_small_values) then
6149 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'add_source_internal_e')
6150 end if
6151 end subroutine add_source_internal_e
6152
6153 !> Source terms for hydrodynamic energy version of MHD
6154 subroutine add_source_hydrodynamic_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
6156 use mod_geometry
6157 use mod_usr_methods, only: usr_gravity
6158
6159 integer, intent(in) :: ixi^l, ixo^l
6160 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6161 double precision, intent(inout) :: w(ixi^s,1:nw)
6162 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
6163
6164 double precision :: b(ixi^s,3), j(ixi^s,3), jxb(ixi^s,3)
6165 double precision :: current(ixi^s,7-2*ndir:3)
6166 double precision :: bu(ixo^s,1:ndir), tmp(ixo^s), b2(ixo^s)
6167 double precision :: gravity_field(ixi^s,1:ndir), vaoc
6168 integer :: idir, idirmin, idims, ix^d
6169
6170 {^nothreed
6171 b=0.0d0
6172 do idir = 1, ndir
6173 b(ixo^s, idir) = wct(ixo^s,mag(idir))
6174 end do
6175
6176 if(slab_uniform)then
6177 ! get current in fourth order accuracy in Cartesian
6178 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
6179 else
6180 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6181 endif
6182
6183 j=0.0d0
6184 do idir=7-2*ndir,3
6185 j(ixo^s,idir)=current(ixo^s,idir)
6186 end do
6187
6188 ! get Lorentz force JxB
6189 call cross_product(ixi^l,ixo^l,j,b,jxb)
6190 }
6191 {^ifthreed
6192 if(slab_uniform)then
6193 ! get current in fourth order accuracy in Cartesian
6194 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,1,ndir,.true.)
6195 else
6196 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6197 endif
6198 ! get Lorentz force JxB
6199 call cross_product(ixi^l,ixo^l,current,wct(ixi^s,mag(1:ndir)),jxb)
6200 }
6201
6202 ! mhd_semirelativistic does not combine with mhd_hydrodynamic_e
6203 !!if(mhd_semirelativistic) then
6204 !! ! (v . nabla) v
6205 !! do idir=1,ndir
6206 !! do idims=1,ndim
6207 !! call gradient(wCTprim(ixI^S,mom(idir)),ixI^L,ixO^L,idims,J(ixI^S,idims))
6208 !! end do
6209 !! B(ixO^S,idir)=sum(wCTprim(ixO^S,mom(1:ndir))*J(ixO^S,1:ndir),dim=ndim+1)
6210 !! end do
6211 !! ! nabla p
6212 !! do idir=1,ndir
6213 !! call gradient(wCTprim(ixI^S,p_),ixI^L,ixO^L,idir,J(ixI^S,idir))
6214 !! end do
6215 !! if(mhd_gravity) then
6216 !! gravity_field=0.d0
6217 !! call usr_gravity(ixI^L,ixO^L,wCT,x,gravity_field(ixI^S,1:ndim))
6218 !! do idir=1,ndir
6219 !! 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)
6220 !! end do
6221 !! else
6222 !! do idir=1,ndir
6223 !! B(ixO^S,idir)=wCT(ixO^S,rho_)*B(ixO^S,idir)+J(ixO^S,idir)-JxB(ixO^S,idir)
6224 !! end do
6225 !! end if
6226 !! b2(ixO^S)=sum(wCT(ixO^S,mag(:))**2,dim=ndim+1)
6227 !! tmp(ixO^S)=sqrt(b2(ixO^S))
6228 !! where(tmp(ixO^S)>smalldouble)
6229 !! tmp(ixO^S)=1.d0/tmp(ixO^S)
6230 !! else where
6231 !! tmp(ixO^S)=0.d0
6232 !! end where
6233 !! ! unit vector of magnetic field
6234 !! do idir=1,ndir
6235 !! bu(ixO^S,idir)=wCT(ixO^S,mag(idir))*tmp(ixO^S)
6236 !! end do
6237 !! !b2(ixO^S)=b2(ixO^S)/w(ixO^S,rho_)*inv_squared_c
6238 !! !b2(ixO^S)=b2(ixO^S)/(1.d0+b2(ixO^S))
6239 !! {do ix^DB=ixOmin^DB,ixOmax^DB\}
6240 !! ! Va^2/c^2
6241 !! Vaoc=b2(ix^D)/w(ix^D,rho_)*inv_squared_c
6242 !! ! Va^2/c^2 / (1+Va^2/c^2)
6243 !! b2(ix^D)=Vaoc/(1.d0+Vaoc)
6244 !! {end do\}
6245 !! ! bu . F
6246 !! tmp(ixO^S)=sum(bu(ixO^S,1:ndir)*B(ixO^S,1:ndir),dim=ndim+1)
6247 !! ! Rempel 2017 ApJ 834, 10 equation (54)
6248 !! do idir=1,ndir
6249 !! J(ixO^S,idir)=b2(ixO^S)*(B(ixO^S,idir)-bu(ixO^S,idir)*tmp(ixO^S))
6250 !! end do
6251 !! !! Rempel 2017 ApJ 834, 10 equation (29) add SR force at momentum equation
6252 !! do idir=1,ndir
6253 !! w(ixO^S,mom(idir))=w(ixO^S,mom(idir))+qdt*J(ixO^S,idir)
6254 !! end do
6255 !! ! Rempel 2017 ApJ 834, 10 equation (30) add work of Lorentz force and SR force
6256 !! w(ixO^S,e_)=w(ixO^S,e_)+qdt*sum(wCTprim(ixO^S,mom(1:ndir))*&
6257 !! (JxB(ixO^S,1:ndir)+J(ixO^S,1:ndir)),dim=ndim+1)
6258 !!else
6259 ! add work of Lorentz force
6260 w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*jxb(ixo^s,1:ndir),dim=ndim+1)
6261 !!end if
6262
6263 if(mhd_ambipolar_sts)then
6264 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
6265 end if
6266
6267 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hydrodynamic_e')
6268
6269 end subroutine add_source_hydrodynamic_e
6270
6271 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
6272 !> each direction, non-conservative. Uses the generic Laplacian
6273 !> with fourth order central difference (on uniform cartesian) for the laplacian. Then the
6274 !> stencil is 5 (2 neighbours). NOTE: Unused subroutine!
6275 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
6277 use mod_usr_methods
6278 use mod_geometry
6279
6280 integer, intent(in) :: ixi^l, ixo^l
6281 double precision, intent(in) :: qdt
6282 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6283 double precision, intent(inout) :: w(ixi^s,1:nw)
6284
6285 integer :: ixa^l,idir,jdir,kdir,idirmin,idim
6286 double precision :: tmp(ixi^s),tmp2(ixi^s)
6287
6288 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6289 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6290 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
6291 double precision :: lapl_vec(ixi^s,1:ndir)
6292
6293 ! Calculating resistive sources involves one extra layer
6294 ! asking here for two, so Cartesian works with 4th order CD
6295 ixa^l=ixo^l^ladd2;
6296
6297 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6298 call mpistop("Error in add_source_res1: Non-conforming input limits")
6299
6300 ! Calculate current density and idirmin
6301 call get_current(wct,ixi^l,ixo^l,idirmin,current)
6302
6303 if (mhd_eta>zero)then
6304 eta(ixa^s)=mhd_eta
6305 gradeta(ixo^s,1:ndim)=zero
6306 else
6307 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
6308 do idim=1,ndim
6309 call gradient(eta,ixi^l,ixo^l,idim,tmp)
6310 gradeta(ixo^s,idim)=tmp(ixo^s)
6311 end do
6312 end if
6313
6314 if(b0field) then
6315 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
6316 else
6317 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
6318 end if
6319
6320 call laplacian_of_vector(bf,ixi^l,ixo^l,lapl_vec)
6321
6322 do idir=1,ndir
6323 ! Multiply by eta to store eta*Laplace B_idir
6324 tmp(ixo^s)=lapl_vec(ixo^s,idir)*eta(ixo^s)
6325
6326 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
6327 if (mhd_eta<zero)then
6328 do jdir=1,ndim; do kdir=idirmin,3
6329 if (lvc(idir,jdir,kdir)/=0)then
6330 if (lvc(idir,jdir,kdir)==1)then
6331 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
6332 else
6333 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
6334 end if
6335 end if
6336 end do; end do
6337 end if
6338
6339 ! Add sources related to eta*laplB-grad(eta) x J to B and e
6340 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
6341 if(total_energy) then
6342 w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
6343 end if
6344 end do ! idir
6345
6346 if(mhd_energy) then
6347 ! de/dt+=eta*J**2
6348 w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
6349 end if
6350
6351 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
6352
6353 end subroutine add_source_res1
6354
6355 !> Add resistive source to w within ixO in an explicit fashion
6356 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
6357 subroutine add_source_res_exp(qdt,ixI^L,ixO^L,wCT,w,x)
6359 use mod_usr_methods
6360 use mod_geometry
6361
6362 integer, intent(in) :: ixi^l, ixo^l
6363 double precision, intent(in) :: qdt
6364 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6365 double precision, intent(inout) :: w(ixi^s,1:nw)
6366
6367 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6368 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
6369 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
6370 integer :: ixa^l,idir,idirmin,idirmin1
6371
6372 ixa^l=ixo^l^ladd2;
6373
6374 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6375 call mpistop("Error in add_source_res_exp: Non-conforming input limits")
6376
6377 ixa^l=ixo^l^ladd1;
6378 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
6379 ! Determine exact value of idirmin while doing the loop.
6380 call get_current(wct,ixi^l,ixa^l,idirmin,current)
6381
6382 tmpvec=zero
6383 if(mhd_eta>zero)then
6384 do idir=idirmin,3
6385 tmpvec(ixa^s,idir)=current(ixa^s,idir)*mhd_eta
6386 end do
6387 else
6388 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
6389 do idir=idirmin,3
6390 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
6391 end do
6392 end if
6393
6394 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
6395 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
6396 if(stagger_grid) then
6397 if(ndim==2.and.ndir==3) then
6398 ! if 2.5D
6399 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
6400 end if
6401 else
6402 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
6403 end if
6404
6405 if(mhd_energy) then
6406 if(mhd_eta>zero)then
6407 tmp(ixo^s)=qdt*mhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
6408 else
6409 tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
6410 end if
6411 if(total_energy) then
6412 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
6413 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6414 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6415 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6416 else
6417 ! add eta*J**2 source term in the internal energy equation
6418 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6419 end if
6420 end if
6421
6422 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res_exp')
6423 end subroutine add_source_res_exp
6424
6425
6426 !> Add ambipolar source to w within ixO in an explicit fashion
6427 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
6428 subroutine add_source_ambi_exp(qdt,ixI^L,ixO^L,wCT,w,x)
6430 use mod_usr_methods
6431 use mod_geometry
6432
6433 integer, intent(in) :: ixi^l, ixo^l
6434 double precision, intent(in) :: qdt
6435 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6436 double precision, intent(inout) :: w(ixi^s,1:nw)
6437
6438 double precision :: current(ixi^s,1:3),curlj(ixi^s,1:3)
6439 double precision :: tmpvec(ixi^s,1:3),tmp(ixi^s),btot2(ixi^s)
6440 integer :: ixa^l,idir,idirmin1
6441
6442 ixa^l=ixo^l^ladd2;
6443
6444 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6445 call mpistop("Error in add_source_ambi_exp: Non-conforming input limits")
6446
6447 ixa^l=ixo^l^ladd1;
6448 ! Calculate -J_perpB = (JxB)xB
6449 call mhd_get_jxbxb(wct,x,ixi^l,ixa^l,current)
6450
6451 tmpvec=current
6452 do idir=1,3
6453 !set electric field in tmpvec : E=nuA * jxbxb, where nuA=-etaA/rho^2
6454 !tmpvec(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
6455 call multiplyambicoef(ixi^l,ixa^l,tmpvec(ixi^s,idir),wct,x)
6456 end do
6457
6458 ! dB/dt= -curl(J_perpB*etaA), thus B_i=B_i-eps_ijk d_j Jeta_k
6459 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
6460 if(stagger_grid) then
6461 if(ndim==2.and.ndir==3) then
6462 ! if 2.5D
6463 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
6464 end if
6465 else
6466 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
6467 end if
6468
6469 if(mhd_energy) then
6470 ! compute ambipolar heating term: nuA* J_perpB^2/ B^2
6471 ! avoiding nulls here
6472 btot2(ixa^s)=mhd_mag_en_all(wct,ixi^l,ixa^l)
6473 where (btot2(ixa^s)>smalldouble )
6474 tmp(ixa^s) = sum(current(ixa^s,1:3)**2,dim=ndim+1) / btot2(ixa^s)
6475 elsewhere
6476 tmp(ixa^s) = zero
6477 endwhere
6478 ! multiply with nuA where nuA=-etaA/rho^2
6479 call multiplyambicoef(ixi^l,ixa^l,tmp,wct,x)
6480 ! compensate - sign and add timestep
6481 tmp(ixo^s)=-qdt*tmp(ixo^s)
6482 if(total_energy) then
6483 ! de/dt= +div(B x E_ambi) = eta J^2 - B dot curl(eta J)
6484 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6485 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6486 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6487 else
6488 ! add eta*J**2 source term in the internal or hydrodynamic energy equation
6489 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6490 end if
6491 end if
6492
6493 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_ambi_exp')
6494 end subroutine add_source_ambi_exp
6495
6496 !> Add Hyper-resistive source to w within ixO
6497 !> Uses 9 point stencil (4 neighbours) in each direction.
6498 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
6500 use mod_geometry
6501
6502 integer, intent(in) :: ixi^l, ixo^l
6503 double precision, intent(in) :: qdt
6504 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6505 double precision, intent(inout) :: w(ixi^s,1:nw)
6506 !.. local ..
6507 double precision :: current(ixi^s,7-2*ndir:3)
6508 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
6509 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
6510
6511 ixa^l=ixo^l^ladd3;
6512 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6513 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
6514
6515 call get_current(wct,ixi^l,ixa^l,idirmin,current)
6516 tmpvec(ixa^s,1:ndir)=zero
6517 do jdir=idirmin,3
6518 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
6519 end do
6520
6521 ixa^l=ixo^l^ladd2;
6522 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6523
6524 ixa^l=ixo^l^ladd1;
6525 tmpvec(ixa^s,1:ndir)=zero
6526 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
6527 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mhd_eta_hyper
6528
6529 ixa^l=ixo^l;
6530 tmpvec2(ixa^s,1:ndir)=zero
6531 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6532
6533 do idir=1,ndir
6534 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
6535 end do
6536
6537 if(total_energy) then
6538 ! de/dt= +div(B x Ehyper)
6539 ixa^l=ixo^l^ladd1;
6540 tmpvec2(ixa^s,1:ndir)=zero
6541 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
6542 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
6543 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
6544 end do; end do; end do
6545 tmp(ixo^s)=zero
6546 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
6547 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
6548 end if
6549
6550 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
6551
6552 end subroutine add_source_hyperres
6553
6554 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
6555 ! Add divB related sources to w within ixO
6556 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
6557 ! giving the EGLM-MHD scheme or GLM-MHD scheme
6559 use mod_geometry
6560
6561 integer, intent(in) :: ixi^l, ixo^l
6562 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6563 double precision, intent(inout) :: w(ixi^s,1:nw)
6564
6565 double precision:: divb(ixi^s), gradpsi(ixi^s), ba(ixo^s,1:ndir)
6566 integer :: idir
6567
6568
6569 ! dPsi/dt = - Ch^2/Cp^2 Psi
6570 if (mhd_glm_alpha < zero) then
6571 w(ixo^s,psi_) = abs(mhd_glm_alpha)*wct(ixo^s,psi_)
6572 else
6573 ! implicit update of Psi variable
6574 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
6575 if(slab_uniform) then
6576 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
6577 else
6578 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
6579 end if
6580 end if
6581
6582 if(mhd_glm_extended) then
6583 if(b0field) then
6584 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
6585 else
6586 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))
6587 end if
6588 ! gradient of Psi
6589 if(total_energy) then
6590 do idir=1,ndim
6591 select case(typegrad)
6592 case("central")
6593 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6594 case("limited")
6595 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6596 end select
6597 ! e = e -qdt (b . grad(Psi))
6598 w(ixo^s,e_) = w(ixo^s,e_)-qdt*ba(ixo^s,idir)*gradpsi(ixo^s)
6599 end do
6600 end if
6601
6602 ! We calculate now div B
6603 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6604
6605 ! m = m - qdt b div b
6606 do idir=1,ndir
6607 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*ba(ixo^s,idir)*divb(ixo^s)
6608 end do
6609 end if
6610
6611 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
6612
6613 end subroutine add_source_glm
6614
6615 !> Add divB related sources to w within ixO corresponding to Powel
6616 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
6618
6619 integer, intent(in) :: ixi^l, ixo^l
6620 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6621 double precision, intent(inout) :: w(ixi^s,1:nw)
6622
6623 double precision :: divb(ixi^s), ba(1:ndir)
6624 integer :: idir, ix^d
6625
6626 ! calculate div B
6627 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6628
6629 if(b0field) then
6630 {do ix^db=ixomin^db,ixomax^db\}
6631 ! b = b - qdt v * div b
6632 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6633 ! m = m - qdt b div b
6634 ^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)\
6635 if (total_energy) then
6636 ! e = e - qdt (v . b) * div b
6637 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)
6638 end if
6639 {end do\}
6640 else
6641 {do ix^db=ixomin^db,ixomax^db\}
6642 ! b = b - qdt v * div b
6643 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6644 ! m = m - qdt b div b
6645 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)-qdt*wct(ix^d,b^c_)*divb(ix^d)\
6646 if (total_energy) then
6647 ! e = e - qdt (v . b) * div b
6648 w(ix^d,e_)=w(ix^d,e_)-qdt*(^c&wct(ix^d,m^c_)*wct(ix^d,b^c_)+)*divb(ix^d)
6649 end if
6650 {end do\}
6651 end if
6652
6653 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
6654
6655 end subroutine add_source_powel
6656
6657 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
6658 ! Add divB related sources to w within ixO
6659 ! corresponding to Janhunen, just the term in the induction equation.
6661
6662 integer, intent(in) :: ixi^l, ixo^l
6663 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6664 double precision, intent(inout) :: w(ixi^s,1:nw)
6665
6666 double precision :: divb(ixi^s)
6667 integer :: idir, ix^d
6668
6669 ! calculate div B
6670 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6671
6672 {do ix^db=ixomin^db,ixomax^db\}
6673 ! b = b - qdt v * div b
6674 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6675 {end do\}
6676
6677 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
6678
6679 end subroutine add_source_janhunen
6680
6681 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
6682 ! Add Linde's divB related sources to wnew within ixO
6684 use mod_geometry
6685
6686 integer, intent(in) :: ixi^l, ixo^l
6687 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6688 double precision, intent(inout) :: w(ixi^s,1:nw)
6689
6690 double precision :: divb(ixi^s),graddivb(ixi^s)
6691 integer :: idim, idir, ixp^l, i^d, iside
6692 logical, dimension(-1:1^D&) :: leveljump
6693
6694 ! Calculate div B
6695 ixp^l=ixo^l^ladd1;
6696 call get_divb(wct,ixi^l,ixp^l,divb, mhd_divb_nth)
6697
6698 ! for AMR stability, retreat one cell layer from the boarders of level jump
6699 {do i^db=-1,1\}
6700 if(i^d==0|.and.) cycle
6701 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
6702 leveljump(i^d)=.true.
6703 else
6704 leveljump(i^d)=.false.
6705 end if
6706 {end do\}
6707
6708 ixp^l=ixo^l;
6709 do idim=1,ndim
6710 select case(idim)
6711 {case(^d)
6712 do iside=1,2
6713 i^dd=kr(^dd,^d)*(2*iside-3);
6714 if (leveljump(i^dd)) then
6715 if (iside==1) then
6716 ixpmin^d=ixomin^d-i^d
6717 else
6718 ixpmax^d=ixomax^d-i^d
6719 end if
6720 end if
6721 end do
6722 \}
6723 end select
6724 end do
6725
6726 ! Add Linde's diffusive terms
6727 do idim=1,ndim
6728 ! Calculate grad_idim(divb)
6729 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
6730
6731 {do i^db=ixpmin^db,ixpmax^db\}
6732 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
6733 graddivb(i^d)=graddivb(i^d)*divbdiff/(^d&1.0d0/block%ds({i^d},^d)**2+)
6734
6735 w(i^d,mag(idim))=w(i^d,mag(idim))+graddivb(i^d)
6736
6737 if (typedivbdiff=='all' .and. total_energy) then
6738 ! e += B_idim*eta*grad_idim(divb)
6739 w(i^d,e_)=w(i^d,e_)+wct(i^d,mag(idim))*graddivb(i^d)
6740 end if
6741 {end do\}
6742 end do
6743
6744 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
6745
6746 end subroutine add_source_linde
6747
6748 !> get dimensionless div B = |divB| * volume / area / |B|
6749 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
6750
6752
6753 integer, intent(in) :: ixi^l, ixo^l
6754 double precision, intent(in) :: w(ixi^s,1:nw)
6755 double precision :: divb(ixi^s), dsurface(ixi^s)
6756
6757 double precision :: invb(ixo^s)
6758 integer :: ixa^l,idims
6759
6760 call get_divb(w,ixi^l,ixo^l,divb)
6761 invb(ixo^s)=sqrt(mhd_mag_en_all(w,ixi^l,ixo^l))
6762 where(invb(ixo^s)/=0.d0)
6763 invb(ixo^s)=1.d0/invb(ixo^s)
6764 end where
6765 if(slab_uniform) then
6766 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
6767 else
6768 ixamin^d=ixomin^d-1;
6769 ixamax^d=ixomax^d-1;
6770 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
6771 do idims=1,ndim
6772 ixa^l=ixo^l-kr(idims,^d);
6773 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
6774 end do
6775 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
6776 block%dvolume(ixo^s)/dsurface(ixo^s)
6777 end if
6778
6779 end subroutine get_normalized_divb
6780
6781 !> Calculate idirmin and the idirmin:3 components of the common current array
6782 !> make sure that dxlevel(^D) is set correctly.
6783 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
6785 use mod_geometry
6786
6787 integer, intent(in) :: ixo^l, ixi^l
6788 double precision, intent(in) :: w(ixi^s,1:nw)
6789 integer, intent(out) :: idirmin
6790
6791 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6792 double precision :: current(ixi^s,7-2*ndir:3)
6793 integer :: idir, idirmin0
6794
6795 idirmin0 = 7-2*ndir
6796
6797 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
6798
6799 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
6800 block%J0(ixo^s,idirmin0:3)
6801 end subroutine get_current
6802
6803 !> If resistivity is not zero, check diffusion time limit for dt and similar other effects
6804 subroutine mhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
6806 use mod_usr_methods
6808 use mod_gravity, only: gravity_get_dt
6809 use mod_cak_force, only: cak_get_dt
6810 use mod_fld, only: fld_radforce_get_dt
6811
6812 integer, intent(in) :: ixi^l, ixo^l
6813 double precision, intent(inout) :: dtnew
6814 double precision, intent(in) :: dx^d
6815 double precision, intent(in) :: wprim(ixi^s,1:nw)
6816 double precision, intent(in) :: x(ixi^s,1:ndim)
6817
6818 double precision :: dxarr(ndim)
6819 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6820 integer :: idirmin,idim
6821
6822 dtnew = bigdouble
6823
6824 ^d&dxarr(^d)=dx^d;
6825 if (mhd_eta>zero)then
6826 if(slab_uniform) then
6827 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mhd_eta
6828 else
6829 dtnew=dtdiffpar*minval(block%ds(ixo^s,1:ndim))**2/mhd_eta
6830 end if
6831 else if (mhd_eta<zero)then
6832 call get_current(wprim,ixi^l,ixo^l,idirmin,current)
6833 call usr_special_resistivity(wprim,ixi^l,ixo^l,idirmin,x,current,eta)
6834 dtnew=bigdouble
6835 do idim=1,ndim
6836 if(slab_uniform) then
6837 dtnew=min(dtnew,&
6838 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
6839 else
6840 dtnew=min(dtnew,&
6841 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
6842 end if
6843 end do
6844 end if
6845
6846 if(mhd_eta_hyper>zero) then
6847 if(slab_uniform) then
6848 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mhd_eta_hyper,dtnew)
6849 else
6850 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mhd_eta_hyper,dtnew)
6851 end if
6852 end if
6853
6854 if(mhd_viscosity) then
6855 call viscosity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6856 end if
6857
6858 if(mhd_gravity) then
6859 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6860 end if
6861
6862 if(mhd_ambipolar_exp) then
6863 dtnew=min(dtdiffpar*get_ambipolar_dt(wprim,ixi^l,ixo^l,dx^d,x),dtnew)
6864 endif
6865
6866 if (mhd_cak_force) then
6867 call cak_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6868 end if
6869
6870 if(mhd_radiation_fld) then
6871 call fld_radforce_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6872 endif
6873
6874 end subroutine mhd_get_dt
6875
6876 ! Add geometrical source terms to w
6877 ! Geometric sources to momentum and induction
6878 ! for the regular case, not semi-relativistic, nor any splitting active
6879 ! but possibly no energy equation at all
6880 ! NOTE: Hall terms in induction not handled yet
6881 subroutine mhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6883 use mod_geometry
6886
6887 integer, intent(in) :: ixi^l, ixo^l
6888 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6889 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6890
6891 double precision :: adiabs(ixi^s), gammas(ixi^s)
6892 double precision :: tmp,tmp1,invr,cot
6893 integer :: ix^d
6894 integer :: mr_,mphi_ ! Polar var. names
6895 integer :: br_,bphi_
6896
6897 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6898 br_=mag(1); bphi_=mag(1)-1+phi_
6899
6900 if(.not.mhd_energy) then
6901 if(associated(usr_set_adiab)) then
6902 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6903 else
6904 adiabs=mhd_adiab
6905 end if
6906 if(associated(usr_set_gamma)) then
6907 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6908 else
6909 gammas=mhd_gamma
6910 end if
6911 end if
6912
6913 select case (coordinate)
6914 case (cylindrical)
6915 {do ix^db=ixomin^db,ixomax^db\}
6916 ! include dt in invr, invr is always used with qdt
6917 if(local_timestep) then
6918 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6919 else
6920 invr=qdt/x(ix^d,1)
6921 end if
6922 if(mhd_energy) then
6923 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6924 else
6925 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6926 end if
6927 if(phi_>0) then
6928 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6929 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6930 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6931 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6932 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6933 if(.not.stagger_grid) then
6934 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6935 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6936 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6937 end if
6938 else
6939 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6940 end if
6941 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6942 {end do\}
6943 case (spherical)
6944 {do ix^db=ixomin^db,ixomax^db\}
6945 ! include dt in invr, invr is always used with qdt
6946 if(local_timestep) then
6947 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6948 else
6949 invr=qdt/x(ix^d,1)
6950 end if
6951 if(mhd_energy) then
6952 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6953 else
6954 tmp1=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6955 end if
6956 ! m1
6957 {^ifonec
6958 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6959 }
6960 {^noonec
6961 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6962 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6963 }
6964 ! b1
6965 if(mhd_glm) then
6966 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6967 end if
6968 {^ifoned
6969 cot=0.d0
6970 }
6971 {^nooned
6972 cot=1.d0/tan(x(ix^d,2))
6973 }
6974 {^iftwoc
6975 ! m2
6976 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6977 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6978 ! b2
6979 if(.not.stagger_grid) then
6980 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6981 if(mhd_glm) then
6982 tmp=tmp+wprim(ix^d,psi_)*cot
6983 end if
6984 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6985 end if
6986 }
6987 {^ifthreec
6988 ! m2
6989 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6990 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
6991 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
6992 ! b2
6993 if(.not.stagger_grid) then
6994 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6995 if(mhd_glm) then
6996 tmp=tmp+wprim(ix^d,psi_)*cot
6997 end if
6998 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6999 end if
7000 ! m3
7001 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7002 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7003 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7004 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7005 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
7006 ! b3
7007 if(.not.stagger_grid) then
7008 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7009 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7010 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7011 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7012 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7013 end if
7014 }
7015 {end do\}
7016 end select
7017
7018 if (mhd_rotating_frame) then
7019 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7020 end if
7021
7022 end subroutine mhd_add_source_geom
7023
7024 ! Add geometrical source terms to w
7025 ! Geometric sources to momentum and induction
7026 ! for the semi-relativistic, hence no splitting active
7027 ! but possibly no energy equation at all
7028 ! NOTE: Hall terms in induction not handled yet
7029 subroutine mhd_add_source_geom_semirelati(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
7031 use mod_geometry
7034
7035 integer, intent(in) :: ixi^l, ixo^l
7036 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
7037 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
7038
7039 double precision :: adiabs(ixi^s), gammas(ixi^s)
7040 double precision :: tmp,tmp1,tmp2,invr,cot,ef(ixo^s,1:ndir)
7041 integer :: ix^d
7042 integer :: mr_,mphi_ ! Polar var. names
7043 integer :: br_,bphi_
7044
7045 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
7046 br_=mag(1); bphi_=mag(1)-1+phi_
7047
7048 if(.not.mhd_energy) then
7049 if(associated(usr_set_adiab)) then
7050 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
7051 else
7052 adiabs=mhd_adiab
7053 end if
7054 if(associated(usr_set_gamma)) then
7055 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
7056 else
7057 gammas=mhd_gamma
7058 end if
7059 end if
7060
7061 select case (coordinate)
7062 case (cylindrical)
7063 {do ix^db=ixomin^db,ixomax^db\}
7064 ! include dt in invr, invr is always used with qdt
7065 if(local_timestep) then
7066 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7067 else
7068 invr=qdt/x(ix^d,1)
7069 end if
7070 if(mhd_energy) then
7071 tmp=wprim(ix^d,p_)
7072 else
7073 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)
7074 end if
7075 ! E=Bxv
7076 {^ifthreec
7077 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
7078 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
7079 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7080 }
7081 {^iftwoc
7082 ef(ix^d,1)=zero
7083 ! store e3 in e2 to count e3 when ^C is from 1 to 2
7084 ef(ix^d,2)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7085 }
7086 {^ifonec
7087 ef(ix^d,1)=zero
7088 }
7089 if(phi_>0) then
7090 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+&
7091 half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c) -&
7092 wprim(ix^d,bphi_)**2+wprim(ix^d,rho_)*wprim(ix^d,mphi_)**2)
7093 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
7094 -wprim(ix^d,rho_)*wprim(ix^d,mphi_)*wprim(ix^d,mr_) &
7095 +wprim(ix^d,bphi_)*wprim(ix^d,br_)+ef(ix^d,phi_)*ef(ix^d,1)*inv_squared_c)
7096 if(.not.stagger_grid) then
7097 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7098 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
7099 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
7100 end if
7101 else
7102 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+half*((^c&wprim(ix^d,b^c_)**2+)+&
7103 (^c&ef(ix^d,^c)**2+)*inv_squared_c))
7104 end if
7105 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
7106 {end do\}
7107 case (spherical)
7108 {do ix^db=ixomin^db,ixomax^db\}
7109 ! include dt in invr, invr is always used with qdt
7110 if(local_timestep) then
7111 invr=block%dt(ix^d)*dtfactor/x(ix^d,1)
7112 else
7113 invr=qdt/x(ix^d,1)
7114 end if
7115 ! E=Bxv
7116 {^ifthreec
7117 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
7118 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
7119 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7120 }
7121 {^iftwoc
7122 ! store e3 in e1 to count e3 when ^C is from 1 to 2
7123 ef(ix^d,1)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
7124 ef(ix^d,2)=zero
7125 }
7126 {^ifonec
7127 ef(ix^d,1)=zero
7128 }
7129 if(mhd_energy) then
7130 tmp1=wprim(ix^d,p_)+half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c)
7131 else
7132 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)
7133 end if
7134 ! m1
7135 {^ifonec
7136 w(ix^d,m1_)=w(ix^d,m1_)+two*tmp1*invr
7137 }
7138 {^noonec
7139 w(ix^d,m1_)=w(ix^d,m1_)+invr*&
7140 (two*tmp1+(^ce&wprim(ix^d,rho_)*wprim(ix^d,m^ce_)**2-&
7141 wprim(ix^d,b^ce_)**2-ef(ix^d,^ce)**2*inv_squared_c+))
7142 }
7143 ! b1
7144 if(mhd_glm) then
7145 w(ix^d,b1_)=w(ix^d,b1_)+invr*2.0d0*wprim(ix^d,psi_)
7146 end if
7147 {^ifoned
7148 cot=0.d0
7149 }
7150 {^nooned
7151 cot=1.d0/tan(x(ix^d,2))
7152 }
7153 {^iftwoc
7154 ! m2
7155 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_)&
7156 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c)
7157 ! b2
7158 if(.not.stagger_grid) then
7159 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7160 if(mhd_glm) then
7161 tmp=tmp+wprim(ix^d,psi_)*cot
7162 end if
7163 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
7164 end if
7165 }
7166
7167 {^ifthreec
7168 ! m2
7169 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_) &
7170 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c&
7171 +(wprim(ix^d,rho_)*wprim(ix^d,m3_)**2&
7172 -wprim(ix^d,b3_)**2-ef(ix^d,3)**2*inv_squared_c)*cot)
7173 ! b2
7174 if(.not.stagger_grid) then
7175 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7176 if(mhd_glm) then
7177 tmp=tmp+wprim(ix^d,psi_)*cot
7178 end if
7179 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
7180 end if
7181 ! m3
7182 w(ix^d,m3_)=w(ix^d,m3_)+invr*&
7183 (-wprim(ix^d,m3_)*wprim(ix^d,m1_)*wprim(ix^d,rho_) &
7184 +wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7185 +ef(ix^d,3)*ef(ix^d,1)*inv_squared_c&
7186 +(-wprim(ix^d,m2_)*wprim(ix^d,m3_)*wprim(ix^d,rho_) &
7187 +wprim(ix^d,b2_)*wprim(ix^d,b3_)&
7188 +ef(ix^d,2)*ef(ix^d,3)*inv_squared_c)*cot)
7189 ! b3
7190 if(.not.stagger_grid) then
7191 w(ix^d,b3_)=w(ix^d,b3_)+invr*&
7192 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7193 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7194 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7195 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7196 end if
7197 }
7198 {end do\}
7199 end select
7200
7201 if (mhd_rotating_frame) then
7202 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7203 end if
7204
7205 end subroutine mhd_add_source_geom_semirelati
7206
7207 ! Add geometrical source terms to w
7208 ! Geometric sources to momentum and induction
7209 ! for those cases where any kind of splitting (B0field or has_equi_rho_and_p) is active
7210 ! This implies that there is an energy equation included for sure
7211 ! B0field impacts terms in induction equation and geometric sources for them
7212 ! both flags affect the terms in momentum equation, in three variants (TF, TT, FT)
7213 ! NOTE: Hall terms in induction not handled yet
7214 subroutine mhd_add_source_geom_split(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
7216 use mod_geometry
7218
7219 integer, intent(in) :: ixi^l, ixo^l
7220 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
7221 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
7222
7223 double precision :: tmp,tmp1,tmp2,invr,cot
7224 integer :: ix^d
7225 integer :: mr_,mphi_ ! Polar var. names
7226 integer :: br_,bphi_
7227
7228 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
7229 br_=mag(1); bphi_=mag(1)-1+phi_
7230
7231
7232 select case (coordinate)
7233 case (cylindrical)
7234 {do ix^db=ixomin^db,ixomax^db\}
7235 ! include dt in invr, invr is always used with qdt
7236 if(local_timestep) then
7237 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7238 else
7239 invr=qdt/x(ix^d,1)
7240 end if
7241 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
7242 if(b0field) tmp=tmp+(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
7243 if(phi_>0) then
7244 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
7245 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
7246 if(b0field) then
7247 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))
7248 endif
7249 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
7250 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
7251 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
7252 if(b0field) then
7253 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))
7254 endif
7255 if(.not.stagger_grid) then
7256 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7257 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
7258 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
7259 if(b0field) then
7260 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
7261 (block%B0(ix^d,phi_,0)*wprim(ix^d,mr_) &
7262 -block%B0(ix^d,r_,0)*wprim(ix^d,mphi_))
7263 endif
7264 end if
7265 else
7266 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
7267 end if
7268 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
7269 {end do\}
7270 case (spherical)
7271 {do ix^db=ixomin^db,ixomax^db\}
7272 ! include dt in invr, invr is always used with qdt
7273 if(local_timestep) then
7274 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
7275 else
7276 invr=qdt/x(ix^d,1)
7277 end if
7278 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
7279 if(b0field) tmp2=(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
7280 ! m1
7281 {^ifonec
7282 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
7283 if(b0field) w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp2*invr
7284 }
7285 {^noonec
7286 if(b0field) then
7287 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
7288 (two*(tmp1+tmp2)+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+)- &
7289 (^ce&two*block%B0(ix^d,^ce,0)*wprim(ix^d,b^ce_)+))
7290 else
7291 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
7292 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
7293 end if
7294 }
7295 ! b1
7296 if(mhd_glm) then
7297 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
7298 end if
7299 {^ifoned
7300 cot=0.d0
7301 }
7302 {^nooned
7303 cot=1.d0/tan(x(ix^d,2))
7304 }
7305 {^iftwoc
7306 ! m2
7307 if(b0field) then
7308 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7309 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
7310 +wprim(ix^d,b1_)*block%B0(ix^d,2,0))
7311 else
7312 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7313 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
7314 end if
7315 ! b2
7316 if(.not.stagger_grid) then
7317 if(b0field) then
7318 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
7319 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
7320 else
7321 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7322 end if
7323 if(mhd_glm) then
7324 tmp=tmp+wprim(ix^d,psi_)*cot
7325 end if
7326 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
7327 end if
7328 }
7329 {^ifthreec
7330 ! m2
7331 if(b0field) then
7332 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7333 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
7334 +wprim(ix^d,b1_)*block%B0(ix^d,2,0)&
7335 +(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)
7336 else
7337 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
7338 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
7339 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
7340 end if
7341 ! b2
7342 if(.not.stagger_grid) then
7343 if(b0field) then
7344 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
7345 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
7346 else
7347 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
7348 end if
7349 if(mhd_glm) then
7350 tmp=tmp+wprim(ix^d,psi_)*cot
7351 end if
7352 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
7353 end if
7354 ! m3
7355 if(b0field) then
7356 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7357 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7358 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7359 +block%B0(ix^d,1,0)*wprim(ix^d,b3_) &
7360 +wprim(ix^d,b1_)*block%B0(ix^d,3,0) &
7361 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7362 -wprim(ix^d,b2_)*wprim(ix^d,b3_) &
7363 +block%B0(ix^d,2,0)*wprim(ix^d,b3_) &
7364 +wprim(ix^d,b2_)*block%B0(ix^d,3,0))*cot)
7365 else
7366 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
7367 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
7368 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
7369 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
7370 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
7371 end if
7372 ! b3
7373 if(.not.stagger_grid) then
7374 if(b0field) then
7375 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7376 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7377 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7378 +wprim(ix^d,m1_)*block%B0(ix^d,3,0) &
7379 -wprim(ix^d,m3_)*block%B0(ix^d,1,0) &
7380 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7381 -wprim(ix^d,m2_)*wprim(ix^d,b3_) &
7382 +wprim(ix^d,m3_)*block%B0(ix^d,2,0) &
7383 -wprim(ix^d,m2_)*block%B0(ix^d,3,0))*cot)
7384 else
7385 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
7386 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
7387 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
7388 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
7389 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
7390 end if
7391 end if
7392 }
7393 {end do\}
7394 end select
7395
7396 if (mhd_rotating_frame) then
7397 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
7398 end if
7399
7400 end subroutine mhd_add_source_geom_split
7401
7402 !> Compute 2 times total magnetic energy
7403 function mhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
7405 integer, intent(in) :: ixi^l, ixo^l
7406 double precision, intent(in) :: w(ixi^s, nw)
7407 double precision :: mge(ixo^s)
7408
7409 if (b0field) then
7410 mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
7411 else
7412 mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
7413 end if
7414 end function mhd_mag_en_all
7415
7416 subroutine mhd_getv_hall(w,x,ixI^L,ixO^L,vHall,partial)
7418 use mod_geometry
7419
7420 integer, intent(in) :: ixi^l, ixo^l
7421 double precision, intent(in) :: w(ixi^s,nw)
7422 double precision, intent(in) :: x(ixi^s,1:ndim)
7423 double precision, intent(inout) :: vhall(ixi^s,1:ndir)
7424 logical, intent(in), optional :: partial
7425
7426 double precision :: current(ixi^s,7-2*ndir:3)
7427 double precision :: rho(ixi^s)
7428 integer :: idir, idirmin, ix^d
7429 logical :: use_partial
7430
7431 use_partial=.false.
7432 if(present(partial)) use_partial=partial
7433 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
7434 if(.not.use_partial)then
7435 ! Calculate current density and idirmin, including J0 when split
7436 call get_current(w,ixi^l,ixo^l,idirmin,current)
7437 else
7438 if(slab_uniform) then
7439 ! fourth order CD in cartesian
7440 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
7441 else
7442 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir)
7443 endif
7444 endif
7445 do idir = idirmin, ndir
7446 {do ix^db=ixomin^db,ixomax^db\}
7447 vhall(ix^d,idir)=-mhd_etah*current(ix^d,idir)/rho(ix^d)
7448 {end do\}
7449 end do
7450
7451 end subroutine mhd_getv_hall
7452
7453 subroutine mhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
7455 use mod_usr_methods
7456 integer, intent(in) :: ixi^l, ixo^l, idir
7457 double precision, intent(in) :: qt
7458 double precision, intent(inout) :: wlc(ixi^s,1:nw), wrc(ixi^s,1:nw)
7459 double precision, intent(inout) :: wlp(ixi^s,1:nw), wrp(ixi^s,1:nw)
7460 type(state) :: s
7461
7462 double precision :: db(ixo^s), dpsi(ixo^s)
7463 integer :: ix^d
7464
7465 if(stagger_grid) then
7466 {do ix^db=ixomin^db,ixomax^db\}
7467 wlc(ix^d,mag(idir))=s%ws(ix^d,idir)
7468 wrc(ix^d,mag(idir))=s%ws(ix^d,idir)
7469 wlp(ix^d,mag(idir))=s%ws(ix^d,idir)
7470 wrp(ix^d,mag(idir))=s%ws(ix^d,idir)
7471 {end do\}
7472 else
7473 ! Solve the Riemann problem for the linear 2x2 system for normal
7474 ! B-field and GLM_Psi according to Dedner 2002:
7475 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
7476 ! Gives the Riemann solution on the interface
7477 ! for the normal B component and Psi in the GLM-MHD system.
7478 ! 23/04/2013 Oliver Porth
7479 {do ix^db=ixomin^db,ixomax^db\}
7480 db(ix^d)=wrp(ix^d,mag(idir))-wlp(ix^d,mag(idir))
7481 dpsi(ix^d)=wrp(ix^d,psi_)-wlp(ix^d,psi_)
7482 wlp(ix^d,mag(idir))=half*(wrp(ix^d,mag(idir))+wlp(ix^d,mag(idir))-dpsi(ix^d)/cmax_global)
7483 wlp(ix^d,psi_)=half*(wrp(ix^d,psi_)+wlp(ix^d,psi_)-db(ix^d)*cmax_global)
7484 wrp(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7485 wrp(ix^d,psi_)=wlp(ix^d,psi_)
7486 if(total_energy) then
7487 wrc(ix^d,e_)=wrc(ix^d,e_)-half*wrc(ix^d,mag(idir))**2
7488 wlc(ix^d,e_)=wlc(ix^d,e_)-half*wlc(ix^d,mag(idir))**2
7489 end if
7490 wrc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7491 wrc(ix^d,psi_)=wlp(ix^d,psi_)
7492 wlc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7493 wlc(ix^d,psi_)=wlp(ix^d,psi_)
7494 ! modify total energy according to the change of magnetic field
7495 if(total_energy) then
7496 wrc(ix^d,e_)=wrc(ix^d,e_)+half*wrc(ix^d,mag(idir))**2
7497 wlc(ix^d,e_)=wlc(ix^d,e_)+half*wlc(ix^d,mag(idir))**2
7498 end if
7499 {end do\}
7500 end if
7501
7502 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
7503
7504 end subroutine mhd_modify_wlr
7505
7506 subroutine mhd_boundary_adjust(igrid,psb)
7508 integer, intent(in) :: igrid
7509 type(state), target :: psb(max_blocks)
7510
7511 integer :: ib, idims, iside, ixo^l, i^d
7512
7513 block=>ps(igrid)
7514 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7515 do idims=1,ndim
7516 ! to avoid using as yet unknown corner info in more than 1D, we
7517 ! fill only interior mesh ranges of the ghost cell ranges at first,
7518 ! and progressively enlarge the ranges to include corners later
7519 do iside=1,2
7520 i^d=kr(^d,idims)*(2*iside-3);
7521 if (neighbor_type(i^d,igrid)/=1) cycle
7522 ib=(idims-1)*2+iside
7523 if(.not.boundary_divbfix(ib)) cycle
7524 if(any(typeboundary(:,ib)==bc_special)) then
7525 ! MF nonlinear force-free B field extrapolation and data driven
7526 ! require normal B of the first ghost cell layer to be untouched by
7527 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
7528 select case (idims)
7529 {case (^d)
7530 if (iside==2) then
7531 ! maximal boundary
7532 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
7533 ixomax^dd=ixghi^dd;
7534 else
7535 ! minimal boundary
7536 ixomin^dd=ixglo^dd;
7537 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
7538 end if \}
7539 end select
7540 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
7541 end if
7542 end do
7543 end do
7544
7545 end subroutine mhd_boundary_adjust
7546
7547 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
7549
7550 integer, intent(in) :: ixg^l,ixo^l,ib
7551 double precision, intent(inout) :: w(ixg^s,1:nw)
7552 double precision, intent(in) :: x(ixg^s,1:ndim)
7553
7554 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
7555 integer :: ix^d,ixf^l
7556
7557 select case(ib)
7558 case(1)
7559 ! 2nd order CD for divB=0 to set normal B component better
7560 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7561 {^iftwod
7562 ixfmin1=ixomin1+1
7563 ixfmax1=ixomax1+1
7564 ixfmin2=ixomin2+1
7565 ixfmax2=ixomax2-1
7566 if(slab_uniform) then
7567 dx1x2=dxlevel(1)/dxlevel(2)
7568 do ix1=ixfmax1,ixfmin1,-1
7569 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
7570 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7571 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7572 enddo
7573 else
7574 do ix1=ixfmax1,ixfmin1,-1
7575 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
7576 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
7577 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7578 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7579 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7580 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7581 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7582 end do
7583 end if
7584 }
7585 {^ifthreed
7586 ixfmin1=ixomin1+1
7587 ixfmax1=ixomax1+1
7588 ixfmin2=ixomin2+1
7589 ixfmax2=ixomax2-1
7590 ixfmin3=ixomin3+1
7591 ixfmax3=ixomax3-1
7592 if(slab_uniform) then
7593 dx1x2=dxlevel(1)/dxlevel(2)
7594 dx1x3=dxlevel(1)/dxlevel(3)
7595 do ix1=ixfmax1,ixfmin1,-1
7596 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7597 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7598 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7599 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7600 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7601 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7602 end do
7603 else
7604 do ix1=ixfmax1,ixfmin1,-1
7605 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7606 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7607 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7608 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7609 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7610 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7611 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7612 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7613 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7614 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7615 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7616 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7617 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7618 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7619 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7620 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7621 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7622 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7623 end do
7624 end if
7625 }
7626 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7627 case(2)
7628 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7629 {^iftwod
7630 ixfmin1=ixomin1-1
7631 ixfmax1=ixomax1-1
7632 ixfmin2=ixomin2+1
7633 ixfmax2=ixomax2-1
7634 if(slab_uniform) then
7635 dx1x2=dxlevel(1)/dxlevel(2)
7636 do ix1=ixfmin1,ixfmax1
7637 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
7638 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7639 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7640 enddo
7641 else
7642 do ix1=ixfmin1,ixfmax1
7643 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
7644 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
7645 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7646 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7647 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7648 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7649 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7650 end do
7651 end if
7652 }
7653 {^ifthreed
7654 ixfmin1=ixomin1-1
7655 ixfmax1=ixomax1-1
7656 ixfmin2=ixomin2+1
7657 ixfmax2=ixomax2-1
7658 ixfmin3=ixomin3+1
7659 ixfmax3=ixomax3-1
7660 if(slab_uniform) then
7661 dx1x2=dxlevel(1)/dxlevel(2)
7662 dx1x3=dxlevel(1)/dxlevel(3)
7663 do ix1=ixfmin1,ixfmax1
7664 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7665 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7666 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7667 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7668 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7669 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7670 end do
7671 else
7672 do ix1=ixfmin1,ixfmax1
7673 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7674 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7675 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7676 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7677 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7678 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7679 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7680 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7681 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7682 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7683 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7684 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7685 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7686 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7687 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7688 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7689 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7690 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7691 end do
7692 end if
7693 }
7694 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7695 case(3)
7696 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7697 {^iftwod
7698 ixfmin1=ixomin1+1
7699 ixfmax1=ixomax1-1
7700 ixfmin2=ixomin2+1
7701 ixfmax2=ixomax2+1
7702 if(slab_uniform) then
7703 dx2x1=dxlevel(2)/dxlevel(1)
7704 do ix2=ixfmax2,ixfmin2,-1
7705 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
7706 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7707 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7708 enddo
7709 else
7710 do ix2=ixfmax2,ixfmin2,-1
7711 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
7712 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
7713 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7714 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7715 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7716 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7717 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7718 end do
7719 end if
7720 }
7721 {^ifthreed
7722 ixfmin1=ixomin1+1
7723 ixfmax1=ixomax1-1
7724 ixfmin3=ixomin3+1
7725 ixfmax3=ixomax3-1
7726 ixfmin2=ixomin2+1
7727 ixfmax2=ixomax2+1
7728 if(slab_uniform) then
7729 dx2x1=dxlevel(2)/dxlevel(1)
7730 dx2x3=dxlevel(2)/dxlevel(3)
7731 do ix2=ixfmax2,ixfmin2,-1
7732 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7733 ix2+1,ixfmin3:ixfmax3,mag(2)) &
7734 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7735 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7736 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7737 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7738 end do
7739 else
7740 do ix2=ixfmax2,ixfmin2,-1
7741 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
7742 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
7743 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7744 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
7745 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7746 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7747 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7748 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7749 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7750 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7751 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7752 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7753 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7754 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7755 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7756 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7757 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
7758 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7759 end do
7760 end if
7761 }
7762 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7763 case(4)
7764 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7765 {^iftwod
7766 ixfmin1=ixomin1+1
7767 ixfmax1=ixomax1-1
7768 ixfmin2=ixomin2-1
7769 ixfmax2=ixomax2-1
7770 if(slab_uniform) then
7771 dx2x1=dxlevel(2)/dxlevel(1)
7772 do ix2=ixfmin2,ixfmax2
7773 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
7774 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7775 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7776 end do
7777 else
7778 do ix2=ixfmin2,ixfmax2
7779 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
7780 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
7781 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7782 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7783 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7784 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7785 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7786 end do
7787 end if
7788 }
7789 {^ifthreed
7790 ixfmin1=ixomin1+1
7791 ixfmax1=ixomax1-1
7792 ixfmin3=ixomin3+1
7793 ixfmax3=ixomax3-1
7794 ixfmin2=ixomin2-1
7795 ixfmax2=ixomax2-1
7796 if(slab_uniform) then
7797 dx2x1=dxlevel(2)/dxlevel(1)
7798 dx2x3=dxlevel(2)/dxlevel(3)
7799 do ix2=ixfmin2,ixfmax2
7800 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7801 ix2-1,ixfmin3:ixfmax3,mag(2)) &
7802 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7803 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7804 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7805 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7806 end do
7807 else
7808 do ix2=ixfmin2,ixfmax2
7809 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
7810 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
7811 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7812 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
7813 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7814 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7815 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7816 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7817 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7818 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7819 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7820 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7821 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7822 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7823 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7824 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7825 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
7826 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7827 end do
7828 end if
7829 }
7830 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7831 {^ifthreed
7832 case(5)
7833 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7834 ixfmin1=ixomin1+1
7835 ixfmax1=ixomax1-1
7836 ixfmin2=ixomin2+1
7837 ixfmax2=ixomax2-1
7838 ixfmin3=ixomin3+1
7839 ixfmax3=ixomax3+1
7840 if(slab_uniform) then
7841 dx3x1=dxlevel(3)/dxlevel(1)
7842 dx3x2=dxlevel(3)/dxlevel(2)
7843 do ix3=ixfmax3,ixfmin3,-1
7844 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
7845 ixfmin2:ixfmax2,ix3+1,mag(3)) &
7846 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7847 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7848 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7849 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7850 end do
7851 else
7852 do ix3=ixfmax3,ixfmin3,-1
7853 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
7854 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
7855 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7856 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
7857 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7858 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7859 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7860 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7861 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7862 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7863 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7864 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7865 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7866 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7867 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7868 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7869 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
7870 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7871 end do
7872 end if
7873 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7874 case(6)
7875 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7876 ixfmin1=ixomin1+1
7877 ixfmax1=ixomax1-1
7878 ixfmin2=ixomin2+1
7879 ixfmax2=ixomax2-1
7880 ixfmin3=ixomin3-1
7881 ixfmax3=ixomax3-1
7882 if(slab_uniform) then
7883 dx3x1=dxlevel(3)/dxlevel(1)
7884 dx3x2=dxlevel(3)/dxlevel(2)
7885 do ix3=ixfmin3,ixfmax3
7886 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
7887 ixfmin2:ixfmax2,ix3-1,mag(3)) &
7888 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7889 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7890 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7891 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7892 end do
7893 else
7894 do ix3=ixfmin3,ixfmax3
7895 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
7896 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
7897 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7898 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
7899 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7900 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7901 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7902 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7903 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7904 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7905 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7906 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7907 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7908 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7909 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7910 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7911 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
7912 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7913 end do
7914 end if
7915 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7916 }
7917 case default
7918 call mpistop("Special boundary is not defined for this region")
7919 end select
7920
7921 end subroutine fixdivb_boundary
7922
7923 {^nooned
7924 subroutine mhd_clean_divb_multigrid(qdt, qt, active)
7925 use mod_forest
7928 use mod_geometry
7929
7930 double precision, intent(in) :: qdt !< Current time step
7931 double precision, intent(in) :: qt !< Current time
7932 logical, intent(inout) :: active !< Output if the source is active
7933
7934 integer :: id
7935 integer, parameter :: max_its = 50
7936 double precision :: residual_it(max_its), max_divb
7937 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
7938 double precision :: res
7939 double precision, parameter :: max_residual = 1d-3
7940 double precision, parameter :: residual_reduction = 1d-10
7941 integer :: iigrid, igrid
7942 integer :: n, nc, lvl, ix^l, ixc^l, idim
7943 type(tree_node), pointer :: pnode
7944
7945 mg%operator_type = mg_laplacian
7946
7947 ! Set boundary conditions
7948 do n = 1, 2*ndim
7949 idim = (n+1)/2
7950 select case (typeboundary(mag(idim), n))
7951 case (bc_symm)
7952 ! d/dx B = 0, take phi = 0
7953 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7954 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7955 case (bc_asymm)
7956 ! B = 0, so grad(phi) = 0
7957 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
7958 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7959 case (bc_cont)
7960 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7961 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7962 case (bc_special)
7963 ! Assume Dirichlet boundary conditions, derivative zero
7964 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7965 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7966 case (bc_periodic)
7967 ! Nothing to do here
7968 case default
7969 write(*,*) "mhd_clean_divb_multigrid warning: unknown boundary type"
7970 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7971 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7972 end select
7973 end do
7974
7975 ix^l=ixm^ll^ladd1;
7976 max_divb = 0.0d0
7977
7978 ! Store divergence of B as right-hand side
7979 do iigrid = 1, igridstail
7980 igrid = igrids(iigrid);
7981 pnode => igrid_to_node(igrid, mype)%node
7982 id = pnode%id
7983 lvl = mg%boxes(id)%lvl
7984 nc = mg%box_size_lvl(lvl)
7985
7986 ! Geometry subroutines expect this to be set
7987 block => ps(igrid)
7988 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7989
7990 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
7992 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
7993 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
7994 end do
7995
7996 ! Solve laplacian(phi) = divB
7997 if(stagger_grid) then
7998 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
7999 mpi_max, icomm, ierrmpi)
8000
8001 if (mype == 0) print *, "Performing multigrid divB cleaning"
8002 if (mype == 0) print *, "iteration vs residual"
8003 ! Solve laplacian(phi) = divB
8004 do n = 1, max_its
8005 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
8006 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
8007 if (residual_it(n) < residual_reduction * max_divb) exit
8008 end do
8009 if (mype == 0 .and. n > max_its) then
8010 print *, "divb_multigrid warning: not fully converged"
8011 print *, "current amplitude of divb: ", residual_it(max_its)
8012 print *, "multigrid smallest grid: ", &
8013 mg%domain_size_lvl(:, mg%lowest_lvl)
8014 print *, "note: smallest grid ideally has <= 8 cells"
8015 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
8016 print *, "note: dx/dy/dz should be similar"
8017 end if
8018 else
8019 do n = 1, max_its
8020 call mg_fas_vcycle(mg, max_res=res)
8021 if (res < max_residual) exit
8022 end do
8023 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
8024 end if
8025
8026
8027 ! Correct the magnetic field
8028 do iigrid = 1, igridstail
8029 igrid = igrids(iigrid);
8030 pnode => igrid_to_node(igrid, mype)%node
8031 id = pnode%id
8032
8033 ! Geometry subroutines expect this to be set
8034 block => ps(igrid)
8035 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
8036
8037 ! Compute the gradient of phi
8038 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
8039
8040 if(stagger_grid) then
8041 do idim =1, ndim
8042 ixcmin^d=ixmlo^d-kr(idim,^d);
8043 ixcmax^d=ixmhi^d;
8044 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
8045 ! Apply the correction B* = B - gradient(phi)
8046 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
8047 end do
8048 ! store cell-center magnetic energy
8049 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
8050 ! change cell-center magnetic field
8051 call mhd_face_to_center(ixm^ll,ps(igrid))
8052 else
8053 do idim = 1, ndim
8054 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
8055 end do
8056 ! store cell-center magnetic energy
8057 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
8058 ! Apply the correction B* = B - gradient(phi)
8059 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
8060 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
8061 end if
8062
8063 if(total_energy) then
8064 ! Determine magnetic energy difference
8065 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
8066 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
8067 ! Keep thermal pressure the same
8068 ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
8069 end if
8070 end do
8071
8072 active = .true.
8073
8074 end subroutine mhd_clean_divb_multigrid
8075 }
8076
8077 !> get electric field through averaging neighors to update faces in CT
8078 subroutine mhd_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8080 use mod_usr_methods
8081
8082 integer, intent(in) :: ixi^l, ixo^l
8083 double precision, intent(in) :: qt,qdt
8084 ! cell-center primitive variables
8085 double precision, intent(in) :: wp(ixi^s,1:nw)
8086 type(state) :: sct, s
8087 type(ct_velocity) :: vcts
8088 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8089 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8090
8091 double precision :: circ(ixi^s,1:ndim)
8092 ! non-ideal electric field on cell edges
8093 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8094 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
8095 integer :: idim1,idim2,idir,iwdim1,iwdim2
8096
8097 associate(bfaces=>s%ws,x=>s%x)
8098
8099 ! Calculate contribution to FEM of each edge,
8100 ! that is, estimate value of line integral of
8101 ! electric field in the positive idir direction.
8102
8103 ! if there is resistivity, get eta J
8104 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8105
8106 ! if there is ambipolar diffusion, get E_ambi
8107 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8108
8109 do idim1=1,ndim
8110 iwdim1 = mag(idim1)
8111 i1kr^d=kr(idim1,^d);
8112 do idim2=1,ndim
8113 iwdim2 = mag(idim2)
8114 i2kr^d=kr(idim2,^d);
8115 do idir=sdim,3! Direction of line integral
8116 ! Allow only even permutations
8117 if (lvc(idim1,idim2,idir)==1) then
8118 ixcmax^d=ixomax^d;
8119 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8120 ! average cell-face electric field to cell edges
8121 {do ix^db=ixcmin^db,ixcmax^db\}
8122 fe(ix^d,idir)=quarter*&
8123 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
8124 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
8125 ! add resistive electric field at cell edges E=-vxB+eta J
8126 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
8127 ! add ambipolar electric field
8128 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
8129
8130 ! times time step and edge length
8131 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
8132 {end do\}
8133 end if
8134 end do
8135 end do
8136 end do
8137
8138 ! allow user to change inductive electric field, especially for boundary driven applications
8139 if(associated(usr_set_electric_field)) &
8140 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8141
8142 circ(ixi^s,1:ndim)=zero
8143
8144 ! Calculate circulation on each face
8145 do idim1=1,ndim ! Coordinate perpendicular to face
8146 ixcmax^d=ixomax^d;
8147 ixcmin^d=ixomin^d-kr(idim1,^d);
8148 do idim2=1,ndim
8149 ixa^l=ixc^l-kr(idim2,^d);
8150 do idir=sdim,3 ! Direction of line integral
8151 ! Assemble indices
8152 if(lvc(idim1,idim2,idir)==1) then
8153 ! Add line integrals in direction idir
8154 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8155 +(fe(ixc^s,idir)&
8156 -fe(ixa^s,idir))
8157 else if(lvc(idim1,idim2,idir)==-1) then
8158 ! Add line integrals in direction idir
8159 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8160 -(fe(ixc^s,idir)&
8161 -fe(ixa^s,idir))
8162 end if
8163 end do
8164 end do
8165 {do ix^db=ixcmin^db,ixcmax^db\}
8166 ! Divide by the area of the face to get dB/dt
8167 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8168 ! Time update cell-face magnetic field component
8169 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8170 end if
8171 {end do\}
8172 end do
8173
8174 end associate
8175
8176 end subroutine mhd_update_faces_average
8177
8178 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
8179 subroutine mhd_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8181 use mod_usr_methods
8182 use mod_geometry
8183
8184 integer, intent(in) :: ixi^l, ixo^l
8185 double precision, intent(in) :: qt, qdt
8186 ! cell-center primitive variables
8187 double precision, intent(in) :: wp(ixi^s,1:nw)
8188 type(state) :: sct, s
8189 type(ct_velocity) :: vcts
8190 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8191 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8192
8193 double precision :: circ(ixi^s,1:ndim)
8194 ! electric field at cell centers
8195 double precision :: ecc(ixi^s,sdim:3)
8196 double precision :: ein(ixi^s,sdim:3)
8197 ! gradient of E at left and right side of a cell face
8198 double precision :: el(ixi^s),er(ixi^s)
8199 ! gradient of E at left and right side of a cell corner
8200 double precision :: elc,erc
8201 ! non-ideal electric field on cell edges
8202 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8203 ! current on cell edges
8204 double precision :: jce(ixi^s,sdim:3)
8205 ! location at cell faces
8206 double precision :: xs(ixgs^t,1:ndim)
8207 double precision :: gradi(ixgs^t)
8208 integer :: ixc^l,ixa^l
8209 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
8210
8211 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
8212
8213 ! if there is resistivity, get eta J
8214 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8215
8216 ! if there is ambipolar diffusion, get E_ambi
8217 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8218
8219 if(b0field) then
8220 {do ix^db=iximin^db,iximax^db\}
8221 ! Calculate electric field at cell centers
8222 {^ifthreed
8223 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_)
8224 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_)
8225 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_)
8226 }
8227 {^iftwod
8228 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8229 }
8230 {^ifoned
8231 ecc(ix^d,3)=0.d0
8232 }
8233 {end do\}
8234 else
8235 {do ix^db=iximin^db,iximax^db\}
8236 ! Calculate electric field at cell centers
8237 {^ifthreed
8238 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
8239 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
8240 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8241 }
8242 {^iftwod
8243 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
8244 }
8245 {^ifoned
8246 ecc(ix^d,3)=0.d0
8247 }
8248 {end do\}
8249 end if
8250
8251 ! Calculate contribution to FEM of each edge,
8252 ! that is, estimate value of line integral of
8253 ! electric field in the positive idir direction.
8254 ! evaluate electric field along cell edges according to equation (41)
8255 do idim1=1,ndim
8256 iwdim1 = mag(idim1)
8257 i1kr^d=kr(idim1,^d);
8258 do idim2=1,ndim
8259 iwdim2 = mag(idim2)
8260 i2kr^d=kr(idim2,^d);
8261 do idir=sdim,3 ! Direction of line integral
8262 ! Allow only even permutations
8263 if (lvc(idim1,idim2,idir)==1) then
8264 ixcmax^d=ixomax^d;
8265 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8266 ! Assemble indices
8267 ! average cell-face electric field to cell edges
8268 {do ix^db=ixcmin^db,ixcmax^db\}
8269 fe(ix^d,idir)=quarter*&
8270 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
8271 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
8272 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)
8273 {end do\}
8274 ! add slope in idim2 direction from equation (50)
8275 ixamin^d=ixcmin^d;
8276 ixamax^d=ixcmax^d+i1kr^d;
8277 {do ix^db=ixamin^db,ixamax^db\}
8278 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
8279 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
8280 {end do\}
8281 {!dir$ ivdep
8282 do ix^db=ixcmin^db,ixcmax^db\}
8283 if(vnorm(ix^d,idim1)>0.d0) then
8284 elc=el(ix^d)
8285 else if(vnorm(ix^d,idim1)<0.d0) then
8286 elc=el({ix^d+i1kr^d})
8287 else
8288 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
8289 end if
8290 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
8291 erc=er(ix^d)
8292 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
8293 erc=er({ix^d+i1kr^d})
8294 else
8295 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
8296 end if
8297 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
8298 {end do\}
8299
8300 ! add slope in idim1 direction from equation (50)
8301 ixamin^d=ixcmin^d;
8302 ixamax^d=ixcmax^d+i2kr^d;
8303 {do ix^db=ixamin^db,ixamax^db\}
8304 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
8305 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
8306 {end do\}
8307 {!dir$ ivdep
8308 do ix^db=ixcmin^db,ixcmax^db\}
8309 if(vnorm(ix^d,idim2)>0.d0) then
8310 elc=el(ix^d)
8311 else if(vnorm(ix^d,idim2)<0.d0) then
8312 elc=el({ix^d+i2kr^d})
8313 else
8314 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
8315 end if
8316 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
8317 erc=er(ix^d)
8318 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
8319 erc=er({ix^d+i2kr^d})
8320 else
8321 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
8322 end if
8323 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
8324 ! difference between average and upwind interpolated E
8325 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)-ein(ix^d,idir)
8326 ! add resistive electric field at cell edges E=-vxB+eta J
8327 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
8328 ! add ambipolar electric field
8329 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
8330
8331 ! times time step and edge length
8332 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
8333 {end do\}
8334 end if
8335 end do
8336 end do
8337 end do
8338
8340 ! add upwind diffused magnetic energy back to energy
8341 ! calculate current density at cell edges
8342 jce=0.d0
8343 do idim1=1,ndim
8344 do idim2=1,ndim
8345 do idir=sdim,3
8346 if (lvc(idim1,idim2,idir)==0) cycle
8347 ixcmax^d=ixomax^d;
8348 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8349 ixamax^d=ixcmax^d-kr(idir,^d)+1;
8350 ixamin^d=ixcmin^d;
8351 ! current at transverse faces
8352 xs(ixa^s,:)=x(ixa^s,:)
8353 xs(ixa^s,idim2)=x(ixa^s,idim2)+half*s%dx(ixa^s,idim2)
8354 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi)
8355 if (lvc(idim1,idim2,idir)==1) then
8356 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8357 else
8358 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8359 end if
8360 end do
8361 end do
8362 end do
8363 do idir=sdim,3
8364 ixcmax^d=ixomax^d;
8365 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8366 ! E dot J on cell edges
8367 ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
8368 ! average from cell edge to cell center
8369 {^ifthreed
8370 if(idir==1) then
8371 {do ix^db=ixomin^db,ixomax^db\}
8372 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1,ix2-1,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
8373 +ein(ix1,ix2-1,ix3-1,idir))
8374 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8375 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8376 {end do\}
8377 else if(idir==2) then
8378 {do ix^db=ixomin^db,ixomax^db\}
8379 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
8380 +ein(ix1-1,ix2,ix3-1,idir))
8381 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8382 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8383 {end do\}
8384 else
8385 {do ix^db=ixomin^db,ixomax^db\}
8386 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2-1,ix3,idir)&
8387 +ein(ix1-1,ix2-1,ix3,idir))
8388 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8389 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8390 {end do\}
8391 end if
8392 }
8393 {^iftwod
8394 !idir=3
8395 {do ix^db=ixomin^db,ixomax^db\}
8396 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,idir)+ein(ix1,ix2-1,idir)&
8397 +ein(ix1-1,ix2-1,idir))
8398 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
8399 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
8400 {end do\}
8401 }
8402 ! save additional numerical resistive heating to an extra variable
8403 !! if(nwextra>0) then
8404 !! block%w(ixO^S,nw)=block%w(ixO^S,nw)+jce(ixO^S,idir)
8405 !! end if
8406 end do
8407 end if
8408
8409 ! allow user to change inductive electric field, especially for boundary driven applications
8410 if(associated(usr_set_electric_field)) &
8411 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8412
8413 circ(ixi^s,1:ndim)=zero
8414
8415 ! Calculate circulation on each face
8416 do idim1=1,ndim ! Coordinate perpendicular to face
8417 ixcmax^d=ixomax^d;
8418 ixcmin^d=ixomin^d-kr(idim1,^d);
8419 do idim2=1,ndim
8420 ixa^l=ixc^l-kr(idim2,^d);
8421 do idir=sdim,3 ! Direction of line integral
8422 ! Assemble indices
8423 if(lvc(idim1,idim2,idir)==1) then
8424 ! Add line integrals in direction idir
8425 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8426 +(fe(ixc^s,idir)&
8427 -fe(ixa^s,idir))
8428 else if(lvc(idim1,idim2,idir)==-1) then
8429 ! Add line integrals in direction idir
8430 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8431 -(fe(ixc^s,idir)&
8432 -fe(ixa^s,idir))
8433 end if
8434 end do
8435 end do
8436 {do ix^db=ixcmin^db,ixcmax^db\}
8437 ! Divide by the area of the face to get dB/dt
8438 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8439 ! Time update cell-face magnetic field component
8440 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8441 end if
8442 {end do\}
8443 end do
8444
8445 end associate
8446
8447 end subroutine mhd_update_faces_contact
8448
8449 !> update faces
8450 subroutine mhd_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8452 use mod_usr_methods
8454
8455 integer, intent(in) :: ixi^l, ixo^l
8456 double precision, intent(in) :: qt, qdt
8457 ! cell-center primitive variables
8458 double precision, intent(in) :: wp(ixi^s,1:nw)
8459 type(state) :: sct, s
8460 type(ct_velocity) :: vcts
8461 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8462 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8463
8464 double precision :: vtill(ixi^s,2)
8465 double precision :: vtilr(ixi^s,2)
8466 double precision :: bfacetot(ixi^s,ndim)
8467 double precision :: btill(ixi^s,ndim)
8468 double precision :: btilr(ixi^s,ndim)
8469 double precision :: cp(ixi^s,2)
8470 double precision :: cm(ixi^s,2)
8471 double precision :: circ(ixi^s,1:ndim)
8472 ! non-ideal electric field on cell edges
8473 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8474 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
8475 integer :: idim1,idim2,idir,ix^d
8476
8477 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
8478 cbarmax=>vcts%cbarmax)
8479
8480 ! Calculate contribution to FEM of each edge,
8481 ! that is, estimate value of line integral of
8482 ! electric field in the positive idir direction.
8483
8484 ! Loop over components of electric field
8485
8486 ! idir: electric field component we need to calculate
8487 ! idim1: directions in which we already performed the reconstruction
8488 ! idim2: directions in which we perform the reconstruction
8489
8490 ! if there is resistivity, get eta J
8491 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8492
8493 ! if there is ambipolar diffusion, get E_ambi
8494 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8495
8496 do idir=sdim,3
8497 ! Indices
8498 ! idir: electric field component
8499 ! idim1: one surface
8500 ! idim2: the other surface
8501 ! cyclic permutation: idim1,idim2,idir=1,2,3
8502 ! Velocity components on the surface
8503 ! follow cyclic premutations:
8504 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
8505
8506 ixcmax^d=ixomax^d;
8507 ixcmin^d=ixomin^d-1+kr(idir,^d);
8508
8509 ! Set indices and directions
8510 idim1=mod(idir,3)+1
8511 idim2=mod(idir+1,3)+1
8512
8513 jxc^l=ixc^l+kr(idim1,^d);
8514 ixcp^l=ixc^l+kr(idim2,^d);
8515
8516 ! Reconstruct transverse transport velocities
8517 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
8518 vtill(ixi^s,2),vtilr(ixi^s,2))
8519
8520 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
8521 vtill(ixi^s,1),vtilr(ixi^s,1))
8522
8523 ! Reconstruct magnetic fields
8524 ! Eventhough the arrays are larger, reconstruct works with
8525 ! the limits ixG.
8526 if(b0field) then
8527 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
8528 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
8529 else
8530 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
8531 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
8532 end if
8533 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
8534 btill(ixi^s,idim1),btilr(ixi^s,idim1))
8535
8536 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
8537 btill(ixi^s,idim2),btilr(ixi^s,idim2))
8538
8539 ! Take the maximum characteristic
8540
8541 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
8542 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
8543
8544 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
8545 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
8546
8547
8548 ! Calculate eletric field
8549 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
8550 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
8551 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
8552 /(cp(ixc^s,1)+cm(ixc^s,1)) &
8553 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
8554 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
8555 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
8556 /(cp(ixc^s,2)+cm(ixc^s,2))
8557
8558 ! add resistive electric field at cell edges E=-vxB+eta J
8559 if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
8560 ! add ambipolar electric field
8561 if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
8562
8563 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
8564
8565 if (.not.slab) then
8566 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
8567 fe(ixc^s,idir)=zero
8568 end where
8569 end if
8570
8571 end do
8572
8573 ! allow user to change inductive electric field, especially for boundary driven applications
8574 if(associated(usr_set_electric_field)) &
8575 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8576
8577 circ(ixi^s,1:ndim)=zero
8578
8579 ! Calculate circulation on each face: interal(fE dot dl)
8580 do idim1=1,ndim ! Coordinate perpendicular to face
8581 ixcmax^d=ixomax^d;
8582 ixcmin^d=ixomin^d-kr(idim1,^d);
8583 do idim2=1,ndim
8584 do idir=sdim,3 ! Direction of line integral
8585 ! Assemble indices
8586 if(lvc(idim1,idim2,idir)/=0) then
8587 hxc^l=ixc^l-kr(idim2,^d);
8588 ! Add line integrals in direction idir
8589 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8590 +lvc(idim1,idim2,idir)&
8591 *(fe(ixc^s,idir)&
8592 -fe(hxc^s,idir))
8593 end if
8594 end do
8595 end do
8596 {do ix^db=ixcmin^db,ixcmax^db\}
8597 ! Divide by the area of the face to get dB/dt
8598 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8599 ! Time update cell-face magnetic field component
8600 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8601 end if
8602 {end do\}
8603 end do
8604
8605 end associate
8606 end subroutine mhd_update_faces_hll
8607
8608 !> calculate eta J at cell edges
8609 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
8611 use mod_usr_methods
8612 use mod_geometry
8613
8614 integer, intent(in) :: ixi^l, ixo^l
8615 ! cell-center primitive variables
8616 double precision, intent(in) :: wp(ixi^s,1:nw)
8617 type(state), intent(in) :: sct, s
8618 ! current on cell edges
8619 double precision :: jce(ixi^s,sdim:3)
8620
8621 ! current on cell centers
8622 double precision :: jcc(ixi^s,7-2*ndir:3)
8623 ! location at cell faces
8624 double precision :: xs(ixgs^t,1:ndim)
8625 ! resistivity
8626 double precision :: eta(ixi^s)
8627 double precision :: gradi(ixgs^t)
8628 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
8629
8630 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
8631 ! calculate current density at cell edges
8632 jce=0.d0
8633 do idim1=1,ndim
8634 do idim2=1,ndim
8635 do idir=sdim,3
8636 if (lvc(idim1,idim2,idir)==0) cycle
8637 ixcmax^d=ixomax^d;
8638 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8639 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
8640 ixbmin^d=ixcmin^d;
8641 ! current at transverse faces
8642 xs(ixb^s,:)=x(ixb^s,:)
8643 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
8644 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
8645 if (lvc(idim1,idim2,idir)==1) then
8646 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8647 else
8648 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8649 end if
8650 end do
8651 end do
8652 end do
8653 ! get resistivity
8654 if(mhd_eta>zero)then
8655 jce(ixi^s,:)=jce(ixi^s,:)*mhd_eta
8656 else
8657 ixa^l=ixo^l^ladd1;
8658 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
8659 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
8660 ! calculate eta on cell edges
8661 do idir=sdim,3
8662 ixcmax^d=ixomax^d;
8663 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8664 jcc(ixc^s,idir)=0.d0
8665 {do ix^db=0,1\}
8666 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8667 ixamin^d=ixcmin^d+ix^d;
8668 ixamax^d=ixcmax^d+ix^d;
8669 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
8670 {end do\}
8671 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
8672 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
8673 end do
8674 end if
8675
8676 end associate
8677 end subroutine get_resistive_electric_field
8678
8679 !> get ambipolar electric field on cell edges
8680 subroutine get_ambipolar_electric_field(ixI^L,ixO^L,w,x,fE)
8682
8683 integer, intent(in) :: ixi^l, ixo^l
8684 double precision, intent(in) :: w(ixi^s,1:nw)
8685 double precision, intent(in) :: x(ixi^s,1:ndim)
8686 double precision, intent(out) :: fe(ixi^s,sdim:3)
8687
8688 double precision :: jxbxb(ixi^s,1:3)
8689 integer :: idir,ixa^l,ixc^l,ix^d
8690
8691 ixa^l=ixo^l^ladd1;
8692 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,jxbxb)
8693 ! calculate electric field on cell edges from cell centers
8694 do idir=sdim,3
8695 ! set ambipolar electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
8696 ! E_ambi(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
8697 call multiplyambicoef(ixi^l,ixa^l,jxbxb(ixi^s,idir),w,x)
8698 ixcmax^d=ixomax^d;
8699 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8700 fe(ixc^s,idir)=0.d0
8701 {do ix^db=0,1\}
8702 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8703 ixamin^d=ixcmin^d+ix^d;
8704 ixamax^d=ixcmax^d+ix^d;
8705 fe(ixc^s,idir)=fe(ixc^s,idir)+jxbxb(ixa^s,idir)
8706 {end do\}
8707 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0
8708 end do
8709
8710 end subroutine get_ambipolar_electric_field
8711
8712 !> calculate cell-center values from face-center values
8713 subroutine mhd_face_to_center(ixO^L,s)
8715 ! Non-staggered interpolation range
8716 integer, intent(in) :: ixo^l
8717 type(state) :: s
8718
8719 integer :: ix^d
8720
8721 ! calculate cell-center values from face-center values in 2nd order
8722 ! because the staggered arrays have an additional place to the left.
8723 ! Interpolate to cell barycentre using arithmetic average
8724 ! This might be done better later, to make the method less diffusive.
8725 {!dir$ ivdep
8726 do ix^db=ixomin^db,ixomax^db\}
8727 {^ifthreed
8728 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8729 +s%ws(ix1-1,ix2,ix3,1)*s%surfaceC(ix1-1,ix2,ix3,1))
8730 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8731 +s%ws(ix1,ix2-1,ix3,2)*s%surfaceC(ix1,ix2-1,ix3,2))
8732 s%w(ix^d,b3_)=half/s%surface(ix^d,3)*(s%ws(ix^d,3)*s%surfaceC(ix^d,3)&
8733 +s%ws(ix1,ix2,ix3-1,3)*s%surfaceC(ix1,ix2,ix3-1,3))
8734 }
8735 {^iftwod
8736 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8737 +s%ws(ix1-1,ix2,1)*s%surfaceC(ix1-1,ix2,1))
8738 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8739 +s%ws(ix1,ix2-1,2)*s%surfaceC(ix1,ix2-1,2))
8740 }
8741 {end do\}
8742
8743 ! calculate cell-center values from face-center values in 4th order
8744 !do idim=1,ndim
8745 ! gxO^L=ixO^L-2*kr(idim,^D);
8746 ! hxO^L=ixO^L-kr(idim,^D);
8747 ! jxO^L=ixO^L+kr(idim,^D);
8748
8749 ! ! Interpolate to cell barycentre using fourth order central formula
8750 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
8751 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8752 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8753 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8754 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
8755 !end do
8756
8757 ! calculate cell-center values from face-center values in 6th order
8758 !do idim=1,ndim
8759 ! fxO^L=ixO^L-3*kr(idim,^D);
8760 ! gxO^L=ixO^L-2*kr(idim,^D);
8761 ! hxO^L=ixO^L-kr(idim,^D);
8762 ! jxO^L=ixO^L+kr(idim,^D);
8763 ! kxO^L=ixO^L+2*kr(idim,^D);
8764
8765 ! ! Interpolate to cell barycentre using sixth order central formula
8766 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
8767 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
8768 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8769 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8770 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8771 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
8772 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
8773 !end do
8774
8775 end subroutine mhd_face_to_center
8776
8777 !> calculate magnetic field from vector potential
8778 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
8781
8782 integer, intent(in) :: ixis^l, ixi^l, ixo^l
8783 double precision, intent(inout) :: ws(ixis^s,1:nws)
8784 double precision, intent(in) :: x(ixi^s,1:ndim)
8785
8786 double precision :: adummy(ixis^s,1:3)
8787
8788 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
8789
8790 end subroutine b_from_vector_potential
8791
8792 subroutine rfactor_from_temperature_ionization(w,x,ixI^L,ixO^L,Rfactor)
8795 integer, intent(in) :: ixi^l, ixo^l
8796 double precision, intent(in) :: w(ixi^s,1:nw)
8797 double precision, intent(in) :: x(ixi^s,1:ndim)
8798 double precision, intent(out):: rfactor(ixi^s)
8799
8800 double precision :: iz_h(ixo^s),iz_he(ixo^s)
8801
8802 call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,te_),iz_h,iz_he)
8803 ! assume the first and second ionization of Helium have the same degree
8804 rfactor(ixo^s)=(1.d0+iz_h(ixo^s)+0.1d0*(1.d0+iz_he(ixo^s)*(1.d0+iz_he(ixo^s))))/(2.d0+3.d0*he_abundance)
8805
8806 end subroutine rfactor_from_temperature_ionization
8807
8808 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
8810 integer, intent(in) :: ixi^l, ixo^l
8811 double precision, intent(in) :: w(ixi^s,1:nw)
8812 double precision, intent(in) :: x(ixi^s,1:ndim)
8813 double precision, intent(out):: rfactor(ixi^s)
8814
8815 rfactor(ixo^s)=rr
8816
8817 end subroutine rfactor_from_constant_ionization
8818end 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
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
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure)
Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
Definition mod_fld.t:476
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
double precision, public fld_diff_tol
Tolerance for radiative Energy diffusion.
Definition mod_fld.t:27
double precision, public fld_gamma
A copy of (m)hd_gamma.
Definition mod_fld.t:46
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
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 add_fld_rad_force(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active)
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:197
logical fld_radforce_split
source split for energy interact and radforce:
Definition mod_fld.t:18
subroutine, public fld_init(r_gamma)
Initialising FLD-module Read opacities Initialise Multigrid and adimensionalise kappa.
Definition mod_fld.t:86
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x)
get dt limit for radiation force and FLD explicit source additions NOTE: w is primitive on entry
Definition mod_fld.t:334
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.
double precision, dimension(:), allocatable, parameter d
logical local_timestep
each cell has its own timestep or not
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
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 ionization degree - get ionization degree for given temperature
subroutine ionization_degree_from_temperature(ixil, ixol, te, iz_h, iz_he)
module mod_magnetofriction.t Purpose: use magnetofrictional method to relax 3D magnetic field to forc...
subroutine magnetofriction_init()
Initialize the module.
Magneto-hydrodynamics module.
Definition mod_mhd_phys.t:2
subroutine, 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.
logical, public, protected mhd_partial_ionization
Whether plasma is partially ionized.
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.
subroutine, public mhd_get_temperature_from_prim(w, x, ixil, ixol, res)
Calculate temperature=p/rho when in e_ the pressure p_ (primitive) is stored.
double precision, public, protected rr
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
double precision, public mhd_gamma
The adiabatic index.
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 CAK radiation line force is activated.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
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.
procedure(sub_get_pthermal), pointer, public mhd_get_rfactor
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.
logical, public clean_initial_divb
clean initial divB
procedure(sub_convert), pointer, public mhd_to_conserved
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.
subroutine, public mhd_get_temperature_from_etot(w, x, ixil, ixol, res)
Calculate temperature=p/rho from total energy.
logical, public, protected mhd_thermal_conduction
Whether thermal conduction is used.
procedure(sub_get_pthermal), pointer, public mhd_get_temperature
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+)
procedure(sub_convert), pointer, public mhd_to_primitive
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.
logical, public, protected eq_state_units
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.
procedure(sub_get_pthermal), pointer, public mhd_get_pthermal
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)
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
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)
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
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)
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.
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11