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