MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_mhd_phys.t
Go to the documentation of this file.
1!> Magneto-hydrodynamics module
3
4#include "amrvac.h"
5
6 use mod_global_parameters, only: std_len, const_c
10 use mod_fld, only: fld_fluid
11 use mod_physics
12 use mod_eos
13 use mod_comm_lib, only: mpistop
15
16 implicit none
17 private
18
19 !> The adiabatic constant
20 double precision, public :: mhd_adiab = 1.0d0
21 !> The MHD resistivity
22 double precision, public :: mhd_eta = 0.0d0
23 !> The MHD hyper-resistivity
24 double precision, public :: mhd_eta_hyper = 0.0d0
25 !> Hall resistivity
26 double precision, public :: mhd_etah = 0.0d0
27 !> The MHD ambipolar coefficient
28 double precision, public :: mhd_eta_ambi = 0.0d0
29 !> Height of the mask used in the TRAC method
30 double precision, public, protected :: mhd_trac_mask = 0.d0
31 !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
32 !> taking values within [0, 1]
33 double precision, public :: mhd_glm_alpha = 0.5d0
34 !> Reduced speed of light for semirelativistic MHD: 2% of light speed
35 double precision, public, protected :: mhd_reduced_c = 0.02d0*const_c
36 !> The thermal conductivity kappa in hyperbolic thermal conduction
37 double precision, public :: mhd_hyperbolic_tc_kappa = 0.d0
38 logical, public :: mhd_hyperbolic_tc_constant = .false.
39 !> Coefficient of diffusive divB cleaning
40 double precision, public :: divbdiff = 0.8d0
41 !> Ionization fraction of H
42 !> H_ion_fr = H+/(H+ + H)
43 double precision, public, protected :: h_ion_fr=1d0
44 !> Ionization fraction of He
45 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
46 double precision, public, protected :: he_ion_fr=1d0
47 !> Ratio of number He2+ / number He+ + He2+
48 !> He_ion_fr2 = He2+/(He2+ + He+)
49 double precision, public, protected :: he_ion_fr2=1d0
50 ! used for eq of state when it is not defined by units,
51 ! the units do not contain terms related to ionization fraction
52 ! and it is p = RR * rho * T
53 double precision, public, protected :: rr=1d0
54 !> inverse of squared speed of light c0 and reduced speed of light c
55 double precision :: inv_squared_c0=0.d0, inv_squared_c=0.d0
56 !> equi vars indices in the state%equi_vars array
57 integer, public :: equi_rho0_ = -1
58 integer, public :: equi_pe0_ = -1
59 !> Number of tracer species
60 integer, public, protected :: mhd_n_tracer = 0
61 !> Index of the density (in the w array)
62 integer, public, protected :: rho_
63 !> Indices of the momentum density
64 integer, allocatable, public, protected :: mom(:)
65 !> Indices of the momentum density for the form of better vectorization
66 integer, public, protected :: ^c&m^C_
67 !> Index of the energy density (-1 if not present)
68 integer, public, protected :: e_
69 !> Indices of the magnetic field for the form of better vectorization
70 integer, public, protected :: ^c&b^C_
71 !> Index of the gas pressure (-1 if not present) should equal e_
72 integer, public, protected :: p_
73 !> Index of the electron number density for LTE module
74 integer, public, protected :: ne_
75 !> Index of the field-aligned heat flux q_parallel
76 integer, public, protected :: qpar_
77 !> Index of the perpendicular heat flux q_perp
78 integer, public, protected :: qperp_
79 !> Indices of the GLM psi
80 integer, public, protected :: psi_
81 !> Index of the radiation energy
82 integer, public, protected :: r_e
83 !> Indices of temperature
84 integer, public, protected :: te_
85 !> Index of the FIP passive scalar rho*fip in conserved form, fip in primitive form
86 integer, public, protected :: fip_ = -1
87 !> Whether FIP passive scalar is enabled
88 logical, public, protected :: mhd_fip = .false.
89 !> Index of the cutoff temperature for the TRAC method
90 integer, public, protected :: tcoff_
91 integer, public, protected :: tweight_
92 !> Indices of the tracers
93 integer, allocatable, public, protected :: tracer(:)
94 !> The number of waves
95 integer :: nwwave=8
96 !> Method type of divb in a integer for good performance
97 integer :: type_divb
98 !> To skip * layer of ghost cells during divB=0 fix for boundary
99 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
100 ! DivB cleaning methods
101 integer, parameter :: divb_none = 0
102 integer, parameter :: divb_multigrid = -1
103 integer, parameter :: divb_glm = 1
104 integer, parameter :: divb_powel = 2
105 integer, parameter :: divb_janhunen = 3
106 integer, parameter :: divb_linde = 4
107 integer, parameter :: divb_lindejanhunen = 5
108 integer, parameter :: divb_lindepowel = 6
109 integer, parameter :: divb_lindeglm = 7
110 integer, parameter :: divb_ct = 8
111 !> Whether an energy equation is used
112 logical, public, protected :: mhd_energy = .true.
113 !> Whether thermal conduction is used
114 logical, public, protected :: mhd_thermal_conduction = .false.
115 !> Whether radiative cooling is added
116 logical, public, protected :: mhd_radiative_cooling = .false.
117 !> Whether thermal conduction is used
118 logical, public, protected :: mhd_hyperbolic_tc = .false.
119 !> Whether saturation is considered for hyperbolic TC. When the perpendicular
120 !> channel is active, the limiter uses sqrt(q_parallel^2+q_perp^2).
121 logical, public, protected :: mhd_hyperbolic_tc_sat = .false.
122 !> Whether the perpendicular hyperbolic-TC channel is enabled
123 logical, public, protected :: mhd_hyperbolic_tc_use_perp = .false.
124 !> Perpendicular hyperbolic-TC closure mode:
125 !> 'off' = disabled
126 !> 'fixed_reference' = fixed classical ratio at the reference normalisation
127 !> 'weak_field_isotropization' = empirical transition using a prescribed Bmin
128 !> 'electron_magnetization' = simplified ratio 1/(1+chi_e^2)
129 character(len=std_len), public, protected :: mhd_hyperbolic_tc_perp_mode = 'off'
130 !> Relative perpendicular hyperbolic-TC coefficient in fixed/strong-field limit:
131 !> kappa_perp0 = mhd_hyperbolic_tc_kappa_perp_factor * kappa_parallel
132 double precision, public, protected :: mhd_hyperbolic_tc_kappa_perp_factor = 0.d0
133 !> Field-strength transition scale for perpendicular closure
134 double precision, public, protected :: mhd_hyperbolic_tc_bmin = 0.d0
135 !> Constant Coulomb logarithm used by the simplified electron-magnetization
136 !> closure. It is a namelist parameter so changing it has no per-cell cost.
137 double precision, public, protected :: mhd_hyperbolic_tc_coulomb_log = 20.d0
138 !> Whether viscosity is added
139 logical, public, protected :: mhd_viscosity = .false.
140 !> Whether gravity is added
141 logical, public, protected :: mhd_gravity = .false.
142 !> Whether rotating frame is activated
143 logical, public, protected :: mhd_rotating_frame = .false.
144 !> Whether Hall-MHD is used
145 logical, public, protected :: mhd_hall = .false.
146 !> Whether Ambipolar term is used
147 logical, public, protected :: mhd_ambipolar = .false.
148 !> Whether Ambipolar term is implemented using supertimestepping
149 logical, public, protected :: mhd_ambipolar_sts = .false.
150 !> Whether Ambipolar term is implemented explicitly
151 logical, public, protected :: mhd_ambipolar_exp = .false.
152 !> Whether particles module is added
153 logical, public, protected :: mhd_particles = .false.
154 !> Whether magnetofriction is added
155 logical, public, protected :: mhd_magnetofriction = .false.
156 !> Whether GLM-MHD is used to control div B
157 logical, public, protected :: mhd_glm = .false.
158 !> Whether extended GLM-MHD is used with additional sources
159 logical, public, protected :: mhd_glm_extended = .true.
160 !> Whether TRAC method is used
161 logical, public, protected :: mhd_trac = .false.
162 !> Which TRAC method is used
163 integer, public, protected :: mhd_trac_type=1
164 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
165 integer, public, protected :: mhd_trac_finegrid=4
166 !> Whether internal energy is solved instead of total energy
167 logical, public, protected :: mhd_internal_e = .false.
168 !> Whether hydrodynamic energy is solved instead of total energy
169 logical, public, protected :: mhd_hydrodynamic_e = .false.
170 !> Whether divB cleaning sources are added splitting from fluid solver
171 logical, public, protected :: source_split_divb = .false.
172 !> Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved
173 logical, public, protected :: mhd_semirelativistic = .false.
174 !> Whether plasma is partially ionized
175 !> Whether CAK radiation line force is activated
176 logical, public, protected :: mhd_cak_force = .false.
177 !> Whether radiation-gas interaction is handled using flux limited diffusion
178 logical, public, protected :: mhd_radiation_fld = .false.
179 !> Radiation fluid object (gas-EoS callbacks for FLD), wired in mhd_link_eos
180 type(fld_fluid), allocatable, public :: fld_fl
181 !> whether split off equilibrium density and pressure
182 logical, public :: has_equi_rho_and_p = .false.
183 logical, public :: mhd_equi_thermal = .false.
184 !> whether dump full variables (when splitting is used) in a separate dat file
185 logical, public, protected :: mhd_dump_full_vars = .false.
186 !> Whether divB is computed with a fourth order approximation
187 integer, public, protected :: mhd_divb_nth = 1
188 !> Add divB wave in Roe solver
189 logical, public :: divbwave = .true.
190 !> clean initial divB
191 logical, public :: clean_initial_divb = .false.
192 !> To control divB=0 fix for boundary
193 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
194 !> B0 field is force-free
195 logical, public, protected :: b0field_forcefree=.true.
196 !> Whether an total energy equation is used
197 logical :: total_energy = .true.
198 !> Whether numerical resistive heating is included when solving partial energy equation
199 logical, public :: numerical_resistive_heating = .false.
200 !> Whether gravity work is included in energy equation
201 logical :: gravity_energy
202 !> Method type to clean divergence of B
203 character(len=std_len), public, protected :: typedivbfix = 'linde'
204 !> Method type of constrained transport
205 character(len=std_len), public, protected :: type_ct = 'uct_contact'
206 !> Update all equations due to divB cleaning
207 character(len=std_len) :: typedivbdiff = 'all'
208 !> type of fluid for thermal conduction
209 type(tc_fluid), public, allocatable :: tc_fl
210 !> type of fluid for thermal emission synthesis
211 type(te_fluid), public, allocatable :: te_fl_mhd
212 !> type of fluid for radiative cooling
213 type(rc_fluid), public, allocatable :: rc_fl
214
215 !define the subroutine interface for the ambipolar mask
216 abstract interface
217
218 subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
220 integer, intent(in) :: ixi^l, ixo^l
221 double precision, intent(in) :: x(ixi^s,1:ndim)
222 double precision, intent(in) :: w(ixi^s,1:nw)
223 double precision, intent(inout) :: res(ixi^s)
224 end subroutine mask_subroutine
225
226 end interface
227
228 procedure(mask_subroutine), pointer :: usr_mask_ambipolar => null()
229 procedure(sub_small_values), pointer :: mhd_handle_small_values => null()
230 ! Public methods
231 public :: usr_mask_ambipolar
232 public :: mhd_phys_init
233 public :: mhd_get_v
234 public :: mhd_get_rho
235 public :: mhd_e_to_ei
236 public :: mhd_ei_to_e
237 public :: mhd_face_to_center
238 public :: get_divb
239 public :: get_current
240 !> needed public if we want to use the ambipolar coefficient in the user file
241 public :: multiplyambicoef
242 public :: get_normalized_divb
244 public :: mhd_mag_en_all
245 {^nooned
247 }
248 ! Begin: following relevant for radiative MHD using FLD
249 ! first four are local and only of interest for mod_usr applications
250 ! where they can be used in diagnostics
251 ! NOTE those with _prim expect primitives on entry
253 public :: mhd_get_csrad2
254 public :: mhd_get_trad
256 ! as pointer phys_get_csrad2
257 public :: mhd_get_csrad2_prim
258 ! End: following relevant for radiative MHD using FLD
259 ! Removed orphan public declarations: mhd_get_Rfactor, mhd_get_temperature_from_prim,
260 ! mhd_get_temperature_from_etot. These functions live in mod_mhd_eos.t and are
261 ! reached via the eos% / phys_get_Rfactor / phys_get_tgas / phys_get_temperature
262 ! procedure pointers bound by mod_mhd_eos:bind_eos_to_source.
263
264contains
265
266 !> Read this module"s parameters from a file
267 subroutine mhd_read_params(files)
269 use mod_particles, only: particles_eta, particles_etah
270 character(len=*), intent(in) :: files(:)
271 integer :: n
272
273 namelist /mhd_list/ mhd_energy, mhd_n_tracer, mhd_adiab,&
277 typedivbdiff, type_ct, divbwave, &
280 particles_eta, particles_etah,has_equi_rho_and_p,mhd_equi_thermal,&
289
290 do n = 1, size(files)
291 open(unitpar, file=trim(files(n)), status="old")
292 read(unitpar, mhd_list, end=111)
293111 close(unitpar)
294 end do
295
296 ! He_abundance is set in eos_list and accessed via eos%He_abundance
297
298 end subroutine mhd_read_params
299
300 !> Write this module's parameters to a snapsoht
301 subroutine mhd_write_info(fh)
303 integer, intent(in) :: fh
304
305 integer :: er
306 integer, parameter :: n_par = 1
307 double precision :: values(n_par)
308 integer, dimension(MPI_STATUS_SIZE) :: st
309 character(len=name_len) :: names(n_par)
310
311 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
312
313 names(1) = "gamma"
314 values(1) = eos%gamma
315 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
316 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
317 end subroutine mhd_write_info
318
319 subroutine mhd_phys_init()
324 use mod_gravity, only: gravity_init
329 use mod_cak_force, only: cak_init
331 use mod_geometry
333 {^nooned
335 }
336 use mod_fld
337
338 integer :: itr, idir
339
340 call mhd_read_params(par_files)
341
342 if(mhd_internal_e) then
343 if(mhd_hydrodynamic_e) then
344 mhd_hydrodynamic_e=.false.
345 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_internal_e=T'
346 end if
347 if(has_equi_rho_and_p) then
348 has_equi_rho_and_p=.false.
349 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_internal_e=T'
350 end if
351 end if
352
353 if(mhd_hydrodynamic_e) then
354 if(mhd_internal_e) then
355 mhd_internal_e=.false.
356 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_hydrodynamic_e=T'
357 end if
358 if(b0field) then
359 b0field=.false.
360 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_hydrodynamic_e=T'
361 end if
362 if(has_equi_rho_and_p) then
363 has_equi_rho_and_p=.false.
364 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_hydrodynamic_e=T'
365 end if
366 end if
367
368 if(mhd_semirelativistic) then
369 if(b0field) then
370 b0field=.false.
371 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_semirelativistic=T'
372 endif
373 if(has_equi_rho_and_p) then
374 has_equi_rho_and_p=.false.
375 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_semirelativistic=T'
376 end if
377 if(mhd_hydrodynamic_e) then
378 mhd_hydrodynamic_e=.false.
379 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_semirelativistic=T'
380 end if
381 end if
382
383 if(.not. mhd_energy) then
384 if(mhd_internal_e) then
385 mhd_internal_e=.false.
386 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_energy=F'
387 end if
388 if(mhd_hydrodynamic_e) then
389 mhd_hydrodynamic_e=.false.
390 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_energy=F'
391 end if
394 if(mype==0) write(*,*) 'WARNING: set mhd_thermal_conduction=F when mhd_energy=F'
395 end if
396 if(mhd_hyperbolic_tc) then
397 mhd_hyperbolic_tc=.false.
398 if(mype==0) write(*,*) 'WARNING: set mhd_hyperbolic_tc=F when mhd_energy=F'
399 end if
400 if(mhd_radiative_cooling) then
402 if(mype==0) write(*,*) 'WARNING: set mhd_radiative_cooling=F when mhd_energy=F'
403 end if
404 if(mhd_trac) then
405 mhd_trac=.false.
406 if(mype==0) write(*,*) 'WARNING: set mhd_trac=F when mhd_energy=F'
407 end if
408 if(b0field) then
409 b0field=.false.
410 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_energy=F'
411 end if
412 if(has_equi_rho_and_p) then
413 has_equi_rho_and_p=.false.
414 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_energy=F'
415 end if
416 end if
417
420 if(mype==0) write(*,*) 'WARNING: set either parabolic TC or hyperbolic TC to F'
421 if(mype==0) write(*,*) 'WARNING: defaulting to only mhd_hyperbolic_tc=T'
422 end if
423 {^ifoned
425 call mpistop("mhd_hyperbolic_tc_use_perp is not supported in 1D")
426 end if
427 }
428
429 physics_type = "mhd"
430 phys_energy=mhd_energy
431 phys_internal_e=mhd_internal_e
434
435 phys_gamma = eos%gamma
437
438 if(mhd_energy) then
440 total_energy=.false.
441 else
443 total_energy=.true.
444 end if
445 else
446 total_energy=.false.
447 end if
448 phys_total_energy=total_energy
449 if(mhd_energy) then
450 if(mhd_internal_e) then
451 gravity_energy=.false.
452 else
453 gravity_energy=.true.
454 end if
455 else
456 gravity_energy=.false.
457 end if
458
459 {^ifoned
460 if(mhd_trac .and. mhd_trac_type .gt. 2) then
462 if(mype==0) write(*,*) 'WARNING: reset mhd_trac_type=1 for 1D simulation'
463 end if
464 }
465 if(mhd_trac .and. mhd_trac_type .le. 4) then
466 mhd_trac_mask=bigdouble
467 if(mype==0) write(*,*) 'WARNING: set mhd_trac_mask==bigdouble for global TRAC method'
468 end if
470
472 if(ndim==1) typedivbfix='none'
473 select case (typedivbfix)
474 case ('none')
475 type_divb = divb_none
476 {^nooned
477 case ('multigrid')
478 if(mhd_radiation_fld) call mpistop('To verify whether mg usage for FLD versus divB can be combined')
479 type_divb = divb_multigrid
480 use_multigrid = .true.
481 mg%operator_type = mg_laplacian
482 phys_global_source_after => mhd_clean_divb_multigrid
483 }
484 case ('glm')
485 mhd_glm = .true.
486 need_global_cmax = .true.
487 type_divb = divb_glm
488 case ('powel', 'powell')
489 type_divb = divb_powel
490 case ('janhunen')
491 type_divb = divb_janhunen
492 case ('linde')
493 type_divb = divb_linde
494 case ('lindejanhunen')
495 type_divb = divb_lindejanhunen
496 case ('lindepowel')
497 type_divb = divb_lindepowel
498 case ('lindeglm')
499 mhd_glm = .true.
500 need_global_cmax = .true.
501 type_divb = divb_lindeglm
502 case ('ct')
503 type_divb = divb_ct
504 stagger_grid = .true.
505 case default
506 call mpistop('Unknown divB fix')
507 end select
508
509 allocate(start_indices(number_species),stop_indices(number_species))
510 ! set the index of the first flux variable for species 1
511 start_indices(1)=1
512 ! Determine flux variables
513 rho_ = var_set_rho()
514
515 allocate(mom(ndir))
516 mom(:) = var_set_momentum(ndir)
517 m^c_=mom(^c);
518
519 ! Set index of energy variable
520 if (mhd_energy) then
521 nwwave = 8
522 e_ = var_set_energy() ! energy density
523 p_ = e_ ! gas pressure
524 else
525 nwwave = 7
526 e_ = -1
527 p_ = -1
528 end if
529
530 allocate(mag(ndir))
531 mag(:) = var_set_bfield(ndir)
532 b^c_=mag(^c);
533
534 if (mhd_glm) then
535 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
536 else
537 psi_ = -1
538 end if
539
540 if(mhd_hyperbolic_tc) then
541 qpar_ = var_set_fluxvar('q', 'q', need_bc=.false.)
543 qperp_ = var_set_fluxvar('qperp', 'qperp', need_bc=.false.)
544 else
545 qperp_ = -1
546 end if
547 need_global_cmax=.true.
548 else
549 qpar_ = -1
550 qperp_ = -1
551 end if
552
553 if (mhd_fip) then
554 fip_ = var_set_fluxvar('rho_fip', 'fip', need_bc=.false.)
555 else
556 fip_ = -1
557 end if
558
559 if (eos%eos_type == 'LTE') then
560 ne_ = var_set_ne()
561 te_ = var_set_te()
562 else if (eos%eos_type == 'PI') then ! PI stores Te via var_set_te (sets iw_te) so the generic mod_eos_PI getters address it like LTE
563 ne_ = -1
564 te_ = var_set_te()
565 else
566 ne_ = -1
567 te_ = -1
568 end if
569
570 allocate(tracer(mhd_n_tracer))
571 ! Set starting index of tracers
572 do itr = 1, mhd_n_tracer
573 tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
574 end do
575
576 if(mhd_radiation_fld)then
577 if(mhd_cak_force)then
578 if(mype==0) then
579 write(*,*)'Warning: CAK force addition together with FLD radiation'
580 endif
581 endif
583 if(mype==0) then
584 write(*,*)'Warning: Optically thin cooling together with FLD radiation'
585 endif
586 endif
587 if(.not.mhd_energy)then
588 call mpistop('using FLD implies the use of an energy equation, set mhd_energy=T')
589 else
591 call mpistop('using FLD not yet with semirelativistic energy formalism')
592 endif
594 call mpistop('using FLD not yet with hydrodynamic or internal energy formalism')
595 endif
596 if(has_equi_rho_and_p)then
597 call mpistop('using FLD not yet with split off rho and p')
598 endif
599 ! Note: so far ok with total energy equation but allow both split or unsplit B0
600 !> set added variable and equation for radiation energy
601 r_e = var_set_radiation_energy()
602 phys_get_csrad2 => mhd_get_csrad2_prim
603 !> Radiation fluid object: its EoS callbacks are wired in mhd_link_eos
604 allocate(fld_fl)
605 !> Initiate radiation-closure module
606 call fld_init()
607 !> The implicit (MG diffusion) hooks need the fld_fl object, so they
608 !> are wired here to physics-module wrappers that inject it.
609 if(use_multigrid)then
610 phys_implicit_update => mhd_fld_implicit_update
611 phys_evaluate_implicit => mhd_fld_evaluate_implicit
612 endif
613 endif
614 else
615 r_e=-1
616 endif
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
705 !> EOS module: phys_to_primitive / phys_to_conserved are bound by
706 !> mod_mhd_eos:bind_eos_to_source to route through the EoS layer;
707 !> mhd_to_primitive / mhd_to_conserved pointers are NOT used - every
708 !> call to convert state goes through eos%to_primitive / eos%to_conserved.
709 !> eos%inv_squared_c{0,} are set in mhd_physical_units (called below)
710 !> after inv_squared_c{0,} are computed.
711 if(mhd_hydrodynamic_e) then
712 phys_get_flux => mhd_get_flux_hde
713 else if(mhd_semirelativistic) then
714 if(mhd_energy) then
715 phys_get_flux => mhd_get_flux_semirelati
716 else
717 phys_get_flux => mhd_get_flux_semirelati_noe
718 end if
719 else
720 if(b0field.or.has_equi_rho_and_p) then
721 phys_get_flux => mhd_get_flux_split
722 else if(mhd_energy) then
723 phys_get_flux => mhd_get_flux
724 else
725 phys_get_flux => mhd_get_flux_noe
726 end if
727 end if
728 phys_get_v => mhd_get_v
729 if(mhd_semirelativistic) then
730 phys_add_source_geom => mhd_add_source_geom_semirelati
731 else if(b0field.or.has_equi_rho_and_p) then
732 phys_add_source_geom => mhd_add_source_geom_split
733 else
734 phys_add_source_geom => mhd_add_source_geom
735 end if
736 phys_add_source => mhd_add_source
737 phys_check_params => mhd_check_params
738 phys_write_info => mhd_write_info
739
740 if(mhd_internal_e) then
741 phys_handle_small_values => mhd_handle_small_values_inte
742 mhd_handle_small_values => mhd_handle_small_values_inte
743 phys_check_w => mhd_check_w_inte
744 else if(mhd_hydrodynamic_e) then
745 phys_handle_small_values => mhd_handle_small_values_hde
746 mhd_handle_small_values => mhd_handle_small_values_hde
747 phys_check_w => mhd_check_w_hde
748 else if(mhd_semirelativistic) then
749 phys_handle_small_values => mhd_handle_small_values_semirelati
750 mhd_handle_small_values => mhd_handle_small_values_semirelati
751 phys_check_w => mhd_check_w_semirelati
752 else if(has_equi_rho_and_p) then
753 phys_handle_small_values => mhd_handle_small_values_split
754 mhd_handle_small_values => mhd_handle_small_values_split
755 phys_check_w => mhd_check_w_split
756 else if(mhd_energy) then
757 phys_handle_small_values => mhd_handle_small_values_origin
758 mhd_handle_small_values => mhd_handle_small_values_origin
759 phys_check_w => mhd_check_w_origin
760 else
761 phys_handle_small_values => mhd_handle_small_values_noe
762 mhd_handle_small_values => mhd_handle_small_values_noe
763 phys_check_w => mhd_check_w_noe
764 end if
765
766 ! phys_get_pthermal is set by mhd_link_eos
767
768 if(number_equi_vars>0) then
769 phys_set_equi_vars => set_equi_vars_grid
770 endif
771
772 if(type_divb==divb_glm) then
773 phys_modify_wlr => mhd_modify_wlr
774 end if
775
776 ! Rfactor / temperature / pthermal pointers are bound by
777 ! mod_mhd_eos:bind_eos_to_source (called by mhd_link_eos immediately
778 ! after mhd_phys_init). No EoS machinery in mod_mhd_phys.t.
779
780 ! if using ct stagger grid, boundary divb=0 is not done here
781 if(stagger_grid) then
782 select case(type_ct)
783 case('average')
784 transverse_ghost_cells = 1
785 phys_get_ct_velocity => mhd_get_ct_velocity_average
786 phys_update_faces => mhd_update_faces_average
787 case('uct_contact')
788 transverse_ghost_cells = 1
789 phys_get_ct_velocity => mhd_get_ct_velocity_contact
790 phys_update_faces => mhd_update_faces_contact
791 case('uct_hll')
792 transverse_ghost_cells = 2
793 phys_get_ct_velocity => mhd_get_ct_velocity_hll
794 phys_update_faces => mhd_update_faces_hll
795 case default
796 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
797 end select
798 phys_face_to_center => mhd_face_to_center
799 phys_modify_wlr => mhd_modify_wlr
800 else if(ndim>1) then
801 phys_boundary_adjust => mhd_boundary_adjust
802 end if
803
804 {^nooned
805 ! clean initial divb
807 call mpistop('To verify whether mg usage for FLD versus divB can be combined')
808 if(clean_initial_divb) phys_clean_divb => mhd_clean_divb_multigrid
809 }
810
811 ! derive units from basic units
812 call mhd_physical_units()
813
814 if(mhd_hyperbolic_tc) then
815 if(mhd_hyperbolic_tc_kappa==0.d0) then
816 if(si_unit) then
818 else
820 end if
821 else
823 end if
824
826 select case(trim(mhd_hyperbolic_tc_perp_mode))
827 case('fixed_reference')
829 if(si_unit) then
832 else
835 end if
836 end if
837 case('weak_field_isotropization')
838 if(mhd_hyperbolic_tc_bmin==0.d0) then
840 end if
841 case('electron_magnetization')
842 if(mhd_hyperbolic_tc_coulomb_log<=zero) then
843 call mpistop("mhd_hyperbolic_tc_coulomb_log must be positive")
844 end if
845 case default
846 call mpistop("invalid mhd_hyperbolic_tc_perp_mode: "// &
848 end select
849 end if
850 end if
851 if(.not. mhd_energy .and. mhd_thermal_conduction) then
852 call mpistop("thermal conduction needs mhd_energy=T")
853 end if
854 if(.not. mhd_energy .and. mhd_hyperbolic_tc) then
855 call mpistop("hyperbolic thermal conduction needs mhd_energy=T")
856 end if
857 if(.not. mhd_energy .and. mhd_radiative_cooling) then
858 call mpistop("radiative cooling needs mhd_energy=T")
859 end if
860
861 !> Cache log10(nH) in wextra for LTE+IonE TC (density invariant during STS)
862 if (eos%eos_type == 'LTE' .and. eos%ionE .and. mhd_thermal_conduction) then
863 iw_log_nh = var_set_wextra()
864 end if
865
866 if(mhd_equi_thermal)then
867 if((.not.has_equi_rho_and_p).or.(.not.total_energy))then
868 mhd_equi_thermal=.false.
869 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no splitting or total e in use'
870 else
872 if(mype==0) write(*,*) 'Will subtract thermal balance in TC or RC with mhd_equi_thermal=T'
873 else
874 mhd_equi_thermal=.false.
875 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no TC or RC in use'
876 endif
877 endif
878 endif
879
880 ! initialize thermal conduction module
881 if (mhd_thermal_conduction) then
882 call sts_init()
883 call tc_init_params(eos%gamma)
884
885 allocate(tc_fl)
886 call tc_get_mhd_params(tc_fl,tc_params_read_mhd)
887 if(ndim==1) then
888 call add_sts_method(mhd_get_tc_dt_hd,mhd_sts_set_source_tc_hd,e_,1,e_,1,.false.)
889 else
890 call add_sts_method(mhd_get_tc_dt_mhd,mhd_sts_set_source_tc_mhd,e_,1,e_,1,.false.)
891 endif
892 ! TC function pointers (get_temperature_from_conserved/eint, get_rho,
893 ! get_temperature_equi, get_rho_equi, subtract_equi) are bound by
894 ! bind_eos_to_source in mod_mhd_eos.t to the correct EoS-aware
895 ! implementations. No EoS machinery in mod_mhd_phys.t.
896 if(.not.mhd_internal_e) then
897 if(mhd_hydrodynamic_e) then
898 call set_conversion_methods_to_head(mhd_e_to_ei_hde, mhd_ei_to_e_hde)
899 phys_e_to_ei => mhd_e_to_ei_hde
900 phys_ei_to_e => mhd_ei_to_e_hde
901 else if(mhd_semirelativistic) then
902 call set_conversion_methods_to_head(mhd_e_to_ei_semirelati, mhd_ei_to_e_semirelati)
903 phys_e_to_ei => mhd_e_to_ei_semirelati
904 phys_ei_to_e => mhd_ei_to_e_semirelati
905 else
906 if (iw_log_nh > 0) then
907 call set_conversion_methods_to_head(mhd_e_to_ei_and_cache_log_nh, mhd_ei_to_e)
908 else
910 end if
911 phys_e_to_ei => mhd_e_to_ei
912 phys_ei_to_e => mhd_ei_to_e
913 end if
914 end if
915 call set_error_handling_to_head(mhd_tc_handle_small_e)
916 tc_fl%e_ = e_
917 tc_fl%Tcoff_ = tcoff_
918 end if
919
920 ! Energy conversion pointers needed by EOS module regardless of TC method
921 if(.not.mhd_internal_e .and. .not.associated(phys_e_to_ei)) then
922 if(mhd_hydrodynamic_e) then
923 phys_e_to_ei => mhd_e_to_ei_hde
924 phys_ei_to_e => mhd_ei_to_e_hde
925 else if(mhd_semirelativistic) then
926 phys_e_to_ei => mhd_e_to_ei_semirelati
927 phys_ei_to_e => mhd_ei_to_e_semirelati
928 else
929 phys_e_to_ei => mhd_e_to_ei
930 phys_ei_to_e => mhd_ei_to_e
931 end if
932 end if
933
934 ! Initialize radiative cooling module
935 if (mhd_radiative_cooling) then
936 call radiative_cooling_init_params(eos%gamma,eos%He_abundance)
937 allocate(rc_fl)
938 rc_fl%fip_ = fip_
939 call radiative_cooling_init(rc_fl,rc_params_read)
940 rc_fl%e_ = e_
941 rc_fl%Tcoff_ = tcoff_
942 rc_fl%subtract_equi = has_equi_rho_and_p
943 ! rc_fl EoS pointers (get_rho, get_pthermal, get_var_Rfactor,
944 ! equi accessors, subtract_equi) are bound by bind_eos_to_source
945 ! in mod_mhd_eos.t. No EoS machinery in mod_mhd_phys.t.
946 end if
947 allocate(te_fl_mhd)
948 ! te_fl_mhd EoS pointers are bound by bind_eos_to_source in mod_mhd_eos.t
949{^ifthreed
950 phys_te_images => mhd_te_images
951}
952
953 ! consistency check for hyperresistivity implementation
954 if (mhd_eta_hyper>0.0d0) then
955 if(mype==0) then
956 write(*,*) '*****Using hyperresistivity: with mhd_eta_hyper :', mhd_eta_hyper
957 endif
958 if(b0field) then
959 ! hyperresistivity not ok yet with splitting
960 call mpistop("Must have B0field=F when using hyperresistivity")
961 end if
962 endif
963 if (mhd_eta_hyper<0.0d0) then
964 call mpistop("Must have mhd_eta_hyper positive when using hyperresistivity")
965 endif
966
967 ! Initialize viscosity module
968 if (mhd_viscosity) then
969 call viscosity_init(phys_wider_stencil)
970 end if
971
972 ! Initialize gravity module
973 if(mhd_gravity) then
974 call gravity_init()
975 end if
976
977 ! Initialize rotating frame module
978 if(mhd_rotating_frame) then
979 if(has_equi_rho_and_p) then
980 ! mod_rotating_frame does not handle splitting of density
981 call mpistop("Must have has_equi_rho_and_p=F when mhd_rotating_frame=T")
982 end if
984 endif
985
986
987 ! initialize magnetofriction module
988 if(mhd_magnetofriction) then
990 end if
991
992 if(mhd_hall) then
993 if(mhd_semirelativistic) then
994 ! semirelativistic does not incorporate hall terms
995 call mpistop("Must have mhd_hall=F when mhd_semirelativistic=T")
996 end if
997 if(coordinate>1)then
998 ! normal unsplit case or split cases do not have geometric sources for Hall included
999 call mpistop("Must have Cartesian coordinates for Hall")
1000 endif
1001 ! For Hall, we need one more reconstructed layer since currents are computed
1002 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1003 phys_wider_stencil = 1
1004 end if
1005
1006 ! The perpendicular HTC geometry evaluates a fourth-order centred
1007 ! temperature gradient inside the reconstructed flux layer. It therefore
1008 ! needs one layer beyond the default two ghost cells.
1010 phys_wider_stencil=max(phys_wider_stencil,1)
1011 end if
1012
1013 if(mhd_ambipolar) then
1014 if(mhd_ambipolar_sts) then
1015 call sts_init()
1017 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mag(1),&
1018 ndir,mag(1),ndir,.true.)
1019 else
1020 ! any total energy or no energy at all case is handled here
1021 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mom(ndir)+1,&
1022 mag(ndir)-mom(ndir),mag(1),ndir,.true.)
1023 end if
1024 else
1025 mhd_ambipolar_exp=.true.
1026 ! For flux ambipolar term, we need one more reconstructed layer since currents are computed
1027 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1028 phys_wider_stencil = 1
1029 end if
1030 end if
1031
1032 ! ionization-degree table init now lives in eos_finalise (eos% owns
1033 ! thermodynamic-backend init, parallel to LTE tables); see mod_eos_PI.
1034
1035 ! Initialize CAK radiation force module
1036 if (mhd_cak_force) then
1038 call mpistop("CAK implementation not available in internal or semirelativistic variants")
1039 endif
1040 if(has_equi_rho_and_p) then
1041 call mpistop("CAK force implementation not available for split off pressure and density")
1042 endif
1043 call cak_init(eos%gamma)
1044 endif
1045
1046 end subroutine mhd_phys_init
1047
1048{^ifthreed
1049 subroutine mhd_te_images
1052
1053 select case(convert_type)
1054 case('EIvtiCCmpi','EIvtuCCmpi')
1056 case('ESvtiCCmpi','ESvtuCCmpi')
1058 case('SIvtiCCmpi','SIvtuCCmpi')
1060 case('WIvtiCCmpi','WIvtuCCmpi')
1062 case default
1063 call mpistop("Error in synthesize emission: Unknown convert_type")
1064 end select
1065 end subroutine mhd_te_images
1066}
1067
1068!!start th cond
1069 ! wrappers for STS functions in thermal_conductivity module
1070 ! which take as argument the tc_fluid (defined in the physics module)
1071 subroutine mhd_sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1075 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1076 double precision, intent(in) :: x(ixi^s,1:ndim)
1077 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1078 double precision, intent(in) :: my_dt
1079 logical, intent(in) :: fix_conserve_at_step
1080 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1081 end subroutine mhd_sts_set_source_tc_mhd
1082
1083 subroutine mhd_sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1087 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1088 double precision, intent(in) :: x(ixi^s,1:ndim)
1089 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1090 double precision, intent(in) :: my_dt
1091 logical, intent(in) :: fix_conserve_at_step
1092 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1093 end subroutine mhd_sts_set_source_tc_hd
1094
1095 function mhd_get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1096 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1097 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1098 !and T=p/rho
1101
1102 integer, intent(in) :: ixi^l, ixo^l
1103 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1104 double precision, intent(in) :: w(ixi^s,1:nw)
1105 double precision :: dtnew
1106
1107 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1108 end function mhd_get_tc_dt_mhd
1109
1110 function mhd_get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1111 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1112 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1113 !and T=p/rho
1116
1117 integer, intent(in) :: ixi^l, ixo^l
1118 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1119 double precision, intent(in) :: w(ixi^s,1:nw)
1120 double precision :: dtnew
1121
1122 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1123 end function mhd_get_tc_dt_hd
1124
1125 subroutine mhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
1127
1128 integer, intent(in) :: ixi^l,ixo^l
1129 double precision, intent(inout) :: w(ixi^s,1:nw)
1130 double precision, intent(in) :: x(ixi^s,1:ndim)
1131 integer, intent(in) :: step
1132 character(len=140) :: error_msg
1133
1134 ! tc_patch_eint repairs w(:, e_) in place during the source-term call,
1135 ! but the Chebyshev recurrence can still produce residual negative
1136 ! e_int in the updated state. Run mhd_handle_small_ei every substep
1137 ! (patch on or off) so STS does not propagate negative e through.
1138 write(error_msg,"(a,i3)") "Thermal conduction step ", step
1139 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
1140 end subroutine mhd_tc_handle_small_e
1141
1142 ! fill in tc_fluid fields from namelist
1143 subroutine tc_params_read_mhd(fl)
1145 type(tc_fluid), intent(inout) :: fl
1146
1147 double precision :: tc_k_para=0d0
1148 double precision :: tc_k_perp=0d0
1149 integer :: n
1150 ! list parameters
1151 logical :: tc_perpendicular=.false.
1152 logical :: tc_saturate=.false.
1153 logical :: tc_patch_eint=.false.
1154 double precision :: trac_t_floor=0.d0
1155 character(len=std_len) :: tc_slope_limiter="MC"
1156
1157 namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp, tc_patch_eint, trac_t_floor
1158
1159 do n = 1, size(par_files)
1160 open(unitpar, file=trim(par_files(n)), status="old")
1161 read(unitpar, tc_list, end=111)
1162111 close(unitpar)
1163 end do
1164
1165 fl%tc_perpendicular = tc_perpendicular
1166 fl%tc_saturate = tc_saturate
1167 fl%tc_patch_eint = tc_patch_eint
1168 fl%tc_k_para = tc_k_para
1169 fl%tc_k_perp = tc_k_perp
1170 fl%trac_T_floor = trac_t_floor / unit_temperature
1171 select case(tc_slope_limiter)
1172 case ('no','none')
1173 fl%tc_slope_limiter = 0
1174 case ('MC')
1175 ! monotonized central limiter Woodward and Collela limiter (eq.3.51h)
1176 fl%tc_slope_limiter = 1
1177 case('minmod')
1178 ! minmod limiter
1179 fl%tc_slope_limiter = 2
1180 case ('superbee')
1181 ! Roes superbee limiter (eq.3.51i)
1182 fl%tc_slope_limiter = 3
1183 case ('koren')
1184 ! Barry Koren Right variant
1185 fl%tc_slope_limiter = 4
1186 case ('vanleer')
1187 ! van Leer limiter
1188 fl%tc_slope_limiter = 5
1189 case default
1190 call mpistop("Unknown tc_slope_limiter, choose MC, minmod, superbee, koren, vanleer")
1191 end select
1192 end subroutine tc_params_read_mhd
1193!!end th cond
1194
1195!!rad cool
1196 subroutine rc_params_read(fl)
1198 use mod_constants, only: bigdouble
1199 type(rc_fluid), intent(inout) :: fl
1200
1201 !> Lower limit of temperature
1202 double precision :: tlow=bigdouble
1203 double precision :: rad_damp_height=0.5d0
1204 double precision :: rad_damp_scale=0.15d0
1205 integer :: n
1206 ! list parameters
1207 integer :: ncool = 4000
1208 !> Fixed temperature not lower than tlow
1209 logical :: tfix=.false.
1210 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1211 logical :: rc_split=.false.
1212 logical :: rad_damp=.false.
1213 !> Name of cooling curve
1214 character(len=std_len) :: coolcurve='JCcorona'
1215 logical :: rad_newton = .false.
1216 double precision :: rad_newton_trad = 0.006d0
1217 double precision :: rad_newton_rhosurf = 1.d4
1218 double precision :: rad_newton_pthick = 25.d0
1219 !> HEAD-side cooling parameters (missing from common content after merge)
1220 double precision :: cfrac=0.1d0
1221 double precision :: rad_cut_hgt=0.5d0
1222 double precision :: rad_cut_dey=0.15d0
1223 !> Variable-c_V Townsend extension (Y_mod): quadrature and sub-intervals
1224 character(len=8) :: rc_y_mod_quadrature='boole'
1225 integer :: rc_y_mod_n_sub=16
1226
1227 namelist /rc_list/ coolcurve, ncool, cfrac, tlow, tfix, rc_split, &
1228 rad_cut_hgt, rad_cut_dey, &
1229 rc_y_mod_quadrature, rc_y_mod_n_sub, &
1230 rad_newton, rad_newton_trad, rad_newton_rhosurf, &
1231 rad_newton_pthick, rad_damp, rad_damp_height, rad_damp_scale
1232
1233 do n = 1, size(par_files)
1234 open(unitpar, file=trim(par_files(n)), status="old")
1235 read(unitpar, rc_list, end=111)
1236111 close(unitpar)
1237 end do
1238
1239 fl%ncool=ncool
1240 fl%coolcurve=coolcurve
1241 fl%tlow=tlow
1242 fl%Tfix=tfix
1243 fl%rc_split=rc_split
1244 fl%cfrac=cfrac
1245 fl%rad_cut_hgt=rad_cut_hgt
1246 fl%rad_cut_dey=rad_cut_dey
1247 fl%Y_mod_quadrature=rc_y_mod_quadrature
1248 fl%Y_mod_N_sub=rc_y_mod_n_sub
1249 fl%rad_damp=rad_damp
1250 fl%rad_damp_height=rad_damp_height
1251 fl%rad_damp_scale=rad_damp_scale
1252 fl%rad_newton=rad_newton
1253 fl%rad_newton_trad=rad_newton_trad
1254 fl%rad_newton_rhosurf=rad_newton_rhosurf
1255 fl%rad_newton_pthick=rad_newton_pthick
1256 end subroutine rc_params_read
1257
1258 !> sets the equilibrium variables
1259 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1261 use mod_usr_methods
1262 integer, intent(in) :: igrid, ixi^l, ixo^l
1263 double precision, intent(in) :: x(ixi^s,1:ndim)
1264
1265 double precision :: delx(ixi^s,1:ndim)
1266 double precision :: xc(ixi^s,1:ndim),xshift^d
1267 integer :: idims, ixc^l, hxo^l, ix, idims2
1268
1269 if(slab_uniform)then
1270 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1271 else
1272 ! for all non-cartesian and stretched cartesian coordinates
1273 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1274 endif
1275
1276 do idims=1,ndim
1277 hxo^l=ixo^l-kr(idims,^d);
1278 if(stagger_grid) then
1279 ! ct needs all transverse cells
1280 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1281 else
1282 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1283 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1284 end if
1285 ! always xshift=0 or 1/2
1286 xshift^d=half*(one-kr(^d,idims));
1287 do idims2=1,ndim
1288 select case(idims2)
1289 {case(^d)
1290 do ix = ixc^lim^d
1291 ! xshift=half: this is the cell center coordinate
1292 ! xshift=0: this is the cell edge i+1/2 coordinate
1293 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1294 end do\}
1295 end select
1296 end do
1297 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1298 end do
1299 end subroutine set_equi_vars_grid_faces
1300
1301 !> sets the equilibrium variables
1302 subroutine set_equi_vars_grid(igrid)
1304 use mod_usr_methods
1305
1306 integer, intent(in) :: igrid
1307
1308 !values at the center
1309 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1310
1311 !values at the interfaces
1312 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1313
1314 end subroutine set_equi_vars_grid
1315
1316 ! w, wnew conserved, add splitted variables back to wnew
1317 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1319 integer, intent(in) :: ixi^l,ixo^l, nwc
1320 double precision, intent(in) :: w(ixi^s, 1:nw)
1321 double precision, intent(in) :: x(ixi^s,1:ndim)
1322 double precision :: wnew(ixo^s, 1:nwc)
1323
1324 if(has_equi_rho_and_p) then
1325 wnew(ixo^s,rho_)=w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0)
1326 else
1327 wnew(ixo^s,rho_)=w(ixo^s,rho_)
1328 endif
1329 wnew(ixo^s,mom(:))=w(ixo^s,mom(:))
1330
1331 if (b0field) then
1332 ! add background magnetic field B0 to B
1333 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
1334 else
1335 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))
1336 end if
1337
1338 if(mhd_energy) then
1339 wnew(ixo^s,e_)=w(ixo^s,e_)
1340 if(has_equi_rho_and_p) then
1341 wnew(ixo^s,e_)=wnew(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1
1342 end if
1343 if(b0field .and. total_energy) then
1344 wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1345 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1346 end if
1347 end if
1348
1349 end function convert_vars_splitting
1350
1351 subroutine mhd_check_params
1353 use mod_usr_methods
1354 use mod_geometry, only: coordinate
1356 use mod_particles, only: particles_init, particles_eta, particles_etah
1357 use mod_particles, only: npayload,nusrpayload, &
1358 ngridvars,num_particles,physics_type_particles
1359 use mod_fld
1360
1361 double precision :: a,b,xfrac,yfrac
1362
1363 ! Initialize particles module here, so all extra and user vars are sample
1364 if(mhd_particles) then
1365 call particles_init()
1366 if (particles_eta < zero) particles_eta = mhd_eta
1367 if (particles_etah < zero) particles_eta = mhd_etah
1368 end if
1369
1370 ! gamma, gamma_minus_1, inv_gamma_minus_1 are set by eos_init
1371 if (.not. mhd_energy) then
1372 if (eos%gamma <= 0.0d0) call mpistop ("Error: gamma <= 0")
1373 if (mhd_adiab < 0.0d0) call mpistop ("Error: mhd_adiab < 0")
1375 else
1376 if (eos%gamma <= 0.0d0 .or. eos%gamma == 1.0d0) &
1377 call mpistop ("Error: gamma <= 0 or gamma == 1")
1378 small_e = small_pressure * eos%inv_gamma_minus_1
1379 small_r_e = small_pressure * eos%inv_gamma_minus_1
1380 end if
1381
1382 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1383 call mpistop("usr_set_equi_vars has to be implemented in the user file")
1384 endif
1385 if(convert .or. autoconvert) then
1386 if(convert_type .eq. 'dat_generic_mpi') then
1387 if(mhd_dump_full_vars) then
1388 if(mype .eq. 0) print*, " add conversion method: split -> full "
1389 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1390 endif
1391 endif
1392 endif
1393
1394 if(mhd_radiation_fld) then
1395 if(.not.use_imex_scheme)then
1396 call mpistop('select IMEX scheme for FLD radiation use')
1397 endif
1398 if(use_multigrid)then
1399 call phys_set_mg_bounds()
1400 else
1401 if(.not.fld_no_mg)call mpistop('multigrid must have BCs for IMEX and FLD radiation use')
1402 endif
1403 if(mype==0)then
1404 write(*,*)'==FLD SETUP======================'
1405 write(*,*)'Using FLD with settings:'
1406 write(*,*)'Using FLD with settings: mhd_radiation_fld=',mhd_radiation_fld
1407 write(*,*)'Using FLD with settings: fld_fluxlimiter=',fld_fluxlimiter
1408 write(*,*)'Using FLD with settings: fld_interaction_method=',fld_interaction_method
1409 write(*,*)'Using FLD with settings: fld_opacity_law=',fld_opacity_law
1410 write(*,*)'Using FLD with settings: fld_kappa0=',fld_kappa0
1411 write(*,*)'Using FLD with settings: fld_opal_table=',fld_opal_table
1412 write(*,*)'Using FLD with settings: fld_Radforce_split=',fld_radforce_split
1413 write(*,*)'Using FLD with settings: fld_bisect_tol=',fld_bisect_tol
1414 write(*,*)'Using FLD with settings: fld_diff_tol=',fld_diff_tol
1415 write(*,*)'Using FLD with settings: nth_for_diff_mg=',nth_for_diff_mg
1416 write(*,*)' FLD has use_imex_scheme and use_multigrid=',use_imex_scheme,use_multigrid
1417 print *,'const_rad_a =',const_rad_a
1418 print *,'NORMALIZED arad_norm=',arad_norm
1419 print *,'NORMALIZED c_norm=',c_norm
1420 print *,'const_kappae =',const_kappae
1421 if(trim(fld_opacity_law).eq.'const_norm')then
1422 print *,'NORMALIZED fld_kappa0 =',fld_kappa0
1423 print *,'physical value (in cgs or SI) =',fld_kappa0*unit_opacity
1424 endif
1425 if(trim(fld_opacity_law).eq.'const')then
1426 print *,'physical fld_kappa (in cgs or SI) =',fld_kappa0
1427 print *,'NORMALIZED value =',fld_kappa0/unit_opacity
1428 endif
1429 write(*,*)'===FLD SETUP====================='
1430 endif
1431 endif
1432
1433 if(mype==0)then
1434 write(*,*)'====MHD run with settings===================='
1435 write(*,*)'Using mod_mhd_phys with settings:'
1436 write(*,*)'SI_unit=',si_unit
1437 write(*,*)'Dimensionality :',ndim
1438 write(*,*)'vector components:',ndir
1439 write(*,*)'coordinate set to type,slab:',coordinate,slab
1440 write(*,*)'number of variables nw=',nw
1441 write(*,*)' start index iwstart=',iwstart
1442 write(*,*)'number of vector variables=',nvector
1443 write(*,*)'number of stagger variables nws=',nws
1444 write(*,*)'number of variables with BCs=',nwgc
1445 write(*,*)'number of vars with fluxes=',nwflux
1446 write(*,*)'number of vars with flux + BC=',nwfluxbc
1447 write(*,*)'number of auxiliary variables=',nwaux
1448 write(*,*)'number of extra vars without flux=',nwextra
1449 write(*,*)'number of extra vars for wextra=',nw_extra
1450 write(*,*)'number of auxiliary I/O variables=',nwauxio
1451 write(*,*)'number of mhd_n_tracer=',mhd_n_tracer
1452 write(*,*)' mhd_energy=',mhd_energy,' with total_energy=',total_energy
1453 write(*,*)' mhd_semirelativistic=',mhd_semirelativistic
1454 write(*,*)' mhd_internal_e=',mhd_internal_e
1455 write(*,*)' mhd_hydrodynamic_e=',mhd_hydrodynamic_e
1456 write(*,*)' mhd_gravity=',mhd_gravity
1457 write(*,*)' mhd_eta=',mhd_eta,' nonzero implies resistivity'
1458 write(*,*)' mhd_viscosity=',mhd_viscosity
1459 write(*,*)' mhd_radiative_cooling=',mhd_radiative_cooling
1460 write(*,*)' mhd_cak_force=',mhd_cak_force
1461 write(*,*)' mhd_radiation_fld=',mhd_radiation_fld
1462 write(*,*)' mhd_thermal_conduction=',mhd_thermal_conduction
1463 write(*,*)' mhd_hyperbolic_tc=',mhd_hyperbolic_tc
1464 write(*,*)' mhd_trac=',mhd_trac
1465 write(*,*)' mhd_hall=',mhd_hall
1466 write(*,*)' mhd_ambipolar=',mhd_ambipolar
1467 write(*,*)' mhd_eta_hyper=',mhd_eta_hyper
1468 write(*,*)' mhd_rotating_frame=',mhd_rotating_frame
1469 write(*,*)' mhd_particles=',mhd_particles
1470 if(mhd_particles) then
1471 write(*,*) '*****Using particles: with mhd_eta, mhd_etah :', mhd_eta, mhd_etah
1472 write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
1473 write(*,*) '*****Using particles: npayload,ngridvars :', npayload,ngridvars
1474 write(*,*) '*****Using particles: nusrpayload :', nusrpayload
1475 write(*,*) '*****Using particles: num_particles :', num_particles
1476 write(*,*) '*****Using particles: physics_type_particles=',physics_type_particles
1477 end if
1478 write(*,*)'number of ghostcells=',nghostcells
1479 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
1480 write(*,*)'==========================================='
1481 print *,'========EOS and UNITS==========='
1482 print *,'SI_unit =',si_unit
1483 print *,'gamma=',eos%gamma
1484 print *,'He_abundance =',eos%He_abundance
1485 print *,'RR =',rr
1486 print *,'========EOS and UNITS==========='
1487 print *,'unit_time =',unit_time
1488 print *,'unit_length =',unit_length
1489 print *,'unit_velocity =',unit_velocity
1490 print *,'unit_pressure =',unit_pressure
1491 print *,'unit_numberdensity =',unit_numberdensity
1492 print *,'unit_density =',unit_density
1493 print *,'unit_temperature =',unit_temperature
1494 print *,'unit_mass =',unit_mass
1495 print *,'unit_Erad =',unit_erad
1496 print *,'unit_radflux =',unit_radflux
1497 print *,'unit_magneticfield =',unit_magneticfield
1498 if(si_unit)then
1499 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/miu0_si
1500 else
1501 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/(4.0d0*dpi)
1502 endif
1503 print *, 'CHECK that p_u ',unit_pressure,' equals ',unit_density*unit_velocity**2
1504 print *, 'CHECK that L_u ',unit_length,' equals ',unit_velocity*unit_time
1505 print *, 'CHECK that M_u',unit_mass,' equals ',unit_density*unit_length**3
1506 print *, 'density to numberdensity has factor ',unit_density/unit_numberdensity
1507 if(si_unit)then
1508 print *, ' compare this to ',mp_si*(1.d0+4.d0*eos%He_abundance)
1509 else
1510 print *, ' compare this to ',mp_cgs*(1.d0+4.d0*eos%He_abundance)
1511 endif
1512 print *, 'pressure to n T has factor ',unit_pressure/(unit_numberdensity*unit_temperature)
1513 if(si_unit)then
1514 print *, ' compare this to ',kb_si*(2.d0+3.d0*eos%He_abundance)
1517 else
1518 print *, ' compare this to ',kb_cgs*(2.d0+3.d0*eos%He_abundance)
1521 endif
1522 if(eos%eos_type /= 'LTE')then
1523 print *, 'mean molecular weight mu is =',a/b,' = ', (1.d0+4.d0*eos%He_abundance)/(2.d0+3.d0*eos%He_abundance)
1524 xfrac=1.d0/a
1525 yfrac=4.d0*eos%He_abundance/(1.d0+4.d0*eos%He_abundance)
1526 print *, 'mass fraction hydrogen X is =',1/a,' and this equals ', 1.d0/(1.d0+4.d0*eos%He_abundance)
1527 print *, 'mass fraction helium Y is =',yfrac
1528 print *, ' check that 1/mu', b/a,' is equal to 2X+3Y/4=',2.d0*xfrac+3.d0*yfrac/4.d0
1529 print *, ' ratio n_e/n_p=',1.d0+2.0d0*eos%He_abundance
1530 endif
1531 print *,'========UNITS==========='
1532 endif
1533
1534 end subroutine mhd_check_params
1535
1536 subroutine mhd_physical_units()
1538 double precision :: mp,kb,miu0,c_lightspeed,xfrac,sigma_telectron
1539 double precision :: a,b
1540 ! Derive scaling units
1541 if(si_unit) then
1542 mp=mp_si
1543 kb=kb_si
1544 miu0=miu0_si
1545 const_sigmasb=sigma_sb_si
1546 c_lightspeed=c_si
1547 sigma_telectron=sigma_te_si
1548 else
1549 mp=mp_cgs
1550 kb=kb_cgs
1551 miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
1552 const_sigmasb=sigma_sb_cgs
1553 c_lightspeed=const_c
1554 sigma_telectron=sigma_te_cgs
1555 end if
1556 ! Normalisation dispatch keyed solely on eos%eos_type (FI is the default, so
1557 ! legacy parfiles land in the FI/PI absorbed-(a,b), RR=1 branch -- the former
1558 ! eq_state_units=.true. result).
1559 if (eos%eos_type == 'LTE') then
1560 !> Remove the assumed FI normalisation from the units and handle in EoS
1561 a=1d0
1562 b=1d0
1563 eos%nH2rhoFactor = 1d0+4d0*eos%He_abundance
1564 rr=(2d0+3d0*eos%He_abundance) / (1d0+4d0*eos%He_abundance)
1565 xfrac=1.d0/(1.d0+4.d0*eos%He_abundance)
1566 else
1567 !> FI / PI: absorbed-(a,b), RR=1 (a=b=1 with RR=1 would be wrong physics
1568 !> for He>0). PI shares FI's normalisation exactly; the partial b lives here.
1569 a=1d0+4d0*eos%He_abundance
1570 if(eos%eos_type=='PI') then
1571 b=1d0+h_ion_fr+eos%He_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0)
1572 else
1573 b=2d0+3d0*eos%He_abundance
1574 end if
1575 rr=1d0
1576 xfrac=1.d0/a
1577 end if
1578 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
1579 if(unit_density/=1.d0) then
1581 else if(unit_numberdensity/=1.d0) then
1583 end if
1584 if(unit_temperature/=1.d0) then
1588 if(unit_length/=1.d0) then
1590 else if(unit_time/=1.d0) then
1592 end if
1593 else if(unit_magneticfield/=1.d0) then
1597 if(unit_length/=1.d0) then
1599 else if(unit_time/=1.d0) then
1601 end if
1602 else if(unit_pressure/=1.d0) then
1606 if(unit_length/=1.d0) then
1608 else if(unit_time/=1.d0) then
1610 end if
1611 else if(unit_velocity/=1.d0) then
1615 if(unit_length/=1.d0) then
1617 else if(unit_time/=1.d0) then
1619 end if
1620 else if(unit_time/=1.d0) then
1625 end if
1626 else if(unit_temperature/=1.d0) then
1627 ! units of temperature and velocity are dependent
1628 if(unit_magneticfield/=1.d0) then
1633 if(unit_length/=1.d0) then
1635 else if(unit_time/=1.d0) then
1637 end if
1638 else if(unit_pressure/=1.d0) then
1643 if(unit_length/=1.d0) then
1645 else if(unit_time/=1.d0) then
1647 end if
1648 end if
1649 else if(unit_magneticfield/=1.d0) then
1650 ! units of magnetic field and pressure are dependent
1651 if(unit_velocity/=1.d0) then
1656 if(unit_length/=1.d0) then
1658 else if(unit_time/=1.d0) then
1660 end if
1661 else if(unit_time/=0.d0) then
1667 end if
1668 else if(unit_pressure/=1.d0) then
1669 if(unit_velocity/=1.d0) then
1674 if(unit_length/=1.d0) then
1676 else if(unit_time/=1.d0) then
1678 end if
1679 else if(unit_time/=0.d0) then
1685 end if
1686 end if
1687 ! Additional units needed for the particles
1688 c_norm=c_lightspeed/unit_velocity
1690 if (.not. si_unit) unit_charge = unit_charge*const_c
1692
1693 if(mhd_semirelativistic) then
1694 if(mhd_reduced_c<1.d0) then
1695 ! dimensionless speed
1696 inv_squared_c0=1.d0
1697 inv_squared_c=1.d0/mhd_reduced_c**2
1698 else
1699 inv_squared_c0=(unit_velocity/c_lightspeed)**2
1700 inv_squared_c=(unit_velocity/mhd_reduced_c)**2
1701 end if
1702 ! Propagate to the EoS container. Must happen AFTER inv_squared_c{0,}
1703 ! are set above; the assignment earlier in mhd_phys_init runs before
1704 ! mhd_physical_units and would store uninitialised values.
1705 eos%inv_squared_c0 = inv_squared_c0
1706 eos%inv_squared_c = inv_squared_c
1707 end if
1708
1709 !> Units for radiative flux and opacity as used in FLD
1710 ! this is the radiation constant in either cgs or SI units
1711 const_rad_a=4.d0*const_sigmasb/c_lightspeed
1712 ! this is the dimensionless conversion factor for Erad to Trad
1714 ! This is the Thomson scattering opacity in the correct units
1715 ! note that the hydrogen mass fraction X=1/a in eq_state_units
1716 const_kappae=sigma_telectron*(1.d0+xfrac)/(2.0d0*mp)
1717 ! these are the units
1721
1722 end subroutine mhd_physical_units
1723
1724 subroutine mhd_check_w_semirelati(primitive,ixI^L,ixO^L,w,flag)
1726
1727 logical, intent(in) :: primitive
1728 logical, intent(inout) :: flag(ixi^s,1:nw)
1729 integer, intent(in) :: ixi^l, ixo^l
1730 double precision, intent(in) :: w(ixi^s,nw)
1731
1732 double precision :: tmp,b(1:ndir),v(1:ndir),factor
1733 integer :: ix^d
1734
1735 flag=.false.
1736 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1737
1738 if(mhd_energy) then
1739 if(primitive) then
1740 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1741 else
1742 if(mhd_internal_e) then
1743 {do ix^db=ixomin^db,ixomax^db \}
1744 if(w(ix^d,e_) < small_e) flag(ix^d,e_) = .true.
1745 {end do\}
1746 else
1747 {do ix^db=ixomin^db,ixomax^db \}
1748 ! Convert momentum to velocity
1749 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
1750 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
1751 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
1752 ! E=Bxv
1753 {^ifthreec
1754 b(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
1755 b(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
1756 b(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1757 }
1758 {^iftwoc
1759 b(1)=zero
1760 ! switch 3 with 2 to allow ^C from 1 to 2
1761 b(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1762 }
1763 {^ifonec
1764 b(1)=zero
1765 }
1766 ! Calculate internal e = e-eK-eB-eE
1767 tmp=w(ix^d,e_)-half*((^c&v(^c)**2+)*w(ix^d,rho_)&
1768 +(^c&w(ix^d,b^c_)**2+)+(^c&b(^c)**2+)*inv_squared_c)
1769 if(tmp<small_e) flag(ix^d,e_)=.true.
1770 {end do\}
1771 end if
1772 end if
1773 end if
1774
1775 end subroutine mhd_check_w_semirelati
1776
1777 subroutine mhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1779
1780 logical, intent(in) :: primitive
1781 integer, intent(in) :: ixi^l, ixo^l
1782 double precision, intent(in) :: w(ixi^s,nw)
1783 logical, intent(inout) :: flag(ixi^s,1:nw)
1784
1785 integer :: ix^d
1786
1787 flag=.false.
1788 {do ix^db=ixomin^db,ixomax^db\}
1789 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1790 if(primitive) then
1791 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1792 else
1793 if(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+&
1794 (^c&w(ix^d,b^c_)**2+))<small_e) flag(ix^d,e_) = .true.
1795 end if
1796 if(mhd_radiation_fld)then
1797 if(w(ix^d,r_e)<small_r_e) flag(ix^d,r_e) = .true.
1798 endif
1799 {end do\}
1800
1801 end subroutine mhd_check_w_origin
1802
1803 subroutine mhd_check_w_split(primitive,ixI^L,ixO^L,w,flag)
1805
1806 logical, intent(in) :: primitive
1807 integer, intent(in) :: ixi^l, ixo^l
1808 double precision, intent(in) :: w(ixi^s,nw)
1809 logical, intent(inout) :: flag(ixi^s,1:nw)
1810
1811 double precision :: tmp
1812 integer :: ix^d
1813
1814 flag=.false.
1815 {do ix^db=ixomin^db,ixomax^db\}
1816 tmp=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1817 if(tmp<small_density) flag(ix^d,rho_) = .true.
1818 if(primitive) then
1819 if(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)<small_pressure) flag(ix^d,e_) = .true.
1820 else
1821 tmp=w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/tmp+(^c&w(ix^d,b^c_)**2+))
1822 if(tmp+block%equi_vars(ix^d,equi_pe0_,0)*eos%inv_gamma_minus_1<small_e) flag(ix^d,e_) = .true.
1823 end if
1824 {end do\}
1825
1826 end subroutine mhd_check_w_split
1827
1828 subroutine mhd_check_w_noe(primitive,ixI^L,ixO^L,w,flag)
1830
1831 logical, intent(in) :: primitive
1832 integer, intent(in) :: ixi^l, ixo^l
1833 double precision, intent(in) :: w(ixi^s,nw)
1834 logical, intent(inout) :: flag(ixi^s,1:nw)
1835
1836 integer :: ix^d
1837
1838 flag=.false.
1839 {do ix^db=ixomin^db,ixomax^db\}
1840 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1841 {end do\}
1842
1843 end subroutine mhd_check_w_noe
1844
1845 subroutine mhd_check_w_inte(primitive,ixI^L,ixO^L,w,flag)
1847
1848 logical, intent(in) :: primitive
1849 integer, intent(in) :: ixi^l, ixo^l
1850 double precision, intent(in) :: w(ixi^s,nw)
1851 logical, intent(inout) :: flag(ixi^s,1:nw)
1852
1853 integer :: ix^d
1854
1855 flag=.false.
1856 {do ix^db=ixomin^db,ixomax^db\}
1857 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1858 if(primitive) then
1859 if(w(ix^d,p_) < small_pressure) flag(ix^d,e_) = .true.
1860 else
1861 if(w(ix^d,e_)<small_e) flag(ix^d,e_) = .true.
1862 end if
1863 {end do\}
1864
1865 end subroutine mhd_check_w_inte
1866
1867 subroutine mhd_check_w_hde(primitive,ixI^L,ixO^L,w,flag)
1869
1870 logical, intent(in) :: primitive
1871 integer, intent(in) :: ixi^l, ixo^l
1872 double precision, intent(in) :: w(ixi^s,nw)
1873 logical, intent(inout) :: flag(ixi^s,1:nw)
1874
1875 integer :: ix^d
1876
1877 flag=.false.
1878 {do ix^db=ixomin^db,ixomax^db\}
1879 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1880 if(primitive) then
1881 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1882 else
1883 if(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)<small_e) flag(ix^d,e_) = .true.
1884 end if
1885 {end do\}
1886
1887 end subroutine mhd_check_w_hde
1888
1889 subroutine mhd_bound_fip(primitive, ixI^L, ixO^L, w)
1891 logical, intent(in) :: primitive
1892 integer, intent(in) :: ixi^l, ixo^l
1893 double precision, intent(inout) :: w(ixi^s,1:nw)
1894
1895 double precision :: rho_safe(ixi^s), fip_prim(ixi^s)
1896
1897 if (.not. mhd_fip) return
1898
1899 if (primitive) then
1900 w(ixo^s,fip_) = min(maxfip, max(minfip, w(ixo^s,fip_)))
1901 else
1902 if (has_equi_rho_and_p) then
1903 rho_safe(ixo^s) = max(w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i), small_density)
1904 else
1905 rho_safe(ixo^s) = max(w(ixo^s,rho_), small_density)
1906 end if
1907 fip_prim(ixo^s) = w(ixo^s,fip_) / rho_safe(ixo^s)
1908 fip_prim(ixo^s) = min(maxfip, max(minfip, fip_prim(ixo^s)))
1909 w(ixo^s,fip_) = rho_safe(ixo^s) * fip_prim(ixo^s)
1910 end if
1911 end subroutine mhd_bound_fip
1912
1913 !> Transform internal energy to total energy
1914 subroutine mhd_ei_to_e(ixI^L,ixO^L,w,x)
1916 integer, intent(in) :: ixi^l, ixo^l
1917 double precision, intent(inout) :: w(ixi^s, nw)
1918 double precision, intent(in) :: x(ixi^s, 1:ndim)
1919
1920 integer :: ix^d
1921
1922 if(has_equi_rho_and_p) then
1923 {do ix^db=ixomin^db,ixomax^db\}
1924 ! Calculate e = ei + ek + eb
1925 w(ix^d,e_)=w(ix^d,e_)&
1926 +half*((^c&w(ix^d,m^c_)**2+)/&
1927 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
1928 +(^c&w(ix^d,b^c_)**2+))
1929 {end do\}
1930 else
1931 {do ix^db=ixomin^db,ixomax^db\}
1932 ! Calculate e = ei + ek + eb
1933 w(ix^d,e_)=w(ix^d,e_)&
1934 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
1935 +(^c&w(ix^d,b^c_)**2+))
1936 {end do\}
1937 end if
1938 end subroutine mhd_ei_to_e
1939
1940 !> Transform internal energy to hydrodynamic energy
1941 subroutine mhd_ei_to_e_hde(ixI^L,ixO^L,w,x)
1943 integer, intent(in) :: ixi^l, ixo^l
1944 double precision, intent(inout) :: w(ixi^s, nw)
1945 double precision, intent(in) :: x(ixi^s, 1:ndim)
1946
1947 integer :: ix^d
1948
1949 {do ix^db=ixomin^db,ixomax^db\}
1950 ! Calculate e = ei + ek
1951 w(ix^d,e_)=w(ix^d,e_)&
1952 +half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
1953 {end do\}
1954
1955 end subroutine mhd_ei_to_e_hde
1956
1957 !> Transform internal energy to total energy and velocity to momentum
1958 subroutine mhd_ei_to_e_semirelati(ixI^L,ixO^L,w,x)
1960 integer, intent(in) :: ixi^l, ixo^l
1961 double precision, intent(inout) :: w(ixi^s, nw)
1962 double precision, intent(in) :: x(ixi^s, 1:ndim)
1963
1964 w(ixo^s,p_)=w(ixo^s,e_)*eos%gamma_minus_1
1965 ! call eos%to_conserved(ixI^L,ixO^L,w,x)
1966 call eos%to_conserved(ixi^l,ixo^l,w,x)
1967
1968 end subroutine mhd_ei_to_e_semirelati
1969
1970 !> Transform total energy to internal energy
1971 subroutine mhd_e_to_ei(ixI^L,ixO^L,w,x)
1973 integer, intent(in) :: ixi^l, ixo^l
1974 double precision, intent(inout) :: w(ixi^s, nw)
1975 double precision, intent(in) :: x(ixi^s, 1:ndim)
1976
1977 integer :: ix^d
1978
1979 if(has_equi_rho_and_p) then
1980 {do ix^db=ixomin^db,ixomax^db\}
1981 ! Calculate ei = e - ek - eb
1982 w(ix^d,e_)=w(ix^d,e_)&
1983 -half*((^c&w(ix^d,m^c_)**2+)/&
1984 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
1985 +(^c&w(ix^d,b^c_)**2+))
1986 {end do\}
1987 else
1988 {do ix^db=ixomin^db,ixomax^db\}
1989 ! Calculate ei = e - ek - eb
1990 w(ix^d,e_)=w(ix^d,e_)&
1991 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
1992 +(^c&w(ix^d,b^c_)**2+))
1993 {end do\}
1994 end if
1995
1996 if(fix_small_values) then
1997 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei')
1998 end if
1999
2000 end subroutine mhd_e_to_ei
2001
2002 !> Wrapper: e_to_ei + cache log10(nH) in wextra for LTE TC fast path.
2003 !> During STS substeps density is invariant, so log10(nH) is computed once
2004 !> per STS cycle (in sts_before_first_cycle hook) and reused across all substeps.
2005 subroutine mhd_e_to_ei_and_cache_log_nh(ixI^L,ixO^L,w,x)
2007 integer, intent(in) :: ixi^l, ixo^l
2008 double precision, intent(inout) :: w(ixi^s, nw)
2009 double precision, intent(in) :: x(ixi^s, 1:ndim)
2010
2011 call mhd_e_to_ei(ixi^l,ixo^l,w,x)
2012 block%wextra(ixo^s, iw_log_nh) = dlog10(w(ixo^s, rho_) / eos%nH2rhoFactor)
2013 end subroutine mhd_e_to_ei_and_cache_log_nh
2014
2015 !> Transform hydrodynamic energy to internal energy
2016 subroutine mhd_e_to_ei_hde(ixI^L,ixO^L,w,x)
2018 integer, intent(in) :: ixi^l, ixo^l
2019 double precision, intent(inout) :: w(ixi^s, nw)
2020 double precision, intent(in) :: x(ixi^s, 1:ndim)
2021
2022 integer :: ix^d
2023
2024 {do ix^db=ixomin^db,ixomax^db\}
2025 ! Calculate ei = e - ek
2026 w(ix^d,e_)=w(ix^d,e_)&
2027 -half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2028 {end do\}
2029
2030 if(fix_small_values) then
2031 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei_hde')
2032 end if
2033
2034 end subroutine mhd_e_to_ei_hde
2035
2036 !> Transform total energy to internal energy and momentum to velocity
2037 subroutine mhd_e_to_ei_semirelati(ixI^L,ixO^L,w,x)
2039 integer, intent(in) :: ixi^l, ixo^l
2040 double precision, intent(inout) :: w(ixi^s, nw)
2041 double precision, intent(in) :: x(ixi^s, 1:ndim)
2042
2043 call eos%to_primitive(ixi^l,ixo^l,w,x)
2044 w(ixo^s,e_)=w(ixo^s,p_)*eos%inv_gamma_minus_1
2045
2046 end subroutine mhd_e_to_ei_semirelati
2047
2048 subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixI^L, ixO^L, subname)
2051 logical, intent(in) :: primitive
2052 integer, intent(in) :: ixi^l,ixo^l
2053 double precision, intent(inout) :: w(ixi^s,1:nw)
2054 double precision, intent(in) :: x(ixi^s,1:ndim)
2055 character(len=*), intent(in) :: subname
2056
2057 double precision :: e(ixi^s,1:ndir), pressure(ixi^s), v(ixi^s,1:ndir)
2058 double precision :: tmp, factor
2059 integer :: ix^d
2060 logical :: flag(ixi^s,1:nw)
2061
2062 flag=.false.
2063 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
2064
2065 if(mhd_energy) then
2066 if(primitive) then
2067 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
2068 else
2069 {do ix^db=ixomin^db,ixomax^db\}
2070 ! Convert momentum to velocity
2071 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2072 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2073 ^c&v(ix^d,^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2074 ! E=Bxv
2075 {^ifthreec
2076 e(ix^d,1)=w(ix^d,b2_)*v(ix^d,3)-w(ix^d,b3_)*v(ix^d,2)
2077 e(ix^d,2)=w(ix^d,b3_)*v(ix^d,1)-w(ix^d,b1_)*v(ix^d,3)
2078 e(ix^d,3)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2079 }
2080 {^iftwoc
2081 e(ix^d,1)=zero
2082 e(ix^d,2)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2083 }
2084 {^ifonec
2085 e(ix^d,1)=zero
2086 }
2087 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2088 pressure(ix^d)=eos%gamma_minus_1*(w(ix^d,e_)&
2089 -half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2090 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c))
2091 if(pressure(ix^d) < small_pressure) flag(ix^d,p_) = .true.
2092 {end do\}
2093 end if
2094 end if
2095
2096 if(any(flag)) then
2097 select case (small_values_method)
2098 case ("replace")
2099 {do ix^db=ixomin^db,ixomax^db\}
2100 if(flag(ix^d,rho_)) then
2101 w(ix^d,rho_) = small_density
2102 ^c&w(ix^d,m^c_)=0.d0\
2103 end if
2104 if(mhd_energy) then
2105 if(primitive) then
2106 if(flag(ix^d,e_)) w(ix^d,p_) = small_pressure
2107 else
2108 if(flag(ix^d,e_)) then
2109 w(ix^d,e_)=small_pressure*eos%inv_gamma_minus_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2110 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2111 end if
2112 end if
2113 end if
2114 {end do\}
2115 case ("average")
2116 ! do averaging of density
2117 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2118 if(mhd_energy) then
2119 if(primitive) then
2120 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2121 else
2122 w(ixo^s,e_)=pressure(ixo^s)
2123 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2124 {do ix^db=ixomin^db,ixomax^db\}
2125 w(ix^d,e_)=w(ix^d,p_)*eos%inv_gamma_minus_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2126 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2127 {end do\}
2128 end if
2129 end if
2130 case default
2131 if(.not.primitive) then
2132 ! change to primitive variables
2133 w(ixo^s,mom(1:ndir))=v(ixo^s,1:ndir)
2134 if(mhd_energy) w(ixo^s,e_)=pressure(ixo^s)
2135 end if
2136 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2137 end select
2138 end if
2139 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2140 end subroutine mhd_handle_small_values_semirelati
2141
2142 subroutine mhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
2145 logical, intent(in) :: primitive
2146 integer, intent(in) :: ixi^l,ixo^l
2147 double precision, intent(inout) :: w(ixi^s,1:nw)
2148 double precision, intent(in) :: x(ixi^s,1:ndim)
2149 character(len=*), intent(in) :: subname
2150
2151 integer :: ix^d
2152 logical :: flag(ixi^s,1:nw)
2153
2154 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2155
2156 if(any(flag)) then
2157 select case (small_values_method)
2158 case ("replace")
2159 {do ix^db=ixomin^db,ixomax^db\}
2160 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2161 {
2162 if(small_values_fix_iw(m^c_)) then
2163 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2164 end if
2165 \}
2166 if(primitive) then
2167 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2168 else
2169 if(flag(ix^d,e_)) &
2170 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+))
2171 end if
2172 if(mhd_radiation_fld)then
2173 if(small_values_fix_iw(r_e)) then
2174 if(flag(ix^d,r_e)) w(ix^d,r_e)=small_r_e
2175 endif
2176 endif
2177 {end do\}
2178 case ("average")
2179 ! do averaging of density
2180 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2181 if(primitive)then
2182 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2183 else
2184 ! do averaging of internal energy
2185 {do ix^db=iximin^db,iximax^db\}
2186 w(ix^d,e_)=w(ix^d,e_)&
2187 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2188 {end do\}
2189 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2190 ! convert back
2191 {do ix^db=iximin^db,iximax^db\}
2192 w(ix^d,e_)=w(ix^d,e_)&
2193 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2194 {end do\}
2195 end if
2196 if(mhd_radiation_fld) then
2197 call small_values_average(ixi^l, ixo^l, w, x, flag, r_e)
2198 endif
2199 case default
2200 if(.not.primitive) then
2201 !convert w to primitive
2202 {do ix^db=ixomin^db,ixomax^db\}
2203 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2204 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
2205 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)))
2206 {end do\}
2207 end if
2208 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2209 end select
2210 end if
2211 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2212 end subroutine mhd_handle_small_values_origin
2213
2214 subroutine mhd_handle_small_values_split(primitive, w, x, ixI^L, ixO^L, subname)
2217 logical, intent(in) :: primitive
2218 integer, intent(in) :: ixi^l,ixo^l
2219 double precision, intent(inout) :: w(ixi^s,1:nw)
2220 double precision, intent(in) :: x(ixi^s,1:ndim)
2221 character(len=*), intent(in) :: subname
2222
2223 double precision :: rho
2224 integer :: ix^d
2225 logical :: flag(ixi^s,1:nw)
2226
2227 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2228
2229 if(any(flag)) then
2230 select case (small_values_method)
2231 case ("replace")
2232 {do ix^db=ixomin^db,ixomax^db\}
2233 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2234 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density-block%equi_vars(ix^d,equi_rho0_,0)
2235 {
2236 if(small_values_fix_iw(m^c_)) then
2237 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2238 end if
2239 \}
2240 if(primitive) then
2241 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure-block%equi_vars(ix^d,equi_pe0_,0)
2242 else
2243 if(flag(ix^d,e_)) &
2244 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))&
2245 -block%equi_vars(ix^d,equi_pe0_,0)*eos%inv_gamma_minus_1
2246 end if
2247 {end do\}
2248 case ("average")
2249 ! do averaging of density
2250 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2251 if(primitive)then
2252 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2253 else
2254 ! do averaging of internal energy
2255 {do ix^db=iximin^db,iximax^db\}
2256 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2257 w(ix^d,e_)=w(ix^d,e_)&
2258 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2259 {end do\}
2260 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2261 ! convert back
2262 {do ix^db=iximin^db,iximax^db\}
2263 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2264 w(ix^d,e_)=w(ix^d,e_)&
2265 +half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2266 {end do\}
2267 end if
2268 case default
2269 if(.not.primitive) then
2270 !convert w to primitive
2271 {do ix^db=ixomin^db,ixomax^db\}
2272 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2273 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/rho\
2274 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)&
2275 -half*((^c&w(ix^d,m^c_)**2+)*rho+(^c&w(ix^d,b^c_)**2+)))
2276 {end do\}
2277 end if
2278 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2279 end select
2280 end if
2281 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2282 end subroutine mhd_handle_small_values_split
2283
2284 subroutine mhd_handle_small_values_inte(primitive, w, x, ixI^L, ixO^L, subname)
2287 logical, intent(in) :: primitive
2288 integer, intent(in) :: ixi^l,ixo^l
2289 double precision, intent(inout) :: w(ixi^s,1:nw)
2290 double precision, intent(in) :: x(ixi^s,1:ndim)
2291 character(len=*), intent(in) :: subname
2292
2293 integer :: ix^d
2294 logical :: flag(ixi^s,1:nw)
2295
2296 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2297
2298 if(any(flag)) then
2299 select case (small_values_method)
2300 case ("replace")
2301 {do ix^db=ixomin^db,ixomax^db\}
2302 if(flag(ix^d,rho_)) then
2303 w(ix^d,rho_)=small_density
2304 ^c&w(ix^d,m^c_)=0.d0\
2305 end if
2306 if(primitive) then
2307 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2308 else
2309 if(flag(ix^d,e_)) w(ix^d,e_)=small_e
2310 end if
2311 {end do\}
2312 case ("average")
2313 ! do averaging of density
2314 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2315 ! do averaging of internal energy
2316 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2317 case default
2318 if(.not.primitive) then
2319 !convert w to primitive
2320 {do ix^db=ixomin^db,ixomax^db\}
2321 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2322 w(ix^d,p_)=eos%gamma_minus_1*w(ix^d,e_)
2323 {end do\}
2324 end if
2325 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2326 end select
2327 end if
2328 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2329 end subroutine mhd_handle_small_values_inte
2330
2331 subroutine mhd_handle_small_values_noe(primitive, w, x, ixI^L, ixO^L, subname)
2334 logical, intent(in) :: primitive
2335 integer, intent(in) :: ixi^l,ixo^l
2336 double precision, intent(inout) :: w(ixi^s,1:nw)
2337 double precision, intent(in) :: x(ixi^s,1:ndim)
2338 character(len=*), intent(in) :: subname
2339
2340 integer :: ix^d
2341 logical :: flag(ixi^s,1:nw)
2342
2343 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2344
2345 if(any(flag)) then
2346 select case (small_values_method)
2347 case ("replace")
2348 {do ix^db=ixomin^db,ixomax^db\}
2349 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2350 {
2351 if(small_values_fix_iw(m^c_)) then
2352 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2353 end if
2354 \}
2355 {end do\}
2356 case ("average")
2357 ! do averaging of density
2358 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2359 case default
2360 if(.not.primitive) then
2361 !convert w to primitive
2362 {do ix^db=ixomin^db,ixomax^db\}
2363 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2364 {end do\}
2365 end if
2366 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2367 end select
2368 end if
2369 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2370 end subroutine mhd_handle_small_values_noe
2371
2372 subroutine mhd_handle_small_values_hde(primitive, w, x, ixI^L, ixO^L, subname)
2375 logical, intent(in) :: primitive
2376 integer, intent(in) :: ixi^l,ixo^l
2377 double precision, intent(inout) :: w(ixi^s,1:nw)
2378 double precision, intent(in) :: x(ixi^s,1:ndim)
2379 character(len=*), intent(in) :: subname
2380
2381 integer :: ix^d
2382 logical :: flag(ixi^s,1:nw)
2383
2384 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2385
2386 if(any(flag)) then
2387 select case (small_values_method)
2388 case ("replace")
2389 {do ix^db=ixomin^db,ixomax^db\}
2390 if(flag(ix^d,rho_)) then
2391 w(ix^d,rho_)=small_density
2392 ^c&w(ix^d,m^c_)=0.d0\
2393 end if
2394 if(primitive) then
2395 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2396 else
2397 if(flag(ix^d,e_)) w(ix^d,e_)=small_e+half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2398 end if
2399 {end do\}
2400 case ("average")
2401 ! do averaging of density
2402 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2403 ! do averaging of energy
2404 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2405 case default
2406 if(.not.primitive) then
2407 !convert w to primitive
2408 {do ix^db=ixomin^db,ixomax^db\}
2409 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2410 w(ix^d,p_)=eos%gamma_minus_1*(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_))
2411 {end do\}
2412 end if
2413 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2414 end select
2415 end if
2416 if (mhd_fip) call mhd_bound_fip(primitive, ixi^l, ixo^l, w)
2417 end subroutine mhd_handle_small_values_hde
2418
2419 !> Calculate v vector
2420 subroutine mhd_get_v(w,x,ixI^L,ixO^L,v)
2422
2423 integer, intent(in) :: ixi^l, ixo^l
2424 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
2425 double precision, intent(out) :: v(ixi^s,ndir)
2426
2427 double precision :: rho(ixi^s)
2428 integer :: idir
2429
2430 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2431
2432 rho(ixo^s)=1.d0/rho(ixo^s)
2433 ! Convert momentum to velocity
2434 do idir = 1, ndir
2435 v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
2436 end do
2437
2438 end subroutine mhd_get_v
2439
2440 !> Calculate csound**2 within ixO^L
2441 subroutine mhd_get_csound2(w,x,ixI^L,ixO^L,cs2)
2443
2444 integer, intent(in) :: ixi^l, ixo^l
2445 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2446 double precision, intent(inout) :: cs2(ixi^s)
2447
2448 double precision :: rho, inv_rho, ploc
2449 integer :: ix^d
2450
2451 {do ix^db=ixomin^db,ixomax^db \}
2452 if(has_equi_rho_and_p) then
2453 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))
2454 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0))
2455 else
2456 rho=w(ix^d,rho_)
2457 ploc=w(ix^d,p_)
2458 end if
2459 inv_rho=1.d0/rho
2460 ! sound speed**2
2461 cs2(ix^d)=eos%gamma*ploc*inv_rho
2462 {end do\}
2463 end subroutine mhd_get_csound2
2464
2465 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2466 subroutine mhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
2468
2469 integer, intent(in) :: ixi^l, ixo^l, idim
2470 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2471 double precision, intent(inout) :: cmax(ixi^s)
2472
2473 double precision :: rho, inv_rho, ploc, cfast2, avmincs2, b2, kmax
2474 double precision :: cs2(ixi^s)
2475 double precision, allocatable :: w_eos(:^d&,:)
2476 integer :: ix^d
2477 logical :: need_aug
2478
2479 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2480
2481 ! Sound speed squared via EoS dispatch (LTE+ionE -> Gamma_1 table; FI -> const gamma).
2482 ! If equi_rho0 / equi_pe0 are active, csound^2 is based on the total state.
2484 if (need_aug) then
2485 allocate(w_eos(ixi^s,nw))
2486 w_eos(ixo^s,:) = w(ixo^s,:)
2487 if (has_equi_rho_and_p) w_eos(ixo^s, rho_) = &
2488 w(ixo^s, rho_) + block%equi_vars(ixo^s, equi_rho0_, b0i)
2489 if (has_equi_rho_and_p) w_eos(ixo^s, p_) = &
2490 w(ixo^s, p_) + block%equi_vars(ixo^s, equi_pe0_, b0i)
2491 call eos%get_csound2(w_eos, x, ixi^l, ixo^l, cs2)
2492 deallocate(w_eos)
2493 else
2494 call eos%get_csound2(w, x, ixi^l, ixo^l, cs2)
2495 end if
2496
2497 if(b0field) then
2498 {do ix^db=ixomin^db,ixomax^db \}
2499 if(has_equi_rho_and_p) then
2500 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2501 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2502 else
2503 rho=w(ix^d,rho_)
2504 ploc=w(ix^d,p_)
2505 end if
2506 inv_rho=1.d0/rho
2507 cmax(ix^d)=cs2(ix^d)
2508 ! store |B|^2 in v
2509 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
2510 cfast2=b2*inv_rho+cmax(ix^d)
2511 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2512 if(avmincs2<zero) avmincs2=zero
2513 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2514 if(mhd_hall) then
2515 ! take the Hall velocity into account: most simple estimate, high k limit:
2516 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2517 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2518 end if
2519 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2520 {end do\}
2521 else
2522 {do ix^db=ixomin^db,ixomax^db \}
2523 if(has_equi_rho_and_p) then
2524 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2525 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2526 else
2527 rho=w(ix^d,rho_)
2528 ploc=w(ix^d,p_)
2529 end if
2530 inv_rho=1.d0/rho
2531 cmax(ix^d)=cs2(ix^d)
2532 ! store |B|^2 in v
2533 b2=(^c&w(ix^d,b^c_)**2+)
2534 cfast2=b2*inv_rho+cmax(ix^d)
2535 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2536 if(avmincs2<zero) avmincs2=zero
2537 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2538 if(mhd_hall) then
2539 ! take the Hall velocity into account: most simple estimate, high k limit:
2540 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2541 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2542 end if
2543 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2544 {end do\}
2545 end if
2546
2547 end subroutine mhd_get_cmax_origin
2548
2549 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2550 subroutine mhd_get_cmax_origin_noe(w,x,ixI^L,ixO^L,idim,cmax)
2553
2554 integer, intent(in) :: ixi^l, ixo^l, idim
2555 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2556 double precision, intent(inout) :: cmax(ixi^s)
2557
2558 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
2559 double precision :: adiabs(ixi^s), gammas(ixi^s)
2560 integer :: ix^d
2561
2562 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2563
2564 if(associated(usr_set_adiab)) then
2565 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
2566 else
2567 adiabs=mhd_adiab
2568 end if
2569 if(associated(usr_set_gamma)) then
2570 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
2571 else
2572 gammas=eos%gamma
2573 end if
2574 {do ix^db=ixomin^db,ixomax^db \}
2575 rho=w(ix^d,rho_)
2576 inv_rho=1.d0/rho
2577 ! sound speed**2
2578 cmax(ix^d)=gammas(ix^d)*adiabs(ix^d)*rho**(gammas(ix^d)-1.d0)
2579 ! store |B|^2 in v
2580 b2=(^c&w(ix^d,b^c_)**2+)
2581 cfast2=b2*inv_rho+cmax(ix^d)
2582 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2583 if(avmincs2<zero) avmincs2=zero
2584 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2585 if(mhd_hall) then
2586 ! take the Hall velocity into account: most simple estimate, high k limit:
2587 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2588 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2589 end if
2590 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2591 {end do\}
2592
2593 end subroutine mhd_get_cmax_origin_noe
2594
2595 !> Calculate cmax_idim for semirelativistic MHD
2596 subroutine mhd_get_cmax_semirelati(w,x,ixI^L,ixO^L,idim,cmax)
2598
2599 integer, intent(in) :: ixi^l, ixo^l, idim
2600 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2601 double precision, intent(inout):: cmax(ixi^s)
2602
2603 double precision :: csound, avmincs2, idim_alfven_speed2
2604 double precision :: inv_rho, alfven_speed2, gamma2
2605 integer :: ix^d
2606
2607 {do ix^db=ixomin^db,ixomax^db \}
2608 inv_rho=1.d0/w(ix^d,rho_)
2609 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
2610 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2611 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
2612 ! squared sound speed
2613 csound=eos%gamma*w(ix^d,p_)*inv_rho
2614 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
2615 ! Va_hat^2+a_hat^2 equation (57)
2616 ! equation (69)
2617 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2618 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2619 if(avmincs2<zero) avmincs2=zero
2620 ! equation (68) fast magnetosonic wave speed
2621 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2622 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
2623 {end do\}
2624
2625 end subroutine mhd_get_cmax_semirelati
2626
2627 !> Calculate cmax_idim for semirelativistic MHD
2628 subroutine mhd_get_cmax_semirelati_noe(w,x,ixI^L,ixO^L,idim,cmax)
2631
2632 integer, intent(in) :: ixi^l, ixo^l, idim
2633 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2634 double precision, intent(inout):: cmax(ixi^s)
2635
2636 double precision :: adiabs(ixi^s), gammas(ixi^s)
2637 double precision :: csound, avmincs2, idim_alfven_speed2
2638 double precision :: inv_rho, alfven_speed2, gamma2
2639 integer :: ix^d
2640
2641 if(associated(usr_set_adiab)) then
2642 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
2643 else
2644 adiabs=mhd_adiab
2645 end if
2646 if(associated(usr_set_gamma)) then
2647 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
2648 else
2649 gammas=eos%gamma
2650 end if
2651
2652 {do ix^db=ixomin^db,ixomax^db \}
2653 inv_rho=1.d0/w(ix^d,rho_)
2654 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
2655 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2656 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
2657 csound=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
2658 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
2659 ! Va_hat^2+a_hat^2 equation (57)
2660 ! equation (69)
2661 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2662 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2663 if(avmincs2<zero) avmincs2=zero
2664 ! equation (68) fast magnetosonic wave speed
2665 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2666 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
2667 {end do\}
2668
2669 end subroutine mhd_get_cmax_semirelati_noe
2670
2671 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
2672 subroutine mhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
2674 use mod_geometry
2675 integer, intent(in) :: ixi^l,ixo^l
2676 double precision, intent(in) :: x(ixi^s,1:ndim)
2677 ! in primitive form
2678 double precision, intent(inout) :: w(ixi^s,1:nw)
2679 double precision, intent(out) :: tco_local,tmax_local
2680
2681 double precision, parameter :: trac_delta=0.25d0
2682 double precision :: te(ixi^s),lts(ixi^s)
2683 double precision, dimension(1:ndim) :: bdir, bunitvec
2684 double precision, dimension(ixI^S,1:ndim) :: gradt
2685 double precision :: ltrc,ltrp,altr
2686 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
2687 integer :: jxp^l,hxp^l,ixp^l,ixq^l
2688
2689 if (eos%eos_type == 'LTE' .or. eos%eos_type == 'PI') then
2690 te(ixi^s) = w(ixi^s, te_)
2691 else
2692 call eos%get_Rfactor(w,x,ixi^l,ixi^l,te)
2693 te(ixi^s)=w(ixi^s,p_)/(te(ixi^s)*w(ixi^s,rho_))
2694 end if
2695 tco_local=zero
2696 tmax_local=maxval(te(ixo^s))
2697
2698 {^ifoned
2699 select case(mhd_trac_type)
2700 case(0)
2701 !> test case, fixed cutoff temperature
2702 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
2703 case(1)
2704 do ix1=ixomin1,ixomax1
2705 lts(ix1)=0.5d0*abs(te(ix1+1)-te(ix1-1))/te(ix1)
2706 if(lts(ix1)>trac_delta) then
2707 tco_local=max(tco_local,te(ix1))
2708 end if
2709 end do
2710 case(2)
2711 !> iijima et al. 2021, LTRAC method
2712 ltrc=1.5d0
2713 ltrp=4.d0
2714 ixp^l=ixo^l^ladd1;
2715 hxo^l=ixo^l-1;
2716 jxo^l=ixo^l+1;
2717 hxp^l=ixp^l-1;
2718 jxp^l=ixp^l+1;
2719 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
2720 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
2721 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
2722 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
2723 case default
2724 call mpistop("mhd_trac_type not allowed for 1D simulation")
2725 end select
2726 }
2727 {^nooned
2728 select case(mhd_trac_type)
2729 case(0)
2730 !> test case, fixed cutoff temperature
2731 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
2732 case(1,4,6)
2733 ! temperature gradient at cell centers
2734 do idims=1,ndim
2735 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
2736 end do
2737 if(mhd_trac_type .gt. 1) then
2738 ! B direction at block center
2739 bdir=zero
2740 if(b0field) then
2741 {do ixa^d=0,1\}
2742 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
2743 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))+block%B0(ixb^d,1:ndim,0)
2744 {end do\}
2745 else
2746 {do ixa^d=0,1\}
2747 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
2748 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))
2749 {end do\}
2750 end if
2751 {^iftwod
2752 if(bdir(1)/=0.d0) then
2753 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
2754 else
2755 block%special_values(3)=0.d0
2756 end if
2757 if(bdir(2)/=0.d0) then
2758 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
2759 else
2760 block%special_values(4)=0.d0
2761 end if
2762 }
2763 {^ifthreed
2764 if(bdir(1)/=0.d0) then
2765 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+&
2766 (bdir(3)/bdir(1))**2)
2767 else
2768 block%special_values(3)=0.d0
2769 end if
2770 if(bdir(2)/=0.d0) then
2771 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+&
2772 (bdir(3)/bdir(2))**2)
2773 else
2774 block%special_values(4)=0.d0
2775 end if
2776 if(bdir(3)/=0.d0) then
2777 block%special_values(5)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+&
2778 (bdir(2)/bdir(3))**2)
2779 else
2780 block%special_values(5)=0.d0
2781 end if
2782 }
2783 end if
2784 ! b unit vector: magnetic field direction vector
2785 block%special_values(1)=zero
2786 {do ix^db=ixomin^db,ixomax^db\}
2787 if(b0field) then
2788 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
2789 else
2790 ^d&bdir(^d)=w({ix^d},iw_mag(^d))\
2791 end if
2792 {^iftwod
2793 if(bdir(1)/=0.d0) then
2794 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
2795 else
2796 bunitvec(1)=0.d0
2797 end if
2798 if(bdir(2)/=0.d0) then
2799 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
2800 else
2801 bunitvec(2)=0.d0
2802 end if
2803 ! temperature length scale inversed
2804 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
2805 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
2806 }
2807 {^ifthreed
2808 if(bdir(1)/=0.d0) then
2809 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
2810 else
2811 bunitvec(1)=0.d0
2812 end if
2813 if(bdir(2)/=0.d0) then
2814 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
2815 else
2816 bunitvec(2)=0.d0
2817 end if
2818 if(bdir(3)/=0.d0) then
2819 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
2820 else
2821 bunitvec(3)=0.d0
2822 end if
2823 ! temperature length scale inversed
2824 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
2825 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
2826 }
2827 if(lts(ix^d)>trac_delta) then
2828 block%special_values(1)=max(block%special_values(1),te(ix^d))
2829 end if
2830 {end do\}
2831 block%special_values(2)=tmax_local
2832 case(2)
2833 !> iijima et al. 2021, LTRAC method
2834 ltrc=1.5d0
2835 ltrp=4.d0
2836 ixp^l=ixo^l^ladd2;
2837 ! temperature gradient at cell centers
2838 do idims=1,ndim
2839 ixq^l=ixp^l;
2840 hxp^l=ixp^l;
2841 jxp^l=ixp^l;
2842 select case(idims)
2843 {case(^d)
2844 ixqmin^d=ixqmin^d+1
2845 ixqmax^d=ixqmax^d-1
2846 hxpmax^d=ixpmin^d
2847 jxpmin^d=ixpmax^d
2848 \}
2849 end select
2850 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
2851 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
2852 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
2853 end do
2854 ! b unit vector: magnetic field direction vector
2855 if(b0field) then
2856 {do ix^db=ixpmin^db,ixpmax^db\}
2857 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
2858 {^iftwod
2859 if(bdir(1)/=0.d0) then
2860 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
2861 else
2862 bunitvec(1)=0.d0
2863 end if
2864 if(bdir(2)/=0.d0) then
2865 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
2866 else
2867 bunitvec(2)=0.d0
2868 end if
2869 }
2870 {^ifthreed
2871 if(bdir(1)/=0.d0) then
2872 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
2873 else
2874 bunitvec(1)=0.d0
2875 end if
2876 if(bdir(2)/=0.d0) then
2877 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
2878 else
2879 bunitvec(2)=0.d0
2880 end if
2881 if(bdir(3)/=0.d0) then
2882 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
2883 else
2884 bunitvec(3)=0.d0
2885 end if
2886 }
2887 ! temperature length scale inversed
2888 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
2889 ! fraction of cells size to temperature length scale
2890 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
2891 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
2892 {end do\}
2893 else
2894 {do ix^db=ixpmin^db,ixpmax^db\}
2895 {^iftwod
2896 if(w(ix^d,iw_mag(1))/=0.d0) then
2897 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)
2898 else
2899 bunitvec(1)=0.d0
2900 end if
2901 if(w(ix^d,iw_mag(2))/=0.d0) then
2902 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)
2903 else
2904 bunitvec(2)=0.d0
2905 end if
2906 }
2907 {^ifthreed
2908 if(w(ix^d,iw_mag(1))/=0.d0) then
2909 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+&
2910 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
2911 else
2912 bunitvec(1)=0.d0
2913 end if
2914 if(w(ix^d,iw_mag(2))/=0.d0) then
2915 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+&
2916 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
2917 else
2918 bunitvec(2)=0.d0
2919 end if
2920 if(w(ix^d,iw_mag(3))/=0.d0) then
2921 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+&
2922 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
2923 else
2924 bunitvec(3)=0.d0
2925 end if
2926 }
2927 ! temperature length scale inversed
2928 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
2929 ! fraction of cells size to temperature length scale
2930 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
2931 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
2932 {end do\}
2933 end if
2934
2935 ! need one ghost layer for thermal conductivity
2936 ixp^l=ixo^l^ladd1;
2937 {do ix^db=ixpmin^db,ixpmax^db\}
2938 {^iftwod
2939 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*bunitvec(1)**2+&
2940 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*bunitvec(2)**2)
2941 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
2942 }
2943 {^ifthreed
2944 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*bunitvec(1)**2+&
2945 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*bunitvec(2)**2+&
2946 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*bunitvec(3)**2)
2947 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
2948 }
2949 {end do\}
2950 case(3,5)
2951 !> do nothing here
2952 case default
2953 call mpistop("unknown mhd_trac_type")
2954 end select
2955 }
2956 end subroutine mhd_get_tcutoff
2957
2958 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
2959 subroutine mhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
2961
2962 integer, intent(in) :: ixi^l, ixo^l, idim
2963 double precision, intent(in) :: wprim(ixi^s, nw)
2964 double precision, intent(in) :: x(ixi^s,1:ndim)
2965 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
2966
2967 double precision :: csound(ixi^s,ndim)
2968 double precision, allocatable :: tmp(:^d&)
2969 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
2970
2971 hspeed=0.d0
2972 ixa^l=ixo^l^ladd1;
2973 allocate(tmp(ixa^s))
2974 do id=1,ndim
2975 if(has_equi_rho_and_p) then
2976 call mhd_get_csound_prim_split(wprim,x,ixi^l,ixa^l,id,tmp)
2977 else
2978 call mhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
2979 endif
2980 csound(ixa^s,id)=tmp(ixa^s)
2981 end do
2982 ixcmax^d=ixomax^d;
2983 ixcmin^d=ixomin^d+kr(idim,^d)-1;
2984 jxcmax^d=ixcmax^d+kr(idim,^d);
2985 jxcmin^d=ixcmin^d+kr(idim,^d);
2986 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))
2987
2988 do id=1,ndim
2989 if(id==idim) cycle
2990 ixamax^d=ixcmax^d+kr(id,^d);
2991 ixamin^d=ixcmin^d+kr(id,^d);
2992 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)))
2993 ixamax^d=ixcmax^d-kr(id,^d);
2994 ixamin^d=ixcmin^d-kr(id,^d);
2995 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)))
2996 end do
2997
2998 do id=1,ndim
2999 if(id==idim) cycle
3000 ixamax^d=jxcmax^d+kr(id,^d);
3001 ixamin^d=jxcmin^d+kr(id,^d);
3002 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)))
3003 ixamax^d=jxcmax^d-kr(id,^d);
3004 ixamin^d=jxcmin^d-kr(id,^d);
3005 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)))
3006 end do
3007 deallocate(tmp)
3008
3009 end subroutine mhd_get_h_speed
3010
3011 !> Estimating bounds for the minimum and maximum signal velocities without split
3012 subroutine mhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3014
3015 integer, intent(in) :: ixi^l, ixo^l, idim
3016 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3017 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3018 double precision, intent(in) :: x(ixi^s,1:ndim)
3019 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3020 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3021 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3022
3023 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3024 double precision :: umean, dmean, tmp1, tmp2, tmp3
3025 integer :: ix^d
3026
3027 select case (boundspeed)
3028 case (1)
3029 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3030 ! Methods for Fluid Dynamics" by Toro.
3031 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3032 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3033 if(present(cmin)) then
3034 {do ix^db=ixomin^db,ixomax^db\}
3035 tmp1=sqrt(wlp(ix^d,rho_))
3036 tmp2=sqrt(wrp(ix^d,rho_))
3037 tmp3=1.d0/(tmp1+tmp2)
3038 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3039 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3040 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3041 cmin(ix^d,1)=umean-dmean
3042 cmax(ix^d,1)=umean+dmean
3043 {end do\}
3044 if(h_correction) then
3045 {do ix^db=ixomin^db,ixomax^db\}
3046 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3047 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3048 {end do\}
3049 end if
3050 else
3051 {do ix^db=ixomin^db,ixomax^db\}
3052 tmp1=sqrt(wlp(ix^d,rho_))
3053 tmp2=sqrt(wrp(ix^d,rho_))
3054 tmp3=1.d0/(tmp1+tmp2)
3055 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3056 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3057 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3058 cmax(ix^d,1)=abs(umean)+dmean
3059 {end do\}
3060 end if
3061 case (2)
3062 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3063 call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
3064 if(present(cmin)) then
3065 {do ix^db=ixomin^db,ixomax^db\}
3066 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3067 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3068 {end do\}
3069 if(h_correction) then
3070 {do ix^db=ixomin^db,ixomax^db\}
3071 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3072 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3073 {end do\}
3074 end if
3075 else
3076 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3077 end if
3078 case (3)
3079 ! Miyoshi 2005 JCP 208, 315 equation (67)
3080 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3081 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3082 if(present(cmin)) then
3083 {do ix^db=ixomin^db,ixomax^db\}
3084 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3085 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3086 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3087 {end do\}
3088 if(h_correction) then
3089 {do ix^db=ixomin^db,ixomax^db\}
3090 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3091 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3092 {end do\}
3093 end if
3094 else
3095 {do ix^db=ixomin^db,ixomax^db\}
3096 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3097 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3098 {end do\}
3099 end if
3100 end select
3101
3102 end subroutine mhd_get_cbounds
3103
3104 !> Estimating bounds for the minimum and maximum signal velocities without split
3105 subroutine mhd_get_cbounds_semirelati(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3107
3108 integer, intent(in) :: ixi^l, ixo^l, idim
3109 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3110 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3111 double precision, intent(in) :: x(ixi^s,1:ndim)
3112 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3113 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3114 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3115
3116 double precision, dimension(ixO^S) :: csoundl, csoundr, gamma2l, gamma2r
3117 integer :: ix^d
3118
3119 ! Miyoshi 2005 JCP 208, 315 equation (67)
3120 if(mhd_energy) then
3121 call mhd_get_csound_semirelati(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3122 call mhd_get_csound_semirelati(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3123 else
3124 call mhd_get_csound_semirelati_noe(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3125 call mhd_get_csound_semirelati_noe(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3126 end if
3127 if(present(cmin)) then
3128 {do ix^db=ixomin^db,ixomax^db\}
3129 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3130 cmin(ix^d,1)=min(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))-csoundl(ix^d)
3131 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3132 {end do\}
3133 else
3134 {do ix^db=ixomin^db,ixomax^db\}
3135 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3136 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3137 {end do\}
3138 end if
3139
3140 end subroutine mhd_get_cbounds_semirelati
3141
3142 !> Estimating bounds for the minimum and maximum signal velocities with rho split
3143 subroutine mhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3145
3146 integer, intent(in) :: ixi^l, ixo^l, idim
3147 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3148 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3149 double precision, intent(in) :: x(ixi^s,1:ndim)
3150 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3151 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3152 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3153
3154 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3155 double precision :: umean, dmean, tmp1, tmp2, tmp3
3156 integer :: ix^d
3157
3158 select case (boundspeed)
3159 case (1)
3160 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3161 ! Methods for Fluid Dynamics" by Toro.
3162 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3163 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3164 if(present(cmin)) then
3165 {do ix^db=ixomin^db,ixomax^db\}
3166 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3167 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3168 tmp3=1.d0/(tmp1+tmp2)
3169 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3170 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3171 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3172 cmin(ix^d,1)=umean-dmean
3173 cmax(ix^d,1)=umean+dmean
3174 {end do\}
3175 if(h_correction) then
3176 {do ix^db=ixomin^db,ixomax^db\}
3177 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3178 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3179 {end do\}
3180 end if
3181 else
3182 {do ix^db=ixomin^db,ixomax^db\}
3183 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3184 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3185 tmp3=1.d0/(tmp1+tmp2)
3186 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3187 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3188 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3189 cmax(ix^d,1)=abs(umean)+dmean
3190 {end do\}
3191 end if
3192 case (2)
3193 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3194 call mhd_get_csound_prim_split(wmean,x,ixi^l,ixo^l,idim,csoundr)
3195 if(present(cmin)) then
3196 {do ix^db=ixomin^db,ixomax^db\}
3197 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3198 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3199 {end do\}
3200 if(h_correction) then
3201 {do ix^db=ixomin^db,ixomax^db\}
3202 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3203 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3204 {end do\}
3205 end if
3206 else
3207 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3208 end if
3209 case (3)
3210 ! Miyoshi 2005 JCP 208, 315 equation (67)
3211 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3212 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3213 if(present(cmin)) then
3214 {do ix^db=ixomin^db,ixomax^db\}
3215 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3216 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3217 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3218 {end do\}
3219 if(h_correction) then
3220 {do ix^db=ixomin^db,ixomax^db\}
3221 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3222 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3223 {end do\}
3224 end if
3225 else
3226 {do ix^db=ixomin^db,ixomax^db\}
3227 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3228 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3229 {end do\}
3230 end if
3231 end select
3232
3233 end subroutine mhd_get_cbounds_split_rho
3234
3235 !> prepare velocities for ct methods
3236 subroutine mhd_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3238
3239 integer, intent(in) :: ixi^l, ixo^l, idim
3240 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3241 double precision, intent(in) :: cmax(ixi^s)
3242 double precision, intent(in), optional :: cmin(ixi^s)
3243 type(ct_velocity), intent(inout):: vcts
3244
3245 end subroutine mhd_get_ct_velocity_average
3246
3247 subroutine mhd_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3249
3250 integer, intent(in) :: ixi^l, ixo^l, idim
3251 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3252 double precision, intent(in) :: cmax(ixi^s)
3253 double precision, intent(in), optional :: cmin(ixi^s)
3254 type(ct_velocity), intent(inout):: vcts
3255
3256 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
3257 ! get average normal velocity at cell faces
3258 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
3259
3260 end subroutine mhd_get_ct_velocity_contact
3261
3262 subroutine mhd_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3264
3265 integer, intent(in) :: ixi^l, ixo^l, idim
3266 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3267 double precision, intent(in) :: cmax(ixi^s)
3268 double precision, intent(in), optional :: cmin(ixi^s)
3269 type(ct_velocity), intent(inout):: vcts
3270
3271 integer :: idime,idimn
3272
3273 if(.not.allocated(vcts%vbarC)) then
3274 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
3275 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
3276 end if
3277 ! Store magnitude of characteristics
3278 if(present(cmin)) then
3279 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
3280 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3281 else
3282 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3283 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
3284 end if
3285
3286 idimn=mod(idim,ndir)+1 ! 'Next' direction
3287 idime=mod(idim+1,ndir)+1 ! Electric field direction
3288 ! Store velocities
3289 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
3290 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
3291 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
3292 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3293 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3294
3295 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
3296 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
3297 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
3298 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3299 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3300
3301 end subroutine mhd_get_ct_velocity_hll
3302
3303 !> Calculate modified squared sound speed for FLD
3304 !> NOTE: only for diagnostic purposes, unused subroutine
3305 subroutine mhd_get_csrad2(w,x,ixI^L,ixO^L,csound)
3307
3308 integer, intent(in) :: ixi^l, ixo^l
3309 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3310 double precision, intent(out):: csound(ixi^s)
3311
3312 double precision :: wprim(ixi^s, nw)
3313
3314 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
3315 call eos%to_primitive(ixi^l,ixo^l,wprim,x)
3316 call mhd_get_csrad2_prim(wprim,x,ixi^l,ixo^l,csound)
3317
3318 end subroutine mhd_get_csrad2
3319
3320
3321 !> Calculate modified squared fast wave speed for FLD
3322 !> NOTE: w is primitive on entry here!
3323 !> NOTE: used in FLD module as phys_get_csrad2
3324 subroutine mhd_get_csrad2_prim(w,x,ixI^L,ixO^L,csound)
3326
3327 integer, intent(in) :: ixi^l, ixo^l
3328 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3329 double precision, intent(out):: csound(ixi^s)
3330
3331 double precision :: inv_rho, b2
3332 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
3333 double precision :: prad_max(ixi^s)
3334 integer :: ix^d
3335
3336 call mhd_get_pradiation_from_prim(w, x, ixi^l, ixo^l, prad_tensor)
3337
3338 if(b0field) then
3339 {do ix^db=ixomin^db,ixomax^db \}
3340 inv_rho=1.d0/w(ix^d,rho_)
3341 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3342 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3343 csound(ix^d)=(eos%gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3344 {end do\}
3345 else
3346 {do ix^db=ixomin^db,ixomax^db \}
3347 inv_rho=1.d0/w(ix^d,rho_)
3348 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3349 b2=(^c&w(ix^d,b^c_)**2+)
3350 csound(ix^d)=(eos%gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3351 {end do\}
3352 end if
3353
3354 if(minval(csound(ixo^s))<smalldouble)then
3355 print *,'issue with squared speed and rad pressure'
3356 print *,minval(csound(ixo^s))
3357 print *,minval(prad_max(ixo^s))
3358 call mpistop("negative squared speed in get_csrad2 for dt")
3359 endif
3360
3361 end subroutine mhd_get_csrad2_prim
3362
3363 !> Calculate fast magnetosonic wave speed
3364 subroutine mhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
3367
3368 integer, intent(in) :: ixi^l, ixo^l, idim
3369 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3370 double precision, intent(out):: csound(ixo^s)
3371
3372 double precision :: adiabs(ixi^s), gammas(ixi^s)
3373 double precision :: inv_rho, cfast2, avmincs2, b2, kmax
3374 double precision :: cs2(ixi^s)
3375 integer :: ix^d
3376
3377 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3378
3379 if(.not.mhd_energy) then
3380 if(associated(usr_set_adiab)) then
3381 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3382 else
3383 adiabs=mhd_adiab
3384 end if
3385 if(associated(usr_set_gamma)) then
3386 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3387 else
3388 gammas=eos%gamma
3389 end if
3390 end if
3391
3392 ! Sound speed squared via EoS dispatch (honours LTE+ionE Gamma_1 table).
3393 if(mhd_energy) then
3394 call eos%get_csound2(w, x, ixi^l, ixo^l, cs2)
3395 end if
3396
3397 ! store |B|^2 in v
3398 if(b0field) then
3399 {do ix^db=ixomin^db,ixomax^db \}
3400 inv_rho=1.d0/w(ix^d,rho_)
3401 if(mhd_energy) then
3402 csound(ix^d)=cs2(ix^d)
3403 else
3404 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3405 end if
3406 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3407 cfast2=b2*inv_rho+csound(ix^d)
3408 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3409 block%B0(ix^d,idim,b0i))**2*inv_rho
3410 if(avmincs2<zero) avmincs2=zero
3411 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3412 if(mhd_hall) then
3413 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3414 end if
3415 {end do\}
3416 else
3417 {do ix^db=ixomin^db,ixomax^db \}
3418 inv_rho=1.d0/w(ix^d,rho_)
3419 if(mhd_energy) then
3420 csound(ix^d)=cs2(ix^d)
3421 else
3422 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3423 end if
3424 b2=(^c&w(ix^d,b^c_)**2+)
3425 cfast2=b2*inv_rho+csound(ix^d)
3426 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3427 if(avmincs2<zero) avmincs2=zero
3428 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3429 if(mhd_hall) then
3430 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3431 end if
3432 {end do\}
3433 end if
3434
3435 end subroutine mhd_get_csound_prim
3436
3437 !> Calculate fast magnetosonic wave speed when rho and p are split
3438 !> hence has_equi_rho_and_p=T
3439 subroutine mhd_get_csound_prim_split(w,x,ixI^L,ixO^L,idim,csound)
3441
3442 integer, intent(in) :: ixi^l, ixo^l, idim
3443 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3444 double precision, intent(out):: csound(ixo^s)
3445
3446 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
3447 integer :: ix^d
3448
3449 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3450
3451 ! store |B|^2 in v
3452 if(b0field) then
3453 {do ix^db=ixomin^db,ixomax^db \}
3454 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3455 inv_rho=1.d0/rho
3456 csound(ix^d)=eos%gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3457 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3458 cfast2=b2*inv_rho+csound(ix^d)
3459 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3460 block%B0(ix^d,idim,b0i))**2*inv_rho
3461 if(avmincs2<zero) avmincs2=zero
3462 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3463 if(mhd_hall) then
3464 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3465 end if
3466 {end do\}
3467 else
3468 {do ix^db=ixomin^db,ixomax^db \}
3469 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3470 inv_rho=1.d0/rho
3471 csound(ix^d)=eos%gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3472 b2=(^c&w(ix^d,b^c_)**2+)
3473 cfast2=b2*inv_rho+csound(ix^d)
3474 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3475 if(avmincs2<zero) avmincs2=zero
3476 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3477 if(mhd_hall) then
3478 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3479 end if
3480 {end do\}
3481 end if
3482
3483 end subroutine mhd_get_csound_prim_split
3484
3485 !> Calculate cmax_idim for semirelativistic MHD
3486 subroutine mhd_get_csound_semirelati(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3488
3489 integer, intent(in) :: ixi^l, ixo^l, idim
3490 ! here w is primitive variables
3491 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3492 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3493
3494 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3495 integer :: ix^d
3496
3497 {do ix^db=ixomin^db,ixomax^db\}
3498 inv_rho = 1.d0/w(ix^d,rho_)
3499 ! squared sound speed
3500 csound(ix^d)=eos%gamma*w(ix^d,p_)*inv_rho
3501 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3502 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3503 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3504 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3505 ! Va_hat^2+a_hat^2 equation (57)
3506 ! equation (69)
3507 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3508 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3509 if(avmincs2<zero) avmincs2=zero
3510 ! equation (68) fast magnetosonic speed
3511 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3512 {end do\}
3513
3514 end subroutine mhd_get_csound_semirelati
3515
3516 !> Calculate cmax_idim for semirelativistic MHD
3517 subroutine mhd_get_csound_semirelati_noe(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3520
3521 integer, intent(in) :: ixi^l, ixo^l, idim
3522 ! here w is primitive variables
3523 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3524 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3525
3526 double precision :: adiabs(ixi^s), gammas(ixi^s)
3527 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3528 integer :: ix^d
3529
3530 if(associated(usr_set_adiab)) then
3531 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3532 else
3533 adiabs=mhd_adiab
3534 end if
3535 if(associated(usr_set_gamma)) then
3536 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3537 else
3538 gammas=eos%gamma
3539 end if
3540 {do ix^db=ixomin^db,ixomax^db\}
3541 inv_rho = 1.d0/w(ix^d,rho_)
3542 ! squared sound speed
3543 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3544 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3545 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3546 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3547 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3548 ! Va_hat^2+a_hat^2 equation (57)
3549 ! equation (69)
3550 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3551 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3552 if(avmincs2<zero) avmincs2=zero
3553 ! equation (68) fast magnetosonic speed
3554 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3555 {end do\}
3556
3557 end subroutine mhd_get_csound_semirelati_noe
3558
3559 ! Thermal pressure and temperature subroutines (mhd_get_pthermal_noe,
3560 ! _inte, _origin, _semirelati, _hde, _LTE, mhd_get_temperature_from_eint,
3561 ! _from_etot, _from_etot_LTE, _with_equi, _equi, mhd_get_rho_equi,
3562 ! mhd_get_pe_equi) are defined in mod_mhd_eos.t. eos%get_temperature_from_{etot,eint}
3563 ! and tc_fl / rc_fl / te_fl_mhd hooks are bound by bind_eos_to_source.
3564
3565
3566 !> Calculate radiation pressure within ixO^L
3567 subroutine mhd_get_pradiation_from_prim(w, x, ixI^L, ixO^L, prad)
3569 use mod_fld
3570 integer, intent(in) :: ixi^l, ixo^l
3571 double precision, intent(in) :: w(ixi^s, 1:nw)
3572 double precision, intent(in) :: x(ixi^s, 1:ndim)
3573 double precision, intent(out):: prad(ixi^s, 1:ndim, 1:ndim)
3574
3575 call fld_get_radpress(w, x, ixi^l, ixo^l, prad, fld_fl)
3576
3577 end subroutine mhd_get_pradiation_from_prim
3578
3579 !> Calculates the sum of the gas pressure and the max Prad tensor element
3580 subroutine mhd_get_pthermal_plus_pradiation(w, x, ixI^L, ixO^L, pth_plus_prad)
3582 integer, intent(in) :: ixi^l, ixo^l
3583 double precision, intent(in) :: w(ixi^s, 1:nw)
3584 double precision, intent(in) :: x(ixi^s, 1:ndim)
3585 double precision, intent(out) :: pth_plus_prad(ixi^s)
3586
3587 double precision :: wprim(ixi^s, 1:nw)
3588 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
3589 double precision :: prad_max(ixi^s)
3590 integer :: ix^d
3591
3592 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
3593 call eos%to_primitive(ixi^l,ixo^l,wprim,x)
3594 call mhd_get_pradiation_from_prim(wprim, x, ixi^l, ixo^l, prad_tensor)
3595 {do ix^d = ixomin^d,ixomax^d\}
3596 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3597 {enddo\}
3598 pth_plus_prad(ixo^s) = wprim(ixo^s,p_) + prad_max(ixo^s)
3600
3601 !> Calculates radiation temperature
3602 subroutine mhd_get_trad(w, x, ixI^L, ixO^L, trad)
3604 use mod_constants
3605
3606 integer, intent(in) :: ixi^l, ixo^l
3607 double precision, intent(in) :: w(ixi^s, 1:nw)
3608 double precision, intent(in) :: x(ixi^s, 1:ndim)
3609 double precision, intent(out):: trad(ixi^s)
3610
3611 trad(ixi^s) = (w(ixi^s,r_e)/arad_norm)**(1.d0/4.d0)
3612
3613 end subroutine mhd_get_trad
3614
3615 !> Calculate fluxes within ixO^L without any splitting
3616 subroutine mhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
3618 use mod_geometry
3619
3620 integer, intent(in) :: ixi^l, ixo^l, idim
3621 ! conservative w
3622 double precision, intent(in) :: wc(ixi^s,nw)
3623 ! primitive w
3624 double precision, intent(in) :: w(ixi^s,nw)
3625 double precision, intent(in) :: x(ixi^s,1:ndim)
3626 double precision,intent(out) :: f(ixi^s,nwflux)
3627
3628 double precision :: vhall(ixi^s,1:ndir)
3629 double precision :: ptotal
3630 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
3631 double precision :: bvec(ixi^s,1:ndir)
3632 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
3633 double precision :: nperp(ixi^s,1:ndir)
3634 logical :: use_perp_flux
3635 integer :: iw, ix^d, idir
3636
3637 if(mhd_internal_e) then
3638 {do ix^db=ixomin^db,ixomax^db\}
3639 ! Get flux of density
3640 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3641 ! f_i[m_k]=v_i*m_k-b_k*b_i
3642 ^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_)\
3643 ! normal one includes total pressure
3644 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
3645 ! Get flux of internal energy
3646 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
3647 ! f_i[b_k]=v_i*b_k-v_k*b_i
3648 ^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_)\
3649 {end do\}
3650 else
3651 {do ix^db=ixomin^db,ixomax^db\}
3652 ! Get flux of density
3653 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3654 ! f_i[m_k]=v_i*m_k-b_k*b_i
3655 ^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_)\
3656 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
3657 ! normal one includes total pressure
3658 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
3659 ! Get flux of total energy
3660 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
3661 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
3662 -w(ix^d,mag(idim))*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
3663 ! f_i[b_k]=v_i*b_k-v_k*b_i
3664 ^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_)\
3665 {end do\}
3666 end if
3667 if(mhd_hall) then
3668 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3669 {do ix^db=ixomin^db,ixomax^db\}
3670 if(total_energy) then
3671 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
3672 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)**2+)&
3673 -w(ix^d,mag(idim))*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
3674 end if
3675 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3676 ^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))\
3677 {end do\}
3678 end if
3679
3680 if(mhd_glm) then
3681 {do ix^db=ixomin^db,ixomax^db\}
3682 f(ix^d,mag(idim))=w(ix^d,psi_)
3683 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3684 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3685 {end do\}
3686 end if
3687
3688 if(mhd_radiation_fld) then
3689 {do ix^db=ixomin^db,ixomax^db\}
3690 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
3691 {end do\}
3692 endif
3693
3694 if (mhd_fip) then
3695 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
3696 end if
3697 ! Get flux of tracer
3698 do iw=1,mhd_n_tracer
3699 {do ix^db=ixomin^db,ixomax^db\}
3700 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
3701 {end do\}
3702 end do
3703
3704 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
3705 trim(mhd_hyperbolic_tc_perp_mode)/='off'
3706 if(use_perp_flux) then
3707 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
3708 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
3709 if(has_equi_rho_and_p) then
3710 te(ixi^s)=(w(ixi^s,p_)+block%equi_vars(ixi^s,equi_pe0_,b0i)) / &
3711 (r(ixi^s)*rho_loc(ixi^s))
3712 else
3713 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
3714 end if
3715 {do ix^db=ixomin^db,ixomax^db\}
3716 do idir=1,ndir
3717 bvec(ix^d,idir)=w(ix^d,mag(idir))
3718 end do
3719 {end do\}
3720 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
3721 end if
3722
3723 if(mhd_hyperbolic_tc) then
3724 {do ix^db=ixomin^db,ixomax^db\}
3725 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
3726 f(ix^d,qpar_)=zero
3727 if(use_perp_flux) then
3728 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
3729 f(ix^d,qperp_)=zero
3730 end if
3731 {end do\}
3732 end if
3733 end subroutine mhd_get_flux
3734
3735 !> Calculate fluxes within ixO^L for case without energy equation, hence without splitting
3736 !> and assuming polytropic closure
3737 subroutine mhd_get_flux_noe(wC,w,x,ixI^L,ixO^L,idim,f)
3739 use mod_geometry
3741
3742 integer, intent(in) :: ixi^l, ixo^l, idim
3743 ! conservative w
3744 double precision, intent(in) :: wc(ixi^s,nw)
3745 ! primitive w
3746 double precision, intent(in) :: w(ixi^s,nw)
3747 double precision, intent(in) :: x(ixi^s,1:ndim)
3748 double precision,intent(out) :: f(ixi^s,nwflux)
3749
3750 double precision :: vhall(ixi^s,1:ndir)
3751 double precision :: adiabs(ixi^s), gammas(ixi^s)
3752 integer :: iw, ix^d
3753
3754 if(associated(usr_set_adiab)) then
3755 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3756 else
3757 adiabs=mhd_adiab
3758 end if
3759 if(associated(usr_set_gamma)) then
3760 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3761 else
3762 gammas=eos%gamma
3763 end if
3764 {do ix^db=ixomin^db,ixomax^db\}
3765 ! Get flux of density
3766 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3767 ! f_i[m_k]=v_i*m_k-b_k*b_i
3768 ^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_)\
3769 ! normal one includes total pressure
3770 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+)
3771 ! f_i[b_k]=v_i*b_k-v_k*b_i
3772 ^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_)\
3773 {end do\}
3774 if(mhd_hall) then
3775 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3776 {do ix^db=ixomin^db,ixomax^db\}
3777 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3778 ^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))\
3779 {end do\}
3780 end if
3781 if(mhd_glm) then
3782 {do ix^db=ixomin^db,ixomax^db\}
3783 f(ix^d,mag(idim))=w(ix^d,psi_)
3784 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3785 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3786 {end do\}
3787 end if
3788 if (mhd_fip) then
3789 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
3790 end if
3791 ! Get flux of tracer
3792 do iw=1,mhd_n_tracer
3793 {do ix^db=ixomin^db,ixomax^db\}
3794 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
3795 {end do\}
3796 end do
3797 end subroutine mhd_get_flux_noe
3798
3799 !> Calculate fluxes with hydrodynamic energy equation
3800 subroutine mhd_get_flux_hde(wC,w,x,ixI^L,ixO^L,idim,f)
3802 use mod_geometry
3803
3804 integer, intent(in) :: ixi^l, ixo^l, idim
3805 ! conservative w
3806 double precision, intent(in) :: wc(ixi^s,nw)
3807 ! primitive w
3808 double precision, intent(in) :: w(ixi^s,nw)
3809 double precision, intent(in) :: x(ixi^s,1:ndim)
3810 double precision,intent(out) :: f(ixi^s,nwflux)
3811
3812 double precision :: vhall(ixi^s,1:ndir)
3813 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
3814 double precision :: bvec(ixi^s,1:ndir)
3815 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
3816 double precision :: nperp(ixi^s,1:ndir)
3817 logical :: use_perp_flux
3818 integer :: iw, ix^d, idir
3819
3820 {do ix^db=ixomin^db,ixomax^db\}
3821 ! Get flux of density
3822 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3823 ! f_i[m_k]=v_i*m_k-b_k*b_i
3824 ^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_)\
3825 ! normal one includes total pressure
3826 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
3827 ! Get flux of energy
3828 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+w(ix^d,p_))
3829 ! f_i[b_k]=v_i*b_k-v_k*b_i
3830 ^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_)\
3831 {end do\}
3832 if(mhd_hall) then
3833 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3834 {do ix^db=ixomin^db,ixomax^db\}
3835 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3836 ^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))\
3837 {end do\}
3838 end if
3839 if(mhd_glm) then
3840 {do ix^db=ixomin^db,ixomax^db\}
3841 f(ix^d,mag(idim))=w(ix^d,psi_)
3842 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3843 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3844 {end do\}
3845 end if
3846 if (mhd_fip) then
3847 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
3848 end if
3849 ! Get flux of tracer
3850 do iw=1,mhd_n_tracer
3851 {do ix^db=ixomin^db,ixomax^db\}
3852 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
3853 {end do\}
3854 end do
3855 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
3856 trim(mhd_hyperbolic_tc_perp_mode)/='off'
3857 if(use_perp_flux) then
3858 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
3859 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
3860 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
3861 {do ix^db=ixomin^db,ixomax^db\}
3862 do idir=1,ndir
3863 bvec(ix^d,idir)=w(ix^d,mag(idir))
3864 end do
3865 {end do\}
3866 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
3867 end if
3868 if(mhd_hyperbolic_tc) then
3869 {do ix^db=ixomin^db,ixomax^db\}
3870 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
3871 f(ix^d,qpar_)=zero
3872 if(use_perp_flux) then
3873 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
3874 f(ix^d,qperp_)=zero
3875 end if
3876 {end do\}
3877 end if
3878 end subroutine mhd_get_flux_hde
3879
3880 !> Calculate fluxes within ixO^L with possible splitting
3881 !> this covers four cases: B0field=T and mhd_internal_e=T (where has_equi_rho_and_p=F)
3882 !> B0field=T and has_equi_rho_and_p=F for total_energy=T
3883 !> B0field=F and has_equi_rho_and_p=T for total_energy=T
3884 !> B0field=T and has_equi_rho_and_p=T for total_energy=T
3885 subroutine mhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
3887 use mod_geometry
3888
3889 integer, intent(in) :: ixi^l, ixo^l, idim
3890 ! conservative w
3891 double precision, intent(in) :: wc(ixi^s,nw)
3892 ! primitive w
3893 double precision, intent(in) :: w(ixi^s,nw)
3894 double precision, intent(in) :: x(ixi^s,1:ndim)
3895 double precision,intent(out) :: f(ixi^s,nwflux)
3896
3897 double precision :: vhall(ixi^s,1:ndir)
3898 double precision :: ptotal, btotal(ixo^s,1:ndir)
3899 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
3900 double precision :: bvec(ixi^s,1:ndir)
3901 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
3902 double precision :: nperp(ixi^s,1:ndir)
3903 logical :: use_perp_flux
3904 integer :: iw, ix^d, idir
3905
3906 {do ix^db=ixomin^db,ixomax^db\}
3907 ! Get flux of density
3908 if(has_equi_rho_and_p) then
3909 f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3910 else
3911 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
3912 end if
3913
3914 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
3915
3916 if(b0field) then
3917 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)+block%B0(ix^d,^c,idim)\
3918 ptotal=ptotal+(^c&w(ix^d,b^c_)*block%B0(ix^d,^c,idim)+)
3919 ! Get flux of momentum and magnetic field
3920 ! f_i[m_k]=v_i*m_k-b_k*b_i
3921 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-&
3922 btotal(ix^d,idim)*w(ix^d,b^c_)-w(ix^d,mag(idim))*block%B0(ix^d,^c,idim)\
3923 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
3924 else
3925 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)\
3926 ! Get flux of momentum and magnetic field
3927 ! f_i[m_k]=v_i*m_k-b_k*b_i
3928 ^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_)\
3929 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
3930 end if
3931 ! f_i[b_k]=v_i*b_k-v_k*b_i
3932 ^c&f(ix^d,b^c_)=w(ix^d,mom(idim))*btotal(ix^d,^c)-btotal(ix^d,idim)*w(ix^d,m^c_)\
3933
3934 ! Get flux of energy
3935 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
3936 if(mhd_internal_e) then
3937 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
3938 else
3939 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
3940 -btotal(ix^d,idim)*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
3941 end if
3942 {end do\}
3943
3944 if(mhd_glm) then
3945 {do ix^db=ixomin^db,ixomax^db\}
3946 f(ix^d,mag(idim))=w(ix^d,psi_)
3947 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3948 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
3949 {end do\}
3950 end if
3951
3952 if(mhd_radiation_fld) then
3953 {do ix^db=ixomin^db,ixomax^db\}
3954 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
3955 {end do\}
3956 endif
3957
3958 if(mhd_hall) then
3959 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
3960 {do ix^db=ixomin^db,ixomax^db\}
3961 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3962 ^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)\
3963 if(total_energy) then
3964 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
3965 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)*btotal(ix^d,^c)+)&
3966 -btotal(ix^d,idim)*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
3967 end if
3968 {end do\}
3969 end if
3970 if (mhd_fip) then
3971 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
3972 end if
3973 ! Get flux of tracer
3974 do iw=1,mhd_n_tracer
3975 {do ix^db=ixomin^db,ixomax^db\}
3976 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
3977 {end do\}
3978 end do
3979 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
3980 trim(mhd_hyperbolic_tc_perp_mode)/='off'
3981 if(use_perp_flux) then
3982 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
3983 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
3984 if(has_equi_rho_and_p) then
3985 te(ixi^s)=(w(ixi^s,p_)+block%equi_vars(ixi^s,equi_pe0_,b0i)) / &
3986 (r(ixi^s)*rho_loc(ixi^s))
3987 else
3988 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
3989 end if
3990 {do ix^db=ixomin^db,ixomax^db\}
3991 do idir=1,ndir
3992 bvec(ix^d,idir)=btotal(ix^d,idir)
3993 end do
3994 {end do\}
3995 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
3996 end if
3997 if(mhd_hyperbolic_tc) then
3998 {do ix^db=ixomin^db,ixomax^db\}
3999 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*btotal(ix^d,idim)/(dsqrt(^c&btotal(ix^d,^c)**2+)+smalldouble)
4000 f(ix^d,qpar_)=zero
4001 if(use_perp_flux) then
4002 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4003 f(ix^d,qperp_)=zero
4004 end if
4005 {end do\}
4006 end if
4007 end subroutine mhd_get_flux_split
4008
4009 !> Calculate semirelativistic fluxes within ixO^L without any splitting
4010 subroutine mhd_get_flux_semirelati(wC,w,x,ixI^L,ixO^L,idim,f)
4012 use mod_geometry
4013
4014 integer, intent(in) :: ixi^l, ixo^l, idim
4015 ! conservative w
4016 double precision, intent(in) :: wc(ixi^s,nw)
4017 ! primitive w
4018 double precision, intent(in) :: w(ixi^s,nw)
4019 double precision, intent(in) :: x(ixi^s,1:ndim)
4020 double precision,intent(out) :: f(ixi^s,nwflux)
4021 double precision :: sa(ixo^s,1:ndir),e(ixo^s,1:ndir),e2
4022 double precision :: r(ixi^s), te(ixi^s), rho_loc(ixi^s)
4023 double precision :: bvec(ixi^s,1:ndir)
4024 double precision :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4025 double precision :: nperp(ixi^s,1:ndir)
4026 logical :: use_perp_flux
4027 integer :: iw, ix^d, idir
4028
4029 {do ix^db=ixomin^db,ixomax^db\}
4030 ! Get flux of density
4031 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4032 ! E=Bxv
4033 {^ifthreec
4034 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4035 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4036 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4037 }
4038 {^iftwoc
4039 e(ix^d,1)=zero
4040 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4041 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4042 }
4043 {^ifonec
4044 e(ix^d,1)=zero
4045 }
4046 e2=(^c&e(ix^d,^c)**2+)
4047 if(mhd_internal_e) then
4048 ! Get flux of internal energy
4049 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4050 else
4051 ! S=ExB
4052 {^ifthreec
4053 sa(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
4054 sa(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
4055 sa(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
4056 }
4057 {^iftwoc
4058 sa(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
4059 sa(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
4060 ! set E2 back to 0, after e^2 is stored
4061 e(ix^d,2)=zero
4062 }
4063 {^ifonec
4064 sa(ix^d,1)=zero
4065 }
4066 ! Get flux of total energy
4067 f(ix^d,e_)=w(ix^d,mom(idim))*(half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)+&
4068 eos%gamma*w(ix^d,p_)*eos%inv_gamma_minus_1)+sa(ix^d,idim)
4069 end if
4070 ! Get flux of momentum
4071 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4072 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4073 ! gas pressure + magnetic pressure + electric pressure
4074 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)
4075 ! compute flux of magnetic field
4076 ! f_i[b_k]=v_i*b_k-v_k*b_i
4077 ^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_)\
4078 {end do\}
4079
4080 if(mhd_glm) then
4081 {do ix^db=ixomin^db,ixomax^db\}
4082 f(ix^d,mag(idim))=w(ix^d,psi_)
4083 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4084 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4085 {end do\}
4086 end if
4087 if (mhd_fip) then
4088 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4089 end if
4090 ! Get flux of tracer
4091 do iw=1,mhd_n_tracer
4092 {do ix^db=ixomin^db,ixomax^db\}
4093 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4094 {end do\}
4095 end do
4096 use_perp_flux = mhd_hyperbolic_tc .and. mhd_hyperbolic_tc_use_perp .and. &
4097 trim(mhd_hyperbolic_tc_perp_mode)/='off'
4098 if(use_perp_flux) then
4099 call mhd_get_rho(w,x,ixi^l,ixi^l,rho_loc)
4100 call eos%get_Rfactor(w,x,ixi^l,ixi^l,r)
4101 te(ixi^s)=w(ixi^s,p_)/(r(ixi^s)*rho_loc(ixi^s))
4102 {do ix^db=ixomin^db,ixomax^db\}
4103 do idir=1,ndir
4104 bvec(ix^d,idir)=w(ix^d,mag(idir))
4105 end do
4106 {end do\}
4107 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
4108 end if
4109 if(mhd_hyperbolic_tc) then
4110 {do ix^db=ixomin^db,ixomax^db\}
4111 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qpar_)*w(ix^d,mag(idim))/(dsqrt(^c&w(ix^d,b^c_)**2+)+smalldouble)
4112 f(ix^d,qpar_)=zero
4113 if(use_perp_flux) then
4114 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,qperp_)*nperp(ix^d,idim)
4115 f(ix^d,qperp_)=zero
4116 end if
4117 {end do\}
4118 end if
4119 end subroutine mhd_get_flux_semirelati
4120
4121 subroutine mhd_get_flux_semirelati_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4123 use mod_geometry
4125
4126 integer, intent(in) :: ixi^l, ixo^l, idim
4127 ! conservative w
4128 double precision, intent(in) :: wc(ixi^s,nw)
4129 ! primitive w
4130 double precision, intent(in) :: w(ixi^s,nw)
4131 double precision, intent(in) :: x(ixi^s,1:ndim)
4132 double precision,intent(out) :: f(ixi^s,nwflux)
4133
4134 double precision :: adiabs(ixi^s), gammas(ixi^s)
4135 double precision :: e(ixo^s,1:ndir),e2
4136 integer :: iw, ix^d
4137
4138 if(associated(usr_set_adiab)) then
4139 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4140 else
4141 adiabs=mhd_adiab
4142 end if
4143 if(associated(usr_set_gamma)) then
4144 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4145 else
4146 gammas=eos%gamma
4147 end if
4148 {do ix^db=ixomin^db,ixomax^db\}
4149 ! Get flux of density
4150 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4151 ! E=Bxv
4152 {^ifthreec
4153 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4154 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4155 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4156 e2=(^c&e(ix^d,^c)**2+)
4157 }
4158 {^iftwoc
4159 e(ix^d,1)=zero
4160 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4161 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4162 e2=e(ix^d,2)**2
4163 e(ix^d,2)=zero
4164 }
4165 {^ifonec
4166 e(ix^d,1)=zero
4167 e2=zero
4168 }
4169 ! Get flux of momentum
4170 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4171 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4172 ! gas pressure + magnetic pressure + electric pressure
4173 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)
4174 ! compute flux of magnetic field
4175 ! f_i[b_k]=v_i*b_k-v_k*b_i
4176 ^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_)\
4177 {end do\}
4178
4179 if(mhd_glm) then
4180 {do ix^db=ixomin^db,ixomax^db\}
4181 f(ix^d,mag(idim))=w(ix^d,psi_)
4182 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4183 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4184 {end do\}
4185 end if
4186 if (mhd_fip) then
4187 f(ixo^s,fip_) = w(ixo^s,mom(idim)) * wc(ixo^s,fip_)
4188 end if
4189 ! Get flux of tracer
4190 do iw=1,mhd_n_tracer
4191 {do ix^db=ixomin^db,ixomax^db\}
4192 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4193 {end do\}
4194 end do
4195 end subroutine mhd_get_flux_semirelati_noe
4196
4197 !> Source term J.E_ambi in internal energy
4198 !> For the ambipolar electric field we have E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4199 !> and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4200 !> the source term J.E_ambi = eta_A * B^2 * J_perpB^2 = eta_A * [(JxB)xB]^2/B^2
4201 !> note that J_perpB= - (JxB)xB/B^2
4202 !> multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4203 subroutine add_source_ambipolar_internal_energy(qdt,ixI^L,ixO^L,wCT,w,x)
4205 integer, intent(in) :: ixi^l, ixo^l
4206 double precision, intent(in) :: qdt
4207 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4208 double precision, intent(inout) :: w(ixi^s,1:nw)
4209
4210 double precision :: tmp(ixi^s),btot2(ixi^s)
4211 double precision :: jxbxb(ixi^s,1:3)
4212
4213 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,jxbxb)
4214 ! avoiding nulls here
4215 btot2(ixo^s)=mhd_mag_en_all(wct,ixi^l,ixo^l)
4216 where (btot2(ixo^s)>smalldouble )
4217 tmp(ixo^s) = sum(jxbxb(ixo^s,1:3)**2,dim=ndim+1) / btot2(ixo^s)
4218 elsewhere
4219 tmp(ixo^s) = zero
4220 endwhere
4221 call multiplyambicoef(ixi^l,ixo^l,tmp,wct,x)
4222 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4223 ! hence minus sign here
4224 w(ixo^s,e_)=w(ixo^s,e_)- qdt*tmp(ixo^s)
4225
4226 end subroutine add_source_ambipolar_internal_energy
4227
4228 !> this subroutine computes -J_perpB= (J x B) x B= B(J.B) - J B^2
4229 subroutine mhd_get_jxbxb(w,x,ixI^L,ixO^L,res)
4231
4232 integer, intent(in) :: ixi^l, ixo^l
4233 double precision, intent(in) :: w(ixi^s,nw)
4234 double precision, intent(in) :: x(ixi^s,1:ndim)
4235 double precision, intent(out) :: res(ixi^s,1:3)
4236
4237 double precision :: btot(ixi^s,1:3)
4238 double precision :: current(ixi^s,7-2*ndir:3)
4239 double precision :: tmp(ixi^s),b2(ixi^s)
4240 integer :: idir, idirmin
4241
4242 res=0.d0
4243 ! Calculate current density and idirmin
4244 ! current has nonzero values only for components in the range idirmin, 3
4245 call get_current(w,ixi^l,ixo^l,idirmin,current)
4246
4247 btot=0.d0
4248 if(b0field) then
4249 do idir=1,ndir
4250 btot(ixo^s, idir) = w(ixo^s,mag(idir)) + block%B0(ixo^s,idir,b0i)
4251 enddo
4252 else
4253 do idir=1,ndir
4254 btot(ixo^s, idir) = w(ixo^s,mag(idir))
4255 enddo
4256 endif
4257
4258 tmp(ixo^s)= sum(current(ixo^s,idirmin:3)*btot(ixo^s,idirmin:3),dim=ndim+1) !J.B
4259 b2(ixo^s) = sum(btot(ixo^s,1:3)**2,dim=ndim+1) !B^2
4260 do idir=1,idirmin-1
4261 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s)
4262 enddo
4263 do idir=idirmin,3
4264 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s) - current(ixo^s,idir) * b2(ixo^s)
4265 enddo
4266
4267 ! avoid possible issues at nulls
4268 do idir=1,3
4269 where (b2(ixo^s)<smalldouble )
4270 res(ixo^s,idir) = zero
4271 endwhere
4272 enddo
4273 end subroutine mhd_get_jxbxb
4274
4275 !> Sets the sources for the ambipolar terms for the STS method
4276 !> The sources are added directly (instead of fluxes as in the explicit)
4277 !> at the corresponding indices
4278 !> store_flux_var is explicitly called for each of the fluxes one by one
4279 subroutine sts_set_source_ambipolar(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
4282
4283 integer, intent(in) :: ixi^l,ixo^l,igrid,nflux
4284 double precision, intent(in) :: x(ixi^s,1:ndim)
4285 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
4286 double precision, intent(in) :: my_dt
4287 logical, intent(in) :: fix_conserve_at_step
4288
4289 double precision, dimension(ixI^S,1:3) :: tmp,ff
4290 double precision :: fluxall(ixi^s,1:nflux,1:ndim)
4291 double precision :: fe(ixi^s,sdim:3)
4292 double precision :: btot(ixi^s,1:3),tmp2(ixi^s)
4293 integer :: i, ixa^l, ie_
4294
4295 ixa^l=ixo^l^ladd1;
4296
4297 fluxall=zero
4298
4299 ! here we compute (JxB)xB= - B^2 J_perpB
4300 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,tmp)
4301
4302 ! set ambipolar electric field in tmp: E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4303 ! and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4304 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4305 do i=1,3
4306 call multiplyambicoef(ixi^l,ixa^l,tmp(ixi^s,i),w,x)
4307 enddo
4308
4309 ! Note: internal energy case is handled through add_source_internal_e
4310 ! Note: hydrodynamic energy case is handled through add_source_hydrodynamic_e
4311 ! both of the above use add_source_ambipolar_internal_energy
4312 !
4313 ! Note: total energy case without B0field split is ok here and adds div(BxE_ambi)
4314 ! Note: total energy case in semirelativistic variant (hence no B0field split) is ok here
4315 ! Note: total energy with B0field=T here adds div(B_1xE_ambi) which needs correction in add_source_B0split
4316 if(mhd_energy .and. .not.(mhd_internal_e.or.mhd_hydrodynamic_e)) then
4317 btot(ixa^s,1:3) = 0.d0
4318 ! HERE: only uses B_1 if split, otherwise this is B
4319 btot(ixa^s,1:ndir) = w(ixa^s,mag(1:ndir))
4320 ! compute ff= E_ambi x B (where B can be B_1 if B0field=T)
4321 call cross_product(ixi^l,ixa^l,tmp,btot,ff)
4322 ! compute actual cell face fluxes in ff and their divergence in tmp2
4323 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4324 if(fix_conserve_at_step) fluxall(ixi^s,1,1:ndim)=ff(ixi^s,1:ndim)
4325 ! - sign as the source is actually div(BxE_ambi) and we have div(E_ambi x B) in tmp2
4326 wres(ixo^s,e_)=-tmp2(ixo^s)
4327 endif
4328
4329 if(stagger_grid) then
4330 ! always 2D or more (2.5/3D)
4331 if(ndir>ndim) then
4332 !!!Bz
4333 ff(ixa^s,1) = tmp(ixa^s,2)
4334 ff(ixa^s,2) = -tmp(ixa^s,1)
4335 ff(ixa^s,3) = 0.d0
4336 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4337 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
4338 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
4339 end if
4340 fe=0.d0
4341 call update_faces_ambipolar(ixi^l,ixo^l,w,x,tmp,fe,btot)
4342 ixamax^d=ixomax^d;
4343 ixamin^d=ixomin^d-1;
4344 wres(ixa^s,mag(1:ndim))=-btot(ixa^s,1:ndim)
4345 else
4346 !write curl(ele) as the divergence
4347 !m1={0,ele[[3]],-ele[[2]]}
4348 !m2={-ele[[3]],0,ele[[1]]}
4349 !m3={ele[[2]],-ele[[1]],0}
4350
4351 {^ifoned
4352 !!!Bx
4353 ff(ixa^s,1) = 0.d0
4354 ff(ixa^s,2) = tmp(ixa^s,3)
4355 ff(ixa^s,3) = -tmp(ixa^s,2)
4356 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4357 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
4358 !flux divergence is a source now
4359 wres(ixo^s,mag(1))=-tmp2(ixo^s)
4360 if(ndir==2.or.ndir==3)then
4361 !!!By
4362 ff(ixa^s,1) = -tmp(ixa^s,3)
4363 ff(ixa^s,2) = 0.d0
4364 ff(ixa^s,3) = tmp(ixa^s,1)
4365 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4366 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
4367 wres(ixo^s,mag(2))=-tmp2(ixo^s)
4368 endif
4369 }
4370 {^nooned
4371 !!!Bx
4372 ff(ixa^s,1) = 0.d0
4373 ff(ixa^s,2) = tmp(ixa^s,3)
4374 ff(ixa^s,3) = -tmp(ixa^s,2)
4375 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4376 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
4377 !flux divergence is a source now
4378 wres(ixo^s,mag(1))=-tmp2(ixo^s)
4379 !!!By
4380 ff(ixa^s,1) = -tmp(ixa^s,3)
4381 ff(ixa^s,2) = 0.d0
4382 ff(ixa^s,3) = tmp(ixa^s,1)
4383 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4384 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
4385 wres(ixo^s,mag(2))=-tmp2(ixo^s)
4386 }
4387
4388 if(ndir==3) then
4389 !!!Bz
4390 ff(ixa^s,1) = tmp(ixa^s,2)
4391 ff(ixa^s,2) = -tmp(ixa^s,1)
4392 ff(ixa^s,3) = 0.d0
4393 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4394 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
4395 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
4396 end if
4397
4398 end if
4399
4400 if(fix_conserve_at_step) then
4401 fluxall=my_dt*fluxall
4402 call store_flux(igrid,fluxall,1,ndim,nflux)
4403 if(stagger_grid) then
4404 call store_edge(igrid,ixi^l,my_dt*fe,1,ndim)
4405 end if
4406 end if
4407
4408 end subroutine sts_set_source_ambipolar
4409
4410 !> get ambipolar electric field and the integrals around cell faces
4411 subroutine update_faces_ambipolar(ixI^L,ixO^L,w,x,ECC,fE,circ)
4413
4414 integer, intent(in) :: ixi^l, ixo^l
4415 double precision, intent(in) :: w(ixi^s,1:nw)
4416 double precision, intent(in) :: x(ixi^s,1:ndim)
4417 ! amibipolar electric field at cell centers
4418 double precision, intent(in) :: ecc(ixi^s,1:3)
4419 double precision, intent(out) :: fe(ixi^s,sdim:3)
4420 double precision, intent(out) :: circ(ixi^s,1:ndim)
4421
4422 integer :: hxc^l,ixc^l,ixa^l
4423 integer :: idim1,idim2,idir,ix^d
4424
4425 fe=zero
4426 ! calculate ambipolar electric field on cell edges from cell centers
4427 do idir=sdim,3
4428 ixcmax^d=ixomax^d;
4429 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4430 {do ix^db=0,1\}
4431 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
4432 ixamin^d=ixcmin^d+ix^d;
4433 ixamax^d=ixcmax^d+ix^d;
4434 fe(ixc^s,idir)=fe(ixc^s,idir)+ecc(ixa^s,idir)
4435 {end do\}
4436 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0*block%dsC(ixc^s,idir)
4437 end do
4438
4439 ! Calculate circulation on each face to get value of line integral of
4440 ! electric field in the positive idir direction.
4441 ixcmax^d=ixomax^d;
4442 ixcmin^d=ixomin^d-1;
4443
4444 circ=zero
4445 do idim1=1,ndim ! Coordinate perpendicular to face
4446 do idim2=1,ndim
4447 do idir=sdim,3 ! Direction of line integral
4448 ! Assemble indices
4449 hxc^l=ixc^l-kr(idim2,^d);
4450 ! Add line integrals in direction idir
4451 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4452 +lvc(idim1,idim2,idir)&
4453 *(fe(ixc^s,idir)&
4454 -fe(hxc^s,idir))
4455 end do
4456 end do
4457 circ(ixc^s,idim1)=circ(ixc^s,idim1)/block%surfaceC(ixc^s,idim1)
4458 end do
4459
4460 end subroutine update_faces_ambipolar
4461
4462 !> use cell-center flux vector to get cell-face flux vector
4463 !> which will be used to add the source term as the divergence of the flux
4464 !> we return fluxes at all faces as well as the divergence of the flux
4465 !> Note that for ndir>ndim, we do not modify the input cell center flux
4466 subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
4468
4469 integer, intent(in) :: ixi^l, ixo^l
4470 double precision, dimension(ixI^S,1:3), intent(inout) :: ff
4471 double precision, intent(out) :: src(ixi^s)
4472
4473 double precision :: ffc(ixi^s,1:ndim)
4474 double precision :: dxinv(ndim)
4475 integer :: idims, ix^d, ixa^l, ixb^l, ixc^l
4476
4477 ixa^l=ixo^l^ladd1;
4478 dxinv=1.d0/dxlevel
4479 ! cell corner flux in ffc
4480 ! TO BE GENERALIZED FOR NON-UNIFORM NON-CARTESIAN MESH
4481 if (slab_uniform)then
4482 ffc=0.d0
4483 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
4484 {do ix^db=0,1\}
4485 ixbmin^d=ixcmin^d+ix^d;
4486 ixbmax^d=ixcmax^d+ix^d;
4487 ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
4488 {end do\}
4489 ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
4490 else
4491 call mpistop("to generalize using volume averaging")
4492 endif
4493 ! now get flux at cell face from corner fluxes in fcc
4494 ff(ixi^s,1:ndim)=0.d0
4495 do idims=1,ndim
4496 ixb^l=ixo^l-kr(idims,^d);
4497 ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
4498 {do ix^db=0,1 \}
4499 if({ ix^d==0 .and. ^d==idims | .or.}) then
4500 ixbmin^d=ixcmin^d-ix^d;
4501 ixbmax^d=ixcmax^d-ix^d;
4502 ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
4503 end if
4504 {end do\}
4505 ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
4506 end do
4507 src=0.d0
4508 if(slab_uniform) then
4509 do idims=1,ndim
4510 ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
4511 ixb^l=ixo^l-kr(idims,^d);
4512 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4513 end do
4514 else
4515 do idims=1,ndim
4516 ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
4517 ixb^l=ixo^l-kr(idims,^d);
4518 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4519 end do
4520 src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
4521 end if
4522 end subroutine get_flux_on_cell_face
4523
4524 !> Calculates the explicit dt for the ambipolar term
4525 !> This function is used by both explicit scheme and STS method
4526 function get_ambipolar_dt(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
4528
4529 integer, intent(in) :: ixi^l, ixo^l
4530 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
4531 double precision, intent(in) :: w(ixi^s,1:nw)
4532 double precision :: dtnew
4533
4534 double precision :: coef
4535 double precision :: dxarr(ndim)
4536 double precision :: tmp(ixi^s)
4537
4538 ^d&dxarr(^d)=dx^d;
4539 tmp(ixo^s) = mhd_mag_en_all(w, ixi^l, ixo^l)
4540 call multiplyambicoef(ixi^l,ixo^l,tmp,w,x)
4541 ! now we have -mhd_eta_ambi B^2 /rho^2 in tmp
4542 coef = maxval(dabs(tmp(ixo^s)))
4543 if(coef/=0.d0) then
4544 coef=1.d0/coef
4545 else
4546 coef=bigdouble
4547 end if
4548 if(slab_uniform) then
4549 dtnew=minval(dxarr(1:ndim))**2.0d0*coef
4550 else
4551 dtnew=minval(block%ds(ixo^s,1:ndim))**2.0d0*coef
4552 end if
4553
4554 end function get_ambipolar_dt
4555
4556 !> multiply res by the ambipolar coefficient
4557 !> The ambipolar coefficient is calculated as -mhd_eta_ambi/rho^2
4558 !> The user may mask its value in the user file
4559 !> by implementing usr_mask_ambipolar subroutine
4560 subroutine multiplyambicoef(ixI^L,ixO^L,res,w,x)
4562 integer, intent(in) :: ixi^l, ixo^l
4563 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
4564 double precision, intent(inout) :: res(ixi^s)
4565 double precision :: tmp(ixi^s)
4566 double precision :: rho(ixi^s)
4567
4568 call mhd_get_rho(w,x,ixi^l,ixi^l,rho)
4569 tmp(ixi^s)=-mhd_eta_ambi/rho(ixi^s)**2
4570 if (associated(usr_mask_ambipolar)) then
4571 call usr_mask_ambipolar(ixi^l,ixo^l,w,x,tmp)
4572 end if
4573 res(ixo^s) = tmp(ixo^s) * res(ixo^s)
4574
4575 end subroutine multiplyambicoef
4576
4577 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
4578 subroutine mhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
4584 use mod_cak_force, only: cak_add_source
4585
4586 integer, intent(in) :: ixi^l, ixo^l
4587 double precision, intent(in) :: qdt,dtfactor
4588 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
4589 double precision, intent(inout) :: w(ixi^s,1:nw)
4590 logical, intent(in) :: qsourcesplit
4591 logical, intent(inout) :: active
4592
4593 !TODO local_timestep support is only added for splitting
4594 ! but not for other nonideal terms such gravity, RC, viscosity,..
4595 ! it will also only work for divbfix 'linde', which does not require
4596 ! modification as it does not use dt in the update
4597
4598 if (.not. qsourcesplit) then
4599 if(mhd_internal_e) then
4600 ! Source for solving internal energy
4601 active = .true.
4602 call add_source_internal_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4603 else
4604 if(has_equi_rho_and_p) then
4605 active = .true.
4606 call add_equi_terms(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
4607 end if
4608 end if
4609
4610 if(mhd_hyperbolic_tc) then
4611 active = .true.
4612 call add_hyperbolic_tc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4613 end if
4614
4615 ! Source for B0 splitting
4616 if (b0field) then
4617 active = .true.
4618 ! this adds source to momentum of type J0 x B0 and to energy equation
4619 ! latter always + J0 * E (electric field being E_ideal, E_hall, E_ambi)
4620 ! used for total energy variants
4621 call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
4622 end if
4623
4624 ! Sources for resistivity in eqs. for e, B1, B2 and B3
4625 if (abs(mhd_eta)>smalldouble)then
4626 active = .true.
4627 call add_source_res_exp(qdt,ixi^l,ixo^l,wct,w,x)
4628 end if
4629
4630 if (mhd_ambipolar_exp)then
4631 active = .true.
4632 call add_source_ambi_exp(qdt,ixi^l,ixo^l,wct,w,x)
4633 end if
4634
4635 if (mhd_eta_hyper>0.d0)then
4636 active = .true.
4637 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
4638 end if
4639
4640 if(mhd_hydrodynamic_e) then
4641 ! Source for solving hydrodynamic energy
4642 active = .true.
4643 call add_source_hydrodynamic_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4644 else if (mhd_semirelativistic) then
4645 ! add sources for semirelativistic MHD
4646 active = .true.
4647 call add_source_semirelativistic(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
4648 end if
4649 end if
4650
4651 {^nooned
4652 if(source_split_divb .eqv. qsourcesplit) then
4653 ! Sources related to div B
4654 select case (type_divb)
4655 case (divb_ct)
4656 continue ! Do nothing
4657 case (divb_linde)
4658 active = .true.
4659 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4660 case (divb_glm)
4661 active = .true.
4662 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
4663 case (divb_powel)
4664 active = .true.
4665 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
4666 case (divb_janhunen)
4667 active = .true.
4668 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
4669 case (divb_lindejanhunen)
4670 active = .true.
4671 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4672 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
4673 case (divb_lindepowel)
4674 active = .true.
4675 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4676 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
4677 case (divb_lindeglm)
4678 active = .true.
4679 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
4680 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
4681 case (divb_multigrid)
4682 continue ! Do nothing
4683 case (divb_none)
4684 ! Do nothing
4685 case default
4686 call mpistop('Unknown divB fix')
4687 end select
4688 end if
4689 }
4690
4691 if(mhd_radiative_cooling) then
4692 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
4693 w,x,qsourcesplit,active, rc_fl)
4694 end if
4695
4696 if(mhd_viscosity) then
4697 call viscosity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
4698 w,x,mhd_energy,qsourcesplit,active)
4699 end if
4700
4701 if(mhd_gravity) then
4702 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
4703 w,x,gravity_energy,qsourcesplit,active)
4704 end if
4705
4706 if (mhd_cak_force) then
4707 call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,mhd_energy,qsourcesplit,active)
4708 end if
4709
4710 ! This is where the radiation force and heating/cooling are added
4711 if (mhd_radiation_fld) then
4712 call mhd_add_radiation_source(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
4713 endif
4714
4715 ! update temperature from new pressure, density, and old ionization degree
4716 if(eos%eos_type == 'PI') then
4717 if(.not.qsourcesplit) then
4718 active = .true.
4719 call eos%update_eos(ixi^l,ixo^l,w,x)
4720 end if
4721 end if
4722
4723 end subroutine mhd_add_source
4724
4725 subroutine mhd_add_radiation_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
4726 use mod_constants
4728 use mod_usr_methods
4729 use mod_fld
4730
4731 integer, intent(in) :: ixi^l, ixo^l
4732 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
4733 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
4734 double precision, intent(inout) :: w(ixi^s,1:nw)
4735 logical, intent(in) :: qsourcesplit
4736 logical, intent(inout) :: active
4737
4738 ! add radiation force and work done by it, changes momentum and gas energy
4739 ! handle photon tiring, heating and cooling exchange between gas and radiation field
4740 call add_fld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active,fld_fl)
4741
4742 end subroutine mhd_add_radiation_source
4743
4744 !> add some source terms to total energy related to has_equi_rho_and_p=T
4745 subroutine add_equi_terms(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
4747 use mod_geometry
4748 use mod_usr_methods
4749
4750 integer, intent(in) :: ixi^l, ixo^l
4751 double precision, intent(in) :: qdt,dtfactor
4752 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4753 double precision, intent(in) :: wctprim(ixi^s,1:nw)
4754 double precision, intent(inout) :: w(ixi^s,1:nw)
4755
4756 double precision :: divv(ixi^s)
4757 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
4758 double precision :: gravity_field(ixi^s,1:ndim)
4759 integer :: idir
4760
4761 if(slab_uniform) then
4762 if(nghostcells .gt. 2) then
4763 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,3)
4764 else
4765 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,2)
4766 end if
4767 else
4768 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv)
4769 end if
4770 divv(ixo^s)=divv(ixo^s)*eos%gamma*eos%inv_gamma_minus_1
4771 if(local_timestep) then
4772 w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
4773 else
4774 w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
4775 end if
4776 if(b0field)then
4777 if(b0field_forcefree.and.mhd_gravity)then
4778 ! add -v dot(rho_0 g)/(gamma-1)
4779 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
4780 do idir=1,ndim
4781 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
4782 enddo
4783 else
4784 a=0.d0
4785 b=0.d0
4786 ! store B0 magnetic field in b
4787 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
4788 ! store J0 current in a
4789 do idir=7-2*ndir,3
4790 a(ixo^s,idir)=block%J0(ixo^s,idir)
4791 end do
4792 call cross_product(ixi^l,ixo^l,a,b,axb)
4793 ! add -v dot(rho_0 g + J0 x B_0)/(gamma-1)
4794 do idir=1,ndir
4795 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*axb(ixo^s,idir)*eos%inv_gamma_minus_1
4796 enddo
4797 if(mhd_gravity)then
4798 ! add -v dot(rho_0 g)/(gamma-1)
4799 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
4800 do idir=1,ndim
4801 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
4802 enddo
4803 endif
4804 endif
4805 else
4806 if(mhd_gravity)then
4807 ! add -v dot(rho_0 g)/(gamma-1)
4808 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
4809 do idir=1,ndim
4810 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*eos%inv_gamma_minus_1
4811 enddo
4812 endif
4813 endif
4814 end subroutine add_equi_terms
4815
4816 subroutine mhd_get_hyperbolic_tc_geometry(ixI^L,ixO^L,Te,Bvec,bgradT,gradTperp_mag,nperp)
4818 use mod_geometry, only: gradient
4819 integer, intent(in) :: ixi^l,ixo^l
4820 double precision, intent(in) :: te(ixi^s)
4821 double precision, intent(in) :: bvec(ixi^s,1:ndir)
4822 double precision, intent(out) :: bgradt(ixi^s), gradtperp_mag(ixi^s)
4823 double precision, intent(out) :: nperp(ixi^s,1:ndir)
4824
4825 double precision :: bmag, bunitvec(ndir), gradt(ndir), gradt_perp(ndir)
4826 double precision :: gradt_cell(ixi^s,1:ndir)
4827 integer :: ix^d, idir
4828
4829 gradt_cell=zero
4830 if(.not. slab_uniform) then
4831 do idir=1,ndim
4832 call gradient(te,ixi^l,ixo^l,idir,gradt_cell(ixi^s,idir))
4833 end do
4834 end if
4835
4836 {^iftwod
4837 do ix2=ixomin2,ixomax2
4838 do ix1=ixomin1,ixomax1
4839 bmag=zero
4840 do idir=1,ndir
4841 bmag=bmag+bvec(ix^d,idir)**2
4842 end do
4843 bmag=dsqrt(bmag)
4844
4845 if(bmag>smalldouble) then
4846 do idir=1,ndir
4847 bunitvec(idir)=bvec(ix^d,idir)/bmag
4848 end do
4849 else
4850 do idir=1,ndir
4851 bunitvec(idir)=zero
4852 end do
4853 end if
4854 if(slab_uniform) then
4855 gradt(1)=((8.d0*(te(ix1+1,ix2)-te(ix1-1,ix2))-te(ix1+2,ix2)+te(ix1-2,ix2))/12.d0)/block%ds(ix^d,1)
4856 gradt(2)=((8.d0*(te(ix1,ix2+1)-te(ix1,ix2-1))-te(ix1,ix2+2)+te(ix1,ix2-2))/12.d0)/block%ds(ix^d,2)
4857 if(ndir>2) gradt(3)=zero
4858 else
4859 do idir=1,ndir
4860 gradt(idir)=gradt_cell(ix^d,idir)
4861 end do
4862 end if
4863
4864 bgradt(ix^d)=zero
4865 do idir=1,ndir
4866 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
4867 end do
4868
4869 do idir=1,ndir
4870 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
4871 end do
4872
4873 gradtperp_mag(ix^d)=zero
4874 do idir=1,ndir
4875 gradtperp_mag(ix^d)=gradtperp_mag(ix^d)+gradt_perp(idir)**2
4876 end do
4877 gradtperp_mag(ix^d)=dsqrt(gradtperp_mag(ix^d))
4878
4879 if(gradtperp_mag(ix^d)>smalldouble) then
4880 do idir=1,ndir
4881 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
4882 end do
4883 else
4884 gradtperp_mag(ix^d)=zero
4885 do idir=1,ndir
4886 nperp(ix^d,idir)=zero
4887 end do
4888 end if
4889 end do
4890 end do
4891 }
4892 {^ifthreed
4893 do ix3=ixomin3,ixomax3
4894 do ix2=ixomin2,ixomax2
4895 do ix1=ixomin1,ixomax1
4896 bmag=dsqrt(bvec(ix^d,1)**2+bvec(ix^d,2)**2+bvec(ix^d,3)**2)
4897 if(bmag>smalldouble) then
4898 bunitvec(1)=bvec(ix^d,1)/bmag
4899 bunitvec(2)=bvec(ix^d,2)/bmag
4900 bunitvec(3)=bvec(ix^d,3)/bmag
4901 else
4902 bunitvec(1)=zero
4903 bunitvec(2)=zero
4904 bunitvec(3)=zero
4905 end if
4906
4907 if(slab_uniform) then
4908 gradt(1)=((8.d0*(te(ix1+1,ix2,ix3)-te(ix1-1,ix2,ix3))-te(ix1+2,ix2,ix3)+te(ix1-2,ix2,ix3))/12.d0)/block%ds(ix^d,1)
4909 gradt(2)=((8.d0*(te(ix1,ix2+1,ix3)-te(ix1,ix2-1,ix3))-te(ix1,ix2+2,ix3)+te(ix1,ix2-2,ix3))/12.d0)/block%ds(ix^d,2)
4910 gradt(3)=((8.d0*(te(ix1,ix2,ix3+1)-te(ix1,ix2,ix3-1))-te(ix1,ix2,ix3+2)+te(ix1,ix2,ix3-2))/12.d0)/block%ds(ix^d,3)
4911 else
4912 do idir=1,ndir
4913 gradt(idir)=gradt_cell(ix^d,idir)
4914 end do
4915 end if
4916
4917 bgradt(ix^d)=zero
4918 do idir=1,ndir
4919 bgradt(ix^d)=bgradt(ix^d)+bunitvec(idir)*gradt(idir)
4920 end do
4921
4922 do idir=1,ndir
4923 gradt_perp(idir)=gradt(idir)-bgradt(ix^d)*bunitvec(idir)
4924 end do
4925
4926 gradtperp_mag(ix^d)=dsqrt(gradt_perp(1)**2+gradt_perp(2)**2+gradt_perp(3)**2)
4927 if(gradtperp_mag(ix^d)>smalldouble) then
4928 do idir=1,ndir
4929 nperp(ix^d,idir)=gradt_perp(idir)/gradtperp_mag(ix^d)
4930 end do
4931 else
4932 gradtperp_mag(ix^d)=zero
4933 do idir=1,ndir
4934 nperp(ix^d,idir)=zero
4935 end do
4936 end if
4937 end do
4938 end do
4939 end do
4940 }
4941 end subroutine mhd_get_hyperbolic_tc_geometry
4942
4943 subroutine add_hyperbolic_tc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
4945 use mod_geometry, only: gradient
4946 integer, intent(in) :: ixi^l,ixo^l
4947 double precision, intent(in) :: qdt
4948 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
4949 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
4950 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
4951
4952 double precision, dimension(ixI^S) :: r,te,rho_loc,pth_loc
4953 double precision, dimension(ixI^S) :: ne_loc,nh_dummy
4954 double precision, dimension(ixI^S,1:ndir) :: bvec
4955 double precision, dimension(ixI^S) :: bgradt, gradtperp_mag
4956 double precision, dimension(ixI^S,1:ndir) :: nperp
4957 double precision, dimension(ixI^S) :: gradt_geom
4958 double precision, parameter :: xe_prefac_cgs = 4.753567596681522d6
4959 double precision :: kappa_t5,kappa_t5_perp,kappa_t5_perp_eff
4960 double precision :: kappa_t7,f_sat,kappat5_bgradt,kappat5_gradtperp,tau,b2,fb,gradt1
4961 double precision :: qclass_diss
4962 double precision :: bmag_loc,tloc,tcond,nloc_code,cchi,chi
4963 double precision :: cmax(ndim),c2,cfast2,avmincs2(ndim),inv_rho
4964 logical :: use_perp_source
4965 integer :: ix^d,idir
4966
4967 ! xe_prefac_cgs expects B [G], T [K], and ne [cm^-3]. Convert the
4968 ! normalisation units explicitly in SI mode, while retaining code-unit
4969 ! state variables in the cell loop below.
4970 cchi=zero
4971 if(trim(mhd_hyperbolic_tc_perp_mode)=='electron_magnetization') then
4972 if(si_unit) then
4973 cchi = (xe_prefac_cgs/mhd_hyperbolic_tc_coulomb_log) * &
4974 (1.d4*unit_magneticfield)*unit_temperature**1.5d0 / &
4975 (1.d-6*unit_numberdensity)
4976 else
4977 cchi = (xe_prefac_cgs/mhd_hyperbolic_tc_coulomb_log) * &
4979 end if
4980 end if
4981 call eos%get_Rfactor(wct,x,ixi^l,ixi^l,r)
4982 {do ix^db=iximin^db,iximax^db\}
4983 if(has_equi_rho_and_p) then
4984 rho_loc(ix^d)=wctprim(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
4985 pth_loc(ix^d)=wctprim(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)
4986 else
4987 rho_loc(ix^d)=wctprim(ix^d,rho_)
4988 pth_loc(ix^d)=wctprim(ix^d,p_)
4989 end if
4990 te(ix^d)=pth_loc(ix^d)/(r(ix^d)*rho_loc(ix^d))
4991 {end do\}
4992 ! Electron number density in code units. Under the FI/PI normalisation,
4993 ! rho_code equals nH_code. FI uses the composition-dependent fully ionised
4994 ! electron count. PI obtains the local electron count from its R factor:
4995 ! R*(2+3 A_He) = (n_nuclei+n_e)/n_H. LTE stores ne explicitly.
4996 if(trim(mhd_hyperbolic_tc_perp_mode)=='electron_magnetization') then
4997 if(eos%eos_type=='LTE') then
4998 call eos%get_ne_nH(ixi^l,ixi^l,wct,ne_loc,nh_dummy)
4999 else if(eos%eos_type=='PI') then
5000 ne_loc(ixi^s)=rho_loc(ixi^s)*max(r(ixi^s)*(2.d0+3.d0*eos%He_abundance) &
5001 -(1.d0+eos%He_abundance),smalldouble)
5002 else
5003 ne_loc(ixi^s)=rho_loc(ixi^s)*(1.d0+2.d0*eos%He_abundance)
5004 end if
5005 end if
5006 use_perp_source = mhd_hyperbolic_tc_use_perp .and. &
5007 trim(mhd_hyperbolic_tc_perp_mode)/='off'
5008 if(b0field) then
5009 {do ix^db=ixomin^db,ixomax^db\}
5010 do idir=1,ndir
5011 bvec(ix^d,idir)=wct(ix^d,mag(idir))+block%B0(ix^d,idir,0)
5012 end do
5013 {end do\}
5014 else
5015 {do ix^db=ixomin^db,ixomax^db\}
5016 do idir=1,ndir
5017 bvec(ix^d,idir)=wct(ix^d,mag(idir))
5018 end do
5019 {end do\}
5020 end if
5021 {^nooned
5022 call mhd_get_hyperbolic_tc_geometry(ixi^l,ixo^l,te,bvec,bgradt,gradtperp_mag,nperp)
5023 }
5024 {^ifoned
5025 gradt_geom=zero
5026 if(.not.slab_uniform) then
5027 call gradient(te,ixi^l,ixo^l,1,gradt_geom)
5028 end if
5029 do ix1=ixomin1,ixomax1
5032 kappa_t7=kappa_t5*te(ix1)
5033 else
5034 tcond = te(ix1)
5035 if(mhd_trac) then
5036 tcond = max(tcond, block%wextra(ix1,tcoff_))
5037 end if
5038 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5039 kappa_t7=kappa_t5*tcond
5040 end if
5041 if(slab_uniform) then
5042 gradt1=((8.d0*(te(ix1+1)-te(ix1-1))-te(ix1+2)+te(ix1-2))/12.d0)/block%ds(ix1,1)
5043 else
5044 gradt1=gradt_geom(ix1)
5045 end if
5046 b2=zero
5047 do idir=1,ndir
5048 b2=b2+bvec(ix1,idir)**2
5049 end do
5050 if(b2>smalldouble**2) then
5051 bgradt(ix1)=bvec(ix1,1)*gradt1/dsqrt(b2)
5052 else
5053 bgradt(ix1)=zero
5054 end if
5055 kappat5_bgradt=kappa_t5*bgradt(ix1)
5056 inv_rho=1.d0/rho_loc(ix1)
5057 c2=eos%gamma*pth_loc(ix1)*inv_rho
5058 cfast2 = b2*inv_rho + c2
5059 avmincs2(1) = cfast2**2 - 4.0d0*c2*bvec(ix1,1)**2*inv_rho
5060 cmax(1) = sqrt(half*(cfast2 + sqrt(dabs(avmincs2(1)))))
5061 if(mhd_hyperbolic_tc_sat) then
5062 f_sat=one/(one+dabs(kappat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5063 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*cmax(1)**2))
5064 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5065 else
5066 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/&
5067 max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*cmax(1)**2))
5068 end if
5069 end do
5070 }
5071 {^iftwod
5072 do ix2=ixomin2,ixomax2
5073 do ix1=ixomin1,ixomax1
5076 kappa_t7=kappa_t5*te(ix^d)
5077 else
5078 tcond=te(ix^d)
5079 if(mhd_trac) then
5080 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5081 end if
5082 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5083 kappa_t7 = kappa_t5*tcond
5084 end if
5085 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5086 b2 = zero
5087 do idir = 1, ndir
5088 b2 = b2 + bvec(ix^d,idir)**2
5089 end do
5090 if(use_perp_source) then
5091 select case(trim(mhd_hyperbolic_tc_perp_mode))
5092 case('fixed_reference')
5093 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5094 case('weak_field_isotropization')
5095 if(mhd_hyperbolic_tc_bmin>zero) then
5096 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5097 else
5098 fb=one
5099 end if
5100 kappa_t5_perp_eff=(one-fb)*kappa_t5
5101 kappa_t5_perp=kappa_t5_perp_eff
5102 case('electron_magnetization')
5103 bmag_loc = dsqrt(b2)
5104 tloc = max(te(ix^d), smalldouble)
5105 nloc_code = max(ne_loc(ix^d), smalldouble)
5106 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5107 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5108 kappa_t5_perp = kappa_t5_perp_eff
5109 case default
5110 kappa_t5_perp=zero
5111 end select
5112 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5113 end if
5114 inv_rho=1.d0/rho_loc(ix^d)
5115 c2=eos%gamma*pth_loc(ix^d)*inv_rho
5116 cfast2 = b2*inv_rho + c2
5117 do idir=1,ndim
5118 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5119 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5120 end do
5121 if(mhd_hyperbolic_tc_sat) then
5122 qclass_diss=dabs(kappat5_bgradt)
5123 if(use_perp_source) &
5124 qclass_diss=dsqrt(kappat5_bgradt**2+kappat5_gradtperp**2)
5125 f_sat=one/(one+qclass_diss/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5126 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5127 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5128 if(use_perp_source) then
5129 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5130 end if
5131 else
5132 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5133 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5134 if(use_perp_source) then
5135 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5136 end if
5137 end if
5138 end do
5139 end do
5140 }
5141 {^ifthreed
5142 do ix3=ixomin3,ixomax3
5143 do ix2=ixomin2,ixomax2
5144 do ix1=ixomin1,ixomax1
5147 kappa_t7=kappa_t5*te(ix^d)
5148 else
5149 tcond=te(ix^d)
5150 if(mhd_trac) then
5151 tcond=max(tcond, block%wextra(ix^d,tcoff_))
5152 end if
5153 kappa_t5=mhd_hyperbolic_tc_kappa*sqrt(tcond**5)
5154 kappa_t7 = kappa_t5*tcond
5155 end if
5156 kappat5_bgradt=kappa_t5*bgradt(ix^d)
5157 b2 = zero
5158 do idir = 1, ndir
5159 b2 = b2 + bvec(ix^d,idir)**2
5160 end do
5161 if(use_perp_source) then
5162 select case(trim(mhd_hyperbolic_tc_perp_mode))
5163 case('fixed_reference')
5164 kappa_t5_perp=mhd_hyperbolic_tc_kappa_perp_factor*kappa_t5
5165 case('weak_field_isotropization')
5166 if(mhd_hyperbolic_tc_bmin>zero) then
5167 fb=b2/(b2+mhd_hyperbolic_tc_bmin**2)
5168 else
5169 fb=one
5170 end if
5171 kappa_t5_perp_eff=(one-fb)*kappa_t5
5172 kappa_t5_perp=kappa_t5_perp_eff
5173 case('electron_magnetization')
5174 bmag_loc = dsqrt(b2)
5175 tloc = max(te(ix^d), smalldouble)
5176 nloc_code = max(ne_loc(ix^d), smalldouble)
5177 chi = cchi*bmag_loc*tloc**1.5d0/nloc_code
5178 kappa_t5_perp_eff = kappa_t5/(one+chi**2)
5179 kappa_t5_perp = kappa_t5_perp_eff
5180 case default
5181 kappa_t5_perp=zero
5182 end select
5183 kappat5_gradtperp=kappa_t5_perp*gradtperp_mag(ix^d)
5184 end if
5185 inv_rho=1.d0/rho_loc(ix^d)
5186 c2=eos%gamma*pth_loc(ix^d)*inv_rho
5187 cfast2 = b2*inv_rho + c2
5188 do idir = 1, ndim
5189 avmincs2(idir)=cfast2**2-4.0d0*c2*bvec(ix^d,idir)**2*inv_rho
5190 cmax(idir)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(idir)))))\
5191 end do
5192 if(mhd_hyperbolic_tc_sat) then
5193 qclass_diss=dabs(kappat5_bgradt)
5194 if(use_perp_source) &
5195 qclass_diss=dsqrt(kappat5_bgradt**2+kappat5_gradtperp**2)
5196 f_sat=one/(one+qclass_diss/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5197 tau=max(4.d0*dt, f_sat*kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5198 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(f_sat*kappat5_bgradt+wct(ix^d,qpar_))/tau
5199 if(use_perp_source) then
5200 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(f_sat*kappat5_gradtperp+wct(ix^d,qperp_))/tau
5201 end if
5202 else
5203 tau=max(4.d0*dt, kappa_t7*courantpar**2/(pth_loc(ix^d)*eos%inv_gamma_minus_1*maxval(cmax(:))**2))
5204 w(ix^d,qpar_)=w(ix^d,qpar_)-qdt*(kappat5_bgradt+wct(ix^d,qpar_))/tau
5205 if(use_perp_source) then
5206 w(ix^d,qperp_)=w(ix^d,qperp_)-qdt*(kappat5_gradtperp+wct(ix^d,qperp_))/tau
5207 end if
5208 end if
5209 end do
5210 end do
5211 end do
5212 }
5213 end subroutine add_hyperbolic_tc_source
5214
5215 !> Compute the Lorentz force (JxB) Note: Unused subroutine
5216 !> perhaps useful for post-processing when made public
5217 subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
5219 integer, intent(in) :: ixi^l, ixo^l
5220 double precision, intent(in) :: w(ixi^s,1:nw)
5221 double precision, intent(inout) :: jxb(ixi^s,3)
5222 double precision :: a(ixi^s,3), b(ixi^s,3)
5223 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5224 double precision :: current(ixi^s,7-2*ndir:3)
5225 integer :: idir, idirmin
5226
5227 b=0.0d0
5228 if(b0field) then
5229 do idir = 1, ndir
5230 b(ixo^s, idir) = w(ixo^s,mag(idir))+block%B0(ixo^s,idir,0)
5231 end do
5232 else
5233 do idir = 1, ndir
5234 b(ixo^s, idir) = w(ixo^s,mag(idir))
5235 end do
5236 end if
5237
5238 ! store J current in a
5239 call get_current(w,ixi^l,ixo^l,idirmin,current)
5240
5241 a=0.0d0
5242 do idir=7-2*ndir,3
5243 a(ixo^s,idir)=current(ixo^s,idir)
5244 end do
5245
5246 call cross_product(ixi^l,ixo^l,a,b,jxb)
5247 end subroutine get_lorentz_force
5248
5249 subroutine mhd_get_rho(w,x,ixI^L,ixO^L,rho)
5251 integer, intent(in) :: ixi^l, ixo^l
5252 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
5253 double precision, intent(out) :: rho(ixi^s)
5254
5255 if(has_equi_rho_and_p) then
5256 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
5257 else
5258 rho(ixo^s) = w(ixo^s,rho_)
5259 endif
5260
5261 end subroutine mhd_get_rho
5262
5263 !> handle small or negative internal energy
5264 subroutine mhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
5267 integer, intent(in) :: ixi^l,ixo^l, ie
5268 double precision, intent(inout) :: w(ixi^s,1:nw)
5269 double precision, intent(in) :: x(ixi^s,1:ndim)
5270 character(len=*), intent(in) :: subname
5271
5272 double precision :: rho(ixi^s)
5273 integer :: idir
5274 logical :: flag(ixi^s,1:nw)
5275
5276 flag=.false.
5277 if(has_equi_rho_and_p) then
5278 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1<small_e)&
5279 flag(ixo^s,ie)=.true.
5280 else
5281 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
5282 endif
5283 if(any(flag(ixo^s,ie))) then
5284 select case (small_values_method)
5285 case ("replace")
5286 if(has_equi_rho_and_p) then
5287 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
5288 block%equi_vars(ixo^s,equi_pe0_,0)*eos%inv_gamma_minus_1
5289 else
5290 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
5291 endif
5292 case ("average")
5293 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
5294 case default
5295 ! small values error shows primitive variables
5296 w(ixo^s,e_)=w(ixo^s,e_)*eos%gamma_minus_1
5297 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
5298 do idir = 1, ndir
5299 w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
5300 end do
5301 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
5302 end select
5303 end if
5304
5305 end subroutine mhd_handle_small_ei
5306
5307
5308 !> Source terms after split off time-independent magnetic field
5309 subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5311
5312 integer, intent(in) :: ixi^l, ixo^l
5313 double precision, intent(in) :: qdt, dtfactor,wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5314 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5315 double precision, intent(inout) :: w(ixi^s,1:nw)
5316
5317 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5318 integer :: idir
5319
5320 a=0.d0
5321 b=0.d0
5322 ! for force-free field J0xB0 =0
5323 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) then
5324 ! store B0 magnetic field in b
5325 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5326
5327 ! store J0 current in a
5328 do idir=7-2*ndir,3
5329 a(ixo^s,idir)=block%J0(ixo^s,idir)
5330 end do
5331 call cross_product(ixi^l,ixo^l,a,b,axb)
5332 if(local_timestep) then
5333 do idir=1,3
5334 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5335 enddo
5336 else
5337 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5338 endif
5339 ! add J0xB0 source term in momentum equations
5340 w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
5341 end if
5342
5343 if(total_energy) then
5344 a=0.d0
5345 ! for free-free field -(vxB0) dot J0 =0
5346 b(ixo^s,:)=wctprim(ixo^s,mag(:))
5347 ! store full magnetic field B0+B1 in b
5348 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
5349 ! store velocity in a
5350 a(ixi^s,1:ndir)=wctprim(ixi^s,mom(1:ndir))
5351 ! -E = a x b
5352 call cross_product(ixi^l,ixo^l,a,b,axb)
5353 if(local_timestep) then
5354 do idir=1,3
5355 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5356 enddo
5357 else
5358 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5359 endif
5360 ! add -(vxB) dot J0 source term in energy equation
5361 ! where it is adding -J0 dot (vxB_1) when appropriate
5362 do idir=7-2*ndir,3
5363 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
5364 end do
5365 if(mhd_hall) then
5366 ! store hall velocity in a, only partial current is needed
5367 call mhd_getv_hall(wct,x,ixi^l,ixo^l,a,.true.)
5368 ! -E = a x b
5369 call cross_product(ixi^l,ixo^l,a,b,axb)
5370 if(local_timestep) then
5371 do idir=1,3
5372 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5373 enddo
5374 else
5375 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5376 endif
5377 ! add -(vxB) dot J0 source term in energy equation
5378 do idir=7-2*ndir,3
5379 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
5380 end do
5381 endif
5382 if(mhd_ambipolar_sts) then
5383 ! in STS variant of ambipolar, we added for split B the term div(B_1xE_ambi)
5384 ! hence needs to add J_0 dot E_ambi
5385 ! to get finally the term etaA (J_perpB)^/B^2-B_1 dot (curl Eambi)
5386 !reuse axb
5387 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,axb)
5388 ! source J0 * E
5389 do idir=sdim,3
5390 !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
5391 call multiplyambicoef(ixi^l,ixo^l,axb(ixi^s,idir),wct,x)
5392 w(ixo^s,e_)=w(ixo^s,e_)+qdt*axb(ixo^s,idir)*block%J0(ixo^s,idir)
5393 enddo
5394 endif
5395 end if
5396
5397
5398 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
5399
5400 end subroutine add_source_b0split
5401
5402 !> Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176
5403 subroutine add_source_semirelativistic(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5405 use mod_geometry
5406
5407 integer, intent(in) :: ixi^l, ixo^l
5408 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5409 double precision, intent(inout) :: w(ixi^s,1:nw)
5410 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
5411
5412 double precision :: e(ixi^s,1:3),curle(ixi^s,1:3),dive(ixi^s)
5413 integer :: idir, idirmin, ix^d
5414
5415 ! if ndir<3 the source is zero
5416 {^ifthreec
5417 {do ix^db=iximin^db,iximax^db\}
5418 ! E=Bxv
5419 e(ix^d,1)=w(ix^d,b2_)*wctprim(ix^d,m3_)-w(ix^d,b3_)*wctprim(ix^d,m2_)
5420 e(ix^d,2)=w(ix^d,b3_)*wctprim(ix^d,m1_)-w(ix^d,b1_)*wctprim(ix^d,m3_)
5421 e(ix^d,3)=w(ix^d,b1_)*wctprim(ix^d,m2_)-w(ix^d,b2_)*wctprim(ix^d,m1_)
5422 {end do\}
5423 call divvector(e,ixi^l,ixo^l,dive)
5424 ! curl E
5425 call curlvector(e,ixi^l,ixo^l,curle,idirmin,1,3)
5426 ! add source term in momentum equations (1/c0^2-1/c^2)(E divE - E x curlE)
5427 ! equation (26) and (27)
5428 {do ix^db=ixomin^db,ixomax^db\}
5429 w(ix^d,m1_)=w(ix^d,m1_)+qdt*(inv_squared_c0-inv_squared_c)*&
5430 (e(ix^d,1)*dive(ix^d)-e(ix^d,2)*curle(ix^d,3)+e(ix^d,3)*curle(ix^d,2))
5431 w(ix^d,m2_)=w(ix^d,m2_)+qdt*(inv_squared_c0-inv_squared_c)*&
5432 (e(ix^d,2)*dive(ix^d)-e(ix^d,3)*curle(ix^d,1)+e(ix^d,1)*curle(ix^d,3))
5433 w(ix^d,m3_)=w(ix^d,m3_)+qdt*(inv_squared_c0-inv_squared_c)*&
5434 (e(ix^d,3)*dive(ix^d)-e(ix^d,1)*curle(ix^d,2)+e(ix^d,2)*curle(ix^d,1) )
5435 {end do\}
5436 }
5437
5438 end subroutine add_source_semirelativistic
5439
5440 !> Source terms for internal energy version of MHD
5441 subroutine add_source_internal_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5443 use mod_geometry
5444
5445 integer, intent(in) :: ixi^l, ixo^l
5446 double precision, intent(in) :: qdt
5447 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5448 double precision, intent(inout) :: w(ixi^s,1:nw)
5449 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5450
5451 double precision :: divv(ixi^s), tmp
5452 integer :: ix^d
5453
5454 if(slab_uniform) then
5455 if(nghostcells .gt. 2) then
5456 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,3)
5457 else
5458 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,2)
5459 end if
5460 else
5461 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv)
5462 end if
5463 {do ix^db=ixomin^db,ixomax^db\}
5464 tmp=w(ix^d,e_)
5465 w(ix^d,e_)=w(ix^d,e_)-qdt*wctprim(ix^d,p_)*divv(ix^d)
5466 if(w(ix^d,e_)<small_e) then
5467 w(ix^d,e_)=tmp
5468 end if
5469 {end do\}
5470 if(mhd_ambipolar_sts)then
5471 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
5472 end if
5473
5474 if(fix_small_values) then
5475 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'add_source_internal_e')
5476 end if
5477 end subroutine add_source_internal_e
5478
5479 !> Source terms for hydrodynamic energy version of MHD
5480 subroutine add_source_hydrodynamic_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5482 use mod_geometry
5483 use mod_usr_methods, only: usr_gravity
5484
5485 integer, intent(in) :: ixi^l, ixo^l
5486 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5487 double precision, intent(inout) :: w(ixi^s,1:nw)
5488 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
5489
5490 double precision :: b(ixi^s,3), j(ixi^s,3), jxb(ixi^s,3)
5491 double precision :: current(ixi^s,7-2*ndir:3)
5492 double precision :: bu(ixo^s,1:ndir), tmp(ixo^s), b2(ixo^s)
5493 double precision :: gravity_field(ixi^s,1:ndir), vaoc
5494 integer :: idir, idirmin, idims, ix^d
5495
5496 {^nothreed
5497 b=0.0d0
5498 do idir = 1, ndir
5499 b(ixo^s, idir) = wct(ixo^s,mag(idir))
5500 end do
5501
5502 if(slab_uniform)then
5503 ! get current in fourth order accuracy in Cartesian
5504 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
5505 else
5506 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5507 endif
5508
5509 j=0.0d0
5510 do idir=7-2*ndir,3
5511 j(ixo^s,idir)=current(ixo^s,idir)
5512 end do
5513
5514 ! get Lorentz force JxB
5515 call cross_product(ixi^l,ixo^l,j,b,jxb)
5516 }
5517 {^ifthreed
5518 if(slab_uniform)then
5519 ! get current in fourth order accuracy in Cartesian
5520 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,1,ndir,.true.)
5521 else
5522 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5523 endif
5524 ! get Lorentz force JxB
5525 call cross_product(ixi^l,ixo^l,current,wct(ixi^s,mag(1:ndir)),jxb)
5526 }
5527
5528 ! mhd_semirelativistic does not combine with mhd_hydrodynamic_e
5529 !!if(mhd_semirelativistic) then
5530 !! ! (v . nabla) v
5531 !! do idir=1,ndir
5532 !! do idims=1,ndim
5533 !! call gradient(wCTprim(ixI^S,mom(idir)),ixI^L,ixO^L,idims,J(ixI^S,idims))
5534 !! end do
5535 !! B(ixO^S,idir)=sum(wCTprim(ixO^S,mom(1:ndir))*J(ixO^S,1:ndir),dim=ndim+1)
5536 !! end do
5537 !! ! nabla p
5538 !! do idir=1,ndir
5539 !! call gradient(wCTprim(ixI^S,p_),ixI^L,ixO^L,idir,J(ixI^S,idir))
5540 !! end do
5541 !! if(mhd_gravity) then
5542 !! gravity_field=0.d0
5543 !! call usr_gravity(ixI^L,ixO^L,wCT,x,gravity_field(ixI^S,1:ndim))
5544 !! do idir=1,ndir
5545 !! 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)
5546 !! end do
5547 !! else
5548 !! do idir=1,ndir
5549 !! B(ixO^S,idir)=wCT(ixO^S,rho_)*B(ixO^S,idir)+J(ixO^S,idir)-JxB(ixO^S,idir)
5550 !! end do
5551 !! end if
5552 !! b2(ixO^S)=sum(wCT(ixO^S,mag(:))**2,dim=ndim+1)
5553 !! tmp(ixO^S)=sqrt(b2(ixO^S))
5554 !! where(tmp(ixO^S)>smalldouble)
5555 !! tmp(ixO^S)=1.d0/tmp(ixO^S)
5556 !! else where
5557 !! tmp(ixO^S)=0.d0
5558 !! end where
5559 !! ! unit vector of magnetic field
5560 !! do idir=1,ndir
5561 !! bu(ixO^S,idir)=wCT(ixO^S,mag(idir))*tmp(ixO^S)
5562 !! end do
5563 !! !b2(ixO^S)=b2(ixO^S)/w(ixO^S,rho_)*inv_squared_c
5564 !! !b2(ixO^S)=b2(ixO^S)/(1.d0+b2(ixO^S))
5565 !! {do ix^DB=ixOmin^DB,ixOmax^DB\}
5566 !! ! Va^2/c^2
5567 !! Vaoc=b2(ix^D)/w(ix^D,rho_)*inv_squared_c
5568 !! ! Va^2/c^2 / (1+Va^2/c^2)
5569 !! b2(ix^D)=Vaoc/(1.d0+Vaoc)
5570 !! {end do\}
5571 !! ! bu . F
5572 !! tmp(ixO^S)=sum(bu(ixO^S,1:ndir)*B(ixO^S,1:ndir),dim=ndim+1)
5573 !! ! Rempel 2017 ApJ 834, 10 equation (54)
5574 !! do idir=1,ndir
5575 !! J(ixO^S,idir)=b2(ixO^S)*(B(ixO^S,idir)-bu(ixO^S,idir)*tmp(ixO^S))
5576 !! end do
5577 !! !! Rempel 2017 ApJ 834, 10 equation (29) add SR force at momentum equation
5578 !! do idir=1,ndir
5579 !! w(ixO^S,mom(idir))=w(ixO^S,mom(idir))+qdt*J(ixO^S,idir)
5580 !! end do
5581 !! ! Rempel 2017 ApJ 834, 10 equation (30) add work of Lorentz force and SR force
5582 !! w(ixO^S,e_)=w(ixO^S,e_)+qdt*sum(wCTprim(ixO^S,mom(1:ndir))*&
5583 !! (JxB(ixO^S,1:ndir)+J(ixO^S,1:ndir)),dim=ndim+1)
5584 !!else
5585 ! add work of Lorentz force
5586 w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*jxb(ixo^s,1:ndir),dim=ndim+1)
5587 !!end if
5588
5589 if(mhd_ambipolar_sts)then
5590 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
5591 end if
5592
5593 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hydrodynamic_e')
5594
5595 end subroutine add_source_hydrodynamic_e
5596
5597 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
5598 !> each direction, non-conservative. Uses the generic Laplacian
5599 !> with fourth order central difference (on uniform cartesian) for the laplacian. Then the
5600 !> stencil is 5 (2 neighbours). NOTE: Unused subroutine!
5601 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
5603 use mod_usr_methods
5604 use mod_geometry
5605
5606 integer, intent(in) :: ixi^l, ixo^l
5607 double precision, intent(in) :: qdt
5608 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5609 double precision, intent(inout) :: w(ixi^s,1:nw)
5610
5611 integer :: ixa^l,idir,jdir,kdir,idirmin,idim
5612 double precision :: tmp(ixi^s),tmp2(ixi^s)
5613
5614 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5615 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
5616 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
5617 double precision :: lapl_vec(ixi^s,1:ndir)
5618
5619 ! Calculating resistive sources involves one extra layer
5620 ! asking here for two, so Cartesian works with 4th order CD
5621 ixa^l=ixo^l^ladd2;
5622
5623 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5624 call mpistop("Error in add_source_res1: Non-conforming input limits")
5625
5626 ! Calculate current density and idirmin
5627 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5628
5629 if (mhd_eta>zero)then
5630 eta(ixa^s)=mhd_eta
5631 gradeta(ixo^s,1:ndim)=zero
5632 else
5633 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
5634 do idim=1,ndim
5635 call gradient(eta,ixi^l,ixo^l,idim,tmp)
5636 gradeta(ixo^s,idim)=tmp(ixo^s)
5637 end do
5638 end if
5639
5640 if(b0field) then
5641 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
5642 else
5643 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
5644 end if
5645
5646 call laplacian_of_vector(bf,ixi^l,ixo^l,lapl_vec)
5647
5648 do idir=1,ndir
5649 ! Multiply by eta to store eta*Laplace B_idir
5650 tmp(ixo^s)=lapl_vec(ixo^s,idir)*eta(ixo^s)
5651
5652 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
5653 if (mhd_eta<zero)then
5654 do jdir=1,ndim; do kdir=idirmin,3
5655 if (lvc(idir,jdir,kdir)/=0)then
5656 if (lvc(idir,jdir,kdir)==1)then
5657 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
5658 else
5659 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
5660 end if
5661 end if
5662 end do; end do
5663 end if
5664
5665 ! Add sources related to eta*laplB-grad(eta) x J to B and e
5666 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
5667 if(total_energy) then
5668 w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
5669 end if
5670 end do ! idir
5671
5672 if(mhd_energy) then
5673 ! de/dt+=eta*J**2
5674 w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
5675 end if
5676
5677 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
5678
5679 end subroutine add_source_res1
5680
5681 !> Add resistive source to w within ixO in an explicit fashion
5682 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
5683 subroutine add_source_res_exp(qdt,ixI^L,ixO^L,wCT,w,x)
5685 use mod_usr_methods
5686 use mod_geometry
5687
5688 integer, intent(in) :: ixi^l, ixo^l
5689 double precision, intent(in) :: qdt
5690 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5691 double precision, intent(inout) :: w(ixi^s,1:nw)
5692
5693 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5694 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
5695 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
5696 integer :: ixa^l,idir,idirmin,idirmin1
5697
5698 ixa^l=ixo^l^ladd2;
5699
5700 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5701 call mpistop("Error in add_source_res_exp: Non-conforming input limits")
5702
5703 ixa^l=ixo^l^ladd1;
5704 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
5705 ! Determine exact value of idirmin while doing the loop.
5706 call get_current(wct,ixi^l,ixa^l,idirmin,current)
5707
5708 tmpvec=zero
5709 if(mhd_eta>zero)then
5710 do idir=idirmin,3
5711 tmpvec(ixa^s,idir)=current(ixa^s,idir)*mhd_eta
5712 end do
5713 else
5714 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
5715 do idir=idirmin,3
5716 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
5717 end do
5718 end if
5719
5720 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
5721 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
5722 if(stagger_grid) then
5723 if(ndim==2.and.ndir==3) then
5724 ! if 2.5D
5725 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
5726 end if
5727 else
5728 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
5729 end if
5730
5731 if(mhd_energy) then
5732 if(mhd_eta>zero)then
5733 tmp(ixo^s)=qdt*mhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
5734 else
5735 tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
5736 end if
5737 if(total_energy) then
5738 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
5739 ! de1/dt= eta J^2 - B1 dot curl(eta J)
5740 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
5741 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
5742 else
5743 ! add eta*J**2 source term in the internal energy equation
5744 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
5745 end if
5746 end if
5747
5748 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res_exp')
5749 end subroutine add_source_res_exp
5750
5751
5752 !> Add ambipolar source to w within ixO in an explicit fashion
5753 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
5754 subroutine add_source_ambi_exp(qdt,ixI^L,ixO^L,wCT,w,x)
5756 use mod_usr_methods
5757 use mod_geometry
5758
5759 integer, intent(in) :: ixi^l, ixo^l
5760 double precision, intent(in) :: qdt
5761 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5762 double precision, intent(inout) :: w(ixi^s,1:nw)
5763
5764 double precision :: current(ixi^s,1:3),curlj(ixi^s,1:3)
5765 double precision :: tmpvec(ixi^s,1:3),tmp(ixi^s),btot2(ixi^s)
5766 integer :: ixa^l,idir,idirmin1
5767
5768 ixa^l=ixo^l^ladd2;
5769
5770 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5771 call mpistop("Error in add_source_ambi_exp: Non-conforming input limits")
5772
5773 ixa^l=ixo^l^ladd1;
5774 ! Calculate -J_perpB = (JxB)xB
5775 call mhd_get_jxbxb(wct,x,ixi^l,ixa^l,current)
5776
5777 tmpvec=current
5778 do idir=1,3
5779 !set electric field in tmpvec : E=nuA * jxbxb, where nuA=-etaA/rho^2
5780 !tmpvec(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
5781 call multiplyambicoef(ixi^l,ixa^l,tmpvec(ixi^s,idir),wct,x)
5782 end do
5783
5784 ! dB/dt= -curl(J_perpB*etaA), thus B_i=B_i-eps_ijk d_j Jeta_k
5785 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
5786 if(stagger_grid) then
5787 if(ndim==2.and.ndir==3) then
5788 ! if 2.5D
5789 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
5790 end if
5791 else
5792 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
5793 end if
5794
5795 if(mhd_energy) then
5796 ! compute ambipolar heating term: nuA* J_perpB^2/ B^2
5797 ! avoiding nulls here
5798 btot2(ixa^s)=mhd_mag_en_all(wct,ixi^l,ixa^l)
5799 where (btot2(ixa^s)>smalldouble )
5800 tmp(ixa^s) = sum(current(ixa^s,1:3)**2,dim=ndim+1) / btot2(ixa^s)
5801 elsewhere
5802 tmp(ixa^s) = zero
5803 endwhere
5804 ! multiply with nuA where nuA=-etaA/rho^2
5805 call multiplyambicoef(ixi^l,ixa^l,tmp,wct,x)
5806 ! compensate - sign and add timestep
5807 tmp(ixo^s)=-qdt*tmp(ixo^s)
5808 if(total_energy) then
5809 ! de/dt= +div(B x E_ambi) = eta J^2 - B dot curl(eta J)
5810 ! de1/dt= eta J^2 - B1 dot curl(eta J)
5811 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
5812 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
5813 else
5814 ! add eta*J**2 source term in the internal or hydrodynamic energy equation
5815 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
5816 end if
5817 end if
5818
5819 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_ambi_exp')
5820 end subroutine add_source_ambi_exp
5821
5822 !> Add Hyper-resistive source to w within ixO
5823 !> Uses 9 point stencil (4 neighbours) in each direction.
5824 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
5826 use mod_geometry
5827
5828 integer, intent(in) :: ixi^l, ixo^l
5829 double precision, intent(in) :: qdt
5830 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5831 double precision, intent(inout) :: w(ixi^s,1:nw)
5832 !.. local ..
5833 double precision :: current(ixi^s,7-2*ndir:3)
5834 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
5835 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
5836
5837 ixa^l=ixo^l^ladd3;
5838 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5839 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
5840
5841 call get_current(wct,ixi^l,ixa^l,idirmin,current)
5842 tmpvec(ixa^s,1:ndir)=zero
5843 do jdir=idirmin,3
5844 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
5845 end do
5846
5847 ixa^l=ixo^l^ladd2;
5848 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
5849
5850 ixa^l=ixo^l^ladd1;
5851 tmpvec(ixa^s,1:ndir)=zero
5852 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
5853 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mhd_eta_hyper
5854
5855 ixa^l=ixo^l;
5856 tmpvec2(ixa^s,1:ndir)=zero
5857 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
5858
5859 do idir=1,ndir
5860 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
5861 end do
5862
5863 if(total_energy) then
5864 ! de/dt= +div(B x Ehyper)
5865 ixa^l=ixo^l^ladd1;
5866 tmpvec2(ixa^s,1:ndir)=zero
5867 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
5868 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
5869 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
5870 end do; end do; end do
5871 tmp(ixo^s)=zero
5872 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
5873 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
5874 end if
5875
5876 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
5877
5878 end subroutine add_source_hyperres
5879
5880 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
5881 ! Add divB related sources to w within ixO
5882 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
5883 ! giving the EGLM-MHD scheme or GLM-MHD scheme
5885 use mod_geometry
5886
5887 integer, intent(in) :: ixi^l, ixo^l
5888 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5889 double precision, intent(inout) :: w(ixi^s,1:nw)
5890
5891 double precision:: divb(ixi^s), gradpsi(ixi^s), ba(ixo^s,1:ndir)
5892 integer :: idir
5893
5894
5895 ! dPsi/dt = - Ch^2/Cp^2 Psi
5896 if (mhd_glm_alpha < zero) then
5897 w(ixo^s,psi_) = abs(mhd_glm_alpha)*wct(ixo^s,psi_)
5898 else
5899 ! implicit update of Psi variable
5900 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
5901 if(slab_uniform) then
5902 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
5903 else
5904 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
5905 end if
5906 end if
5907
5908 if(mhd_glm_extended) then
5909 if(b0field) then
5910 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
5911 else
5912 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))
5913 end if
5914 ! gradient of Psi
5915 if(total_energy) then
5916 do idir=1,ndim
5917 select case(typegrad)
5918 case("central")
5919 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
5920 case("limited")
5921 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
5922 end select
5923 ! e = e -qdt (b . grad(Psi))
5924 w(ixo^s,e_) = w(ixo^s,e_)-qdt*ba(ixo^s,idir)*gradpsi(ixo^s)
5925 end do
5926 end if
5927
5928 ! We calculate now div B
5929 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
5930
5931 ! m = m - qdt b div b
5932 do idir=1,ndir
5933 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*ba(ixo^s,idir)*divb(ixo^s)
5934 end do
5935 end if
5936
5937 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
5938
5939 end subroutine add_source_glm
5940
5941 !> Add divB related sources to w within ixO corresponding to Powel
5942 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
5944
5945 integer, intent(in) :: ixi^l, ixo^l
5946 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5947 double precision, intent(inout) :: w(ixi^s,1:nw)
5948
5949 double precision :: divb(ixi^s), ba(1:ndir)
5950 integer :: idir, ix^d
5951
5952 ! calculate div B
5953 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
5954
5955 if(b0field) then
5956 {do ix^db=ixomin^db,ixomax^db\}
5957 ! b = b - qdt v * div b
5958 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
5959 ! m = m - qdt b div b
5960 ^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)\
5961 if (total_energy) then
5962 ! e = e - qdt (v . b) * div b
5963 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)
5964 end if
5965 {end do\}
5966 else
5967 {do ix^db=ixomin^db,ixomax^db\}
5968 ! b = b - qdt v * div b
5969 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
5970 ! m = m - qdt b div b
5971 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)-qdt*wct(ix^d,b^c_)*divb(ix^d)\
5972 if (total_energy) then
5973 ! e = e - qdt (v . b) * div b
5974 w(ix^d,e_)=w(ix^d,e_)-qdt*(^c&wct(ix^d,m^c_)*wct(ix^d,b^c_)+)*divb(ix^d)
5975 end if
5976 {end do\}
5977 end if
5978
5979 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
5980
5981 end subroutine add_source_powel
5982
5983 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
5984 ! Add divB related sources to w within ixO
5985 ! corresponding to Janhunen, just the term in the induction equation.
5987
5988 integer, intent(in) :: ixi^l, ixo^l
5989 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5990 double precision, intent(inout) :: w(ixi^s,1:nw)
5991
5992 double precision :: divb(ixi^s)
5993 integer :: idir, ix^d
5994
5995 ! calculate div B
5996 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
5997
5998 {do ix^db=ixomin^db,ixomax^db\}
5999 ! b = b - qdt v * div b
6000 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6001 {end do\}
6002
6003 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
6004
6005 end subroutine add_source_janhunen
6006
6007 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
6008 ! Add Linde's divB related sources to wnew within ixO
6010 use mod_geometry
6011
6012 integer, intent(in) :: ixi^l, ixo^l
6013 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6014 double precision, intent(inout) :: w(ixi^s,1:nw)
6015
6016 double precision :: divb(ixi^s),graddivb(ixi^s)
6017 integer :: idim, idir, ixp^l, i^d, iside
6018 logical, dimension(-1:1^D&) :: leveljump
6019
6020 ! Calculate div B
6021 ixp^l=ixo^l^ladd1;
6022 call get_divb(wct,ixi^l,ixp^l,divb, mhd_divb_nth)
6023
6024 ! for AMR stability, retreat one cell layer from the boarders of level jump
6025 {do i^db=-1,1\}
6026 if(i^d==0|.and.) cycle
6027 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
6028 leveljump(i^d)=.true.
6029 else
6030 leveljump(i^d)=.false.
6031 end if
6032 {end do\}
6033
6034 ixp^l=ixo^l;
6035 do idim=1,ndim
6036 select case(idim)
6037 {case(^d)
6038 do iside=1,2
6039 i^dd=kr(^dd,^d)*(2*iside-3);
6040 if (leveljump(i^dd)) then
6041 if (iside==1) then
6042 ixpmin^d=ixomin^d-i^d
6043 else
6044 ixpmax^d=ixomax^d-i^d
6045 end if
6046 end if
6047 end do
6048 \}
6049 end select
6050 end do
6051
6052 ! Add Linde's diffusive terms
6053 do idim=1,ndim
6054 ! Calculate grad_idim(divb)
6055 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
6056
6057 {do i^db=ixpmin^db,ixpmax^db\}
6058 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
6059 graddivb(i^d)=graddivb(i^d)*divbdiff/(^d&1.0d0/block%ds({i^d},^d)**2+)
6060
6061 w(i^d,mag(idim))=w(i^d,mag(idim))+graddivb(i^d)
6062
6063 if (typedivbdiff=='all' .and. total_energy) then
6064 ! e += B_idim*eta*grad_idim(divb)
6065 w(i^d,e_)=w(i^d,e_)+wct(i^d,mag(idim))*graddivb(i^d)
6066 end if
6067 {end do\}
6068 end do
6069
6070 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
6071
6072 end subroutine add_source_linde
6073
6074 !> get dimensionless div B = |divB| * volume / area / |B|
6075 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
6076
6078
6079 integer, intent(in) :: ixi^l, ixo^l
6080 double precision, intent(in) :: w(ixi^s,1:nw)
6081 double precision :: divb(ixi^s), dsurface(ixi^s)
6082
6083 double precision :: invb(ixo^s)
6084 integer :: ixa^l,idims
6085
6086 call get_divb(w,ixi^l,ixo^l,divb)
6087 invb(ixo^s)=sqrt(mhd_mag_en_all(w,ixi^l,ixo^l))
6088 where(invb(ixo^s)/=0.d0)
6089 invb(ixo^s)=1.d0/invb(ixo^s)
6090 end where
6091 if(slab_uniform) then
6092 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
6093 else
6094 ixamin^d=ixomin^d-1;
6095 ixamax^d=ixomax^d-1;
6096 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
6097 do idims=1,ndim
6098 ixa^l=ixo^l-kr(idims,^d);
6099 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
6100 end do
6101 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
6102 block%dvolume(ixo^s)/dsurface(ixo^s)
6103 end if
6104
6105 end subroutine get_normalized_divb
6106
6107 !> Calculate idirmin and the idirmin:3 components of the common current array
6108 !> make sure that dxlevel(^D) is set correctly.
6109 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
6111 use mod_geometry
6112
6113 integer, intent(in) :: ixo^l, ixi^l
6114 double precision, intent(in) :: w(ixi^s,1:nw)
6115 integer, intent(out) :: idirmin
6116
6117 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6118 double precision :: current(ixi^s,7-2*ndir:3)
6119 integer :: idir, idirmin0
6120
6121 idirmin0 = 7-2*ndir
6122
6123 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
6124
6125 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
6126 block%J0(ixo^s,idirmin0:3)
6127 end subroutine get_current
6128
6129 !> If resistivity is not zero, check diffusion time limit for dt and similar other effects
6130 subroutine mhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
6132 use mod_usr_methods
6134 use mod_gravity, only: gravity_get_dt
6135 use mod_cak_force, only: cak_get_dt
6136 use mod_fld, only: fld_radforce_get_dt
6137
6138 integer, intent(in) :: ixi^l, ixo^l
6139 double precision, intent(inout) :: dtnew
6140 double precision, intent(in) :: dx^d
6141 double precision, intent(in) :: wprim(ixi^s,1:nw)
6142 double precision, intent(in) :: x(ixi^s,1:ndim)
6143
6144 double precision :: dxarr(ndim)
6145 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6146 integer :: idirmin,idim
6147
6148 dtnew = bigdouble
6149
6150 ^d&dxarr(^d)=dx^d;
6151 if (mhd_eta>zero)then
6152 if(slab_uniform) then
6153 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mhd_eta
6154 else
6155 dtnew=dtdiffpar*minval(block%ds(ixo^s,1:ndim))**2/mhd_eta
6156 end if
6157 else if (mhd_eta<zero)then
6158 call get_current(wprim,ixi^l,ixo^l,idirmin,current)
6159 call usr_special_resistivity(wprim,ixi^l,ixo^l,idirmin,x,current,eta)
6160 dtnew=bigdouble
6161 do idim=1,ndim
6162 if(slab_uniform) then
6163 dtnew=min(dtnew,&
6164 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
6165 else
6166 dtnew=min(dtnew,&
6167 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
6168 end if
6169 end do
6170 end if
6171
6172 if(mhd_eta_hyper>zero) then
6173 if(slab_uniform) then
6174 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mhd_eta_hyper,dtnew)
6175 else
6176 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mhd_eta_hyper,dtnew)
6177 end if
6178 end if
6179
6180 if(mhd_viscosity) then
6181 call viscosity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6182 end if
6183
6184 if(mhd_gravity) then
6185 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6186 end if
6187
6188 if(mhd_ambipolar_exp) then
6189 dtnew=min(dtdiffpar*get_ambipolar_dt(wprim,ixi^l,ixo^l,dx^d,x),dtnew)
6190 endif
6191
6192 if (mhd_cak_force) then
6193 call cak_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6194 end if
6195
6196 if(mhd_radiation_fld) then
6197 call fld_radforce_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x,fld_fl)
6198 endif
6199
6200 end subroutine mhd_get_dt
6201
6202 !> Wrappers for the FLD implicit (MG diffusion) hooks: phys_implicit_update /
6203 !> phys_evaluate_implicit have fixed interfaces with no fluid argument, so
6204 !> these inject the module's fld_fl object into the threaded fld routines.
6205 subroutine mhd_fld_implicit_update(dtfactor,qdt,qtC,psa,psb)
6207 use mod_fld, only: fld_implicit_update
6208 type(state), target :: psa(max_blocks)
6209 type(state), target :: psb(max_blocks)
6210 double precision, intent(in) :: qdt
6211 double precision, intent(in) :: qtc
6212 double precision, intent(in) :: dtfactor
6213
6214 call fld_implicit_update(dtfactor,qdt,qtc,psa,psb,fld_fl)
6215 end subroutine mhd_fld_implicit_update
6216
6217 subroutine mhd_fld_evaluate_implicit(qtC,psa)
6220 type(state), target :: psa(max_blocks)
6221 double precision, intent(in) :: qtc
6222
6223 call fld_evaluate_implicit(qtc,psa,fld_fl)
6224 end subroutine mhd_fld_evaluate_implicit
6225
6226 ! Add geometrical source terms to w
6227 ! Geometric sources to momentum and induction
6228 ! for the regular case, not semi-relativistic, nor any splitting active
6229 ! but possibly no energy equation at all
6230 ! NOTE: Hall terms in induction not handled yet
6231 subroutine mhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6233 use mod_geometry
6236
6237 integer, intent(in) :: ixi^l, ixo^l
6238 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6239 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6240
6241 double precision :: adiabs(ixi^s), gammas(ixi^s)
6242 double precision :: tmp,tmp1,invr,cot
6243 integer :: ix^d
6244 integer :: mr_,mphi_ ! Polar var. names
6245 integer :: br_,bphi_
6246
6247 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6248 br_=mag(1); bphi_=mag(1)-1+phi_
6249
6250 if(.not.mhd_energy) then
6251 if(associated(usr_set_adiab)) then
6252 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6253 else
6254 adiabs=mhd_adiab
6255 end if
6256 if(associated(usr_set_gamma)) then
6257 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6258 else
6259 gammas=eos%gamma
6260 end if
6261 end if
6262
6263 select case (coordinate)
6264 case (cylindrical)
6265 {do ix^db=ixomin^db,ixomax^db\}
6266 ! include dt in invr, invr is always used with qdt
6267 if(local_timestep) then
6268 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6269 else
6270 invr=qdt/x(ix^d,1)
6271 end if
6272 if(mhd_energy) then
6273 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6274 else
6275 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6276 end if
6277 if(phi_>0) then
6278 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6279 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6280 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6281 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6282 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6283 if(.not.stagger_grid) then
6284 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6285 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6286 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6287 end if
6288 else
6289 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6290 end if
6291 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6292 {end do\}
6293 case (spherical)
6294 {do ix^db=ixomin^db,ixomax^db\}
6295 ! include dt in invr, invr is always used with qdt
6296 if(local_timestep) then
6297 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6298 else
6299 invr=qdt/x(ix^d,1)
6300 end if
6301 if(mhd_energy) then
6302 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6303 else
6304 tmp1=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6305 end if
6306 ! m1
6307 {^ifonec
6308 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6309 }
6310 {^noonec
6311 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6312 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6313 }
6314 ! b1
6315 if(mhd_glm) then
6316 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6317 end if
6318 {^ifoned
6319 cot=0.d0
6320 }
6321 {^nooned
6322 cot=1.d0/tan(x(ix^d,2))
6323 }
6324 {^iftwoc
6325 ! m2
6326 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6327 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6328 ! b2
6329 if(.not.stagger_grid) then
6330 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6331 if(mhd_glm) then
6332 tmp=tmp+wprim(ix^d,psi_)*cot
6333 end if
6334 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6335 end if
6336 }
6337 {^ifthreec
6338 ! m2
6339 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6340 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
6341 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
6342 ! b2
6343 if(.not.stagger_grid) then
6344 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6345 if(mhd_glm) then
6346 tmp=tmp+wprim(ix^d,psi_)*cot
6347 end if
6348 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6349 end if
6350 ! m3
6351 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6352 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6353 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6354 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6355 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
6356 ! b3
6357 if(.not.stagger_grid) then
6358 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6359 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6360 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6361 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6362 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6363 end if
6364 }
6365 {end do\}
6366 end select
6367
6368 if (mhd_rotating_frame) then
6369 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6370 end if
6371
6372 end subroutine mhd_add_source_geom
6373
6374 ! Add geometrical source terms to w
6375 ! Geometric sources to momentum and induction
6376 ! for the semi-relativistic, hence no splitting active
6377 ! but possibly no energy equation at all
6378 ! NOTE: Hall terms in induction not handled yet
6379 subroutine mhd_add_source_geom_semirelati(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6381 use mod_geometry
6384
6385 integer, intent(in) :: ixi^l, ixo^l
6386 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6387 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6388
6389 double precision :: adiabs(ixi^s), gammas(ixi^s)
6390 double precision :: tmp,tmp1,tmp2,invr,cot,ef(ixo^s,1:ndir)
6391 integer :: ix^d
6392 integer :: mr_,mphi_ ! Polar var. names
6393 integer :: br_,bphi_
6394
6395 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6396 br_=mag(1); bphi_=mag(1)-1+phi_
6397
6398 if(.not.mhd_energy) then
6399 if(associated(usr_set_adiab)) then
6400 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6401 else
6402 adiabs=mhd_adiab
6403 end if
6404 if(associated(usr_set_gamma)) then
6405 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6406 else
6407 gammas=eos%gamma
6408 end if
6409 end if
6410
6411 select case (coordinate)
6412 case (cylindrical)
6413 {do ix^db=ixomin^db,ixomax^db\}
6414 ! include dt in invr, invr is always used with qdt
6415 if(local_timestep) then
6416 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6417 else
6418 invr=qdt/x(ix^d,1)
6419 end if
6420 if(mhd_energy) then
6421 tmp=wprim(ix^d,p_)
6422 else
6423 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)
6424 end if
6425 ! E=Bxv
6426 {^ifthreec
6427 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
6428 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
6429 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6430 }
6431 {^iftwoc
6432 ef(ix^d,1)=zero
6433 ! store e3 in e2 to count e3 when ^C is from 1 to 2
6434 ef(ix^d,2)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6435 }
6436 {^ifonec
6437 ef(ix^d,1)=zero
6438 }
6439 if(phi_>0) then
6440 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+&
6441 half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c) -&
6442 wprim(ix^d,bphi_)**2+wprim(ix^d,rho_)*wprim(ix^d,mphi_)**2)
6443 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6444 -wprim(ix^d,rho_)*wprim(ix^d,mphi_)*wprim(ix^d,mr_) &
6445 +wprim(ix^d,bphi_)*wprim(ix^d,br_)+ef(ix^d,phi_)*ef(ix^d,1)*inv_squared_c)
6446 if(.not.stagger_grid) then
6447 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6448 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6449 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6450 end if
6451 else
6452 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+half*((^c&wprim(ix^d,b^c_)**2+)+&
6453 (^c&ef(ix^d,^c)**2+)*inv_squared_c))
6454 end if
6455 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6456 {end do\}
6457 case (spherical)
6458 {do ix^db=ixomin^db,ixomax^db\}
6459 ! include dt in invr, invr is always used with qdt
6460 if(local_timestep) then
6461 invr=block%dt(ix^d)*dtfactor/x(ix^d,1)
6462 else
6463 invr=qdt/x(ix^d,1)
6464 end if
6465 ! E=Bxv
6466 {^ifthreec
6467 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
6468 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
6469 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6470 }
6471 {^iftwoc
6472 ! store e3 in e1 to count e3 when ^C is from 1 to 2
6473 ef(ix^d,1)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6474 ef(ix^d,2)=zero
6475 }
6476 {^ifonec
6477 ef(ix^d,1)=zero
6478 }
6479 if(mhd_energy) then
6480 tmp1=wprim(ix^d,p_)+half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c)
6481 else
6482 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)
6483 end if
6484 ! m1
6485 {^ifonec
6486 w(ix^d,m1_)=w(ix^d,m1_)+two*tmp1*invr
6487 }
6488 {^noonec
6489 w(ix^d,m1_)=w(ix^d,m1_)+invr*&
6490 (two*tmp1+(^ce&wprim(ix^d,rho_)*wprim(ix^d,m^ce_)**2-&
6491 wprim(ix^d,b^ce_)**2-ef(ix^d,^ce)**2*inv_squared_c+))
6492 }
6493 ! b1
6494 if(mhd_glm) then
6495 w(ix^d,b1_)=w(ix^d,b1_)+invr*2.0d0*wprim(ix^d,psi_)
6496 end if
6497 {^ifoned
6498 cot=0.d0
6499 }
6500 {^nooned
6501 cot=1.d0/tan(x(ix^d,2))
6502 }
6503 {^iftwoc
6504 ! m2
6505 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_)&
6506 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c)
6507 ! b2
6508 if(.not.stagger_grid) then
6509 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6510 if(mhd_glm) then
6511 tmp=tmp+wprim(ix^d,psi_)*cot
6512 end if
6513 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
6514 end if
6515 }
6516
6517 {^ifthreec
6518 ! m2
6519 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_) &
6520 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c&
6521 +(wprim(ix^d,rho_)*wprim(ix^d,m3_)**2&
6522 -wprim(ix^d,b3_)**2-ef(ix^d,3)**2*inv_squared_c)*cot)
6523 ! b2
6524 if(.not.stagger_grid) then
6525 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6526 if(mhd_glm) then
6527 tmp=tmp+wprim(ix^d,psi_)*cot
6528 end if
6529 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
6530 end if
6531 ! m3
6532 w(ix^d,m3_)=w(ix^d,m3_)+invr*&
6533 (-wprim(ix^d,m3_)*wprim(ix^d,m1_)*wprim(ix^d,rho_) &
6534 +wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6535 +ef(ix^d,3)*ef(ix^d,1)*inv_squared_c&
6536 +(-wprim(ix^d,m2_)*wprim(ix^d,m3_)*wprim(ix^d,rho_) &
6537 +wprim(ix^d,b2_)*wprim(ix^d,b3_)&
6538 +ef(ix^d,2)*ef(ix^d,3)*inv_squared_c)*cot)
6539 ! b3
6540 if(.not.stagger_grid) then
6541 w(ix^d,b3_)=w(ix^d,b3_)+invr*&
6542 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6543 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6544 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6545 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6546 end if
6547 }
6548 {end do\}
6549 end select
6550
6551 if (mhd_rotating_frame) then
6552 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6553 end if
6554
6555 end subroutine mhd_add_source_geom_semirelati
6556
6557 ! Add geometrical source terms to w
6558 ! Geometric sources to momentum and induction
6559 ! for those cases where any kind of splitting (B0field or has_equi_rho_and_p) is active
6560 ! This implies that there is an energy equation included for sure
6561 ! B0field impacts terms in induction equation and geometric sources for them
6562 ! both flags affect the terms in momentum equation, in three variants (TF, TT, FT)
6563 ! NOTE: Hall terms in induction not handled yet
6564 subroutine mhd_add_source_geom_split(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6566 use mod_geometry
6569
6570 integer, intent(in) :: ixi^l, ixo^l
6571 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6572 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6573
6574 double precision :: tmp,tmp1,tmp2,invr,cot
6575 double precision :: adiabs(ixi^s), gammas(ixi^s)
6576 integer :: ix^d
6577 integer :: mr_,mphi_ ! Polar var. names
6578 integer :: br_,bphi_
6579
6580 if(.not.mhd_energy) then
6581 if(associated(usr_set_adiab)) then
6582 call usr_set_adiab(wprim,x,ixi^l,ixo^l,adiabs)
6583 else
6584 adiabs=mhd_adiab
6585 end if
6586 if(associated(usr_set_gamma)) then
6587 call usr_set_gamma(wprim,x,ixi^l,ixo^l,gammas)
6588 else
6589 gammas=eos%gamma
6590 end if
6591 end if
6592
6593 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6594 br_=mag(1); bphi_=mag(1)-1+phi_
6595
6596
6597 select case (coordinate)
6598 case (cylindrical)
6599 {do ix^db=ixomin^db,ixomax^db\}
6600 ! include dt in invr, invr is always used with qdt
6601 if(local_timestep) then
6602 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6603 else
6604 invr=qdt/x(ix^d,1)
6605 end if
6606 if(mhd_energy) then
6607 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6608 else
6609 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6610 end if
6611 if(b0field) tmp=tmp+(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
6612 if(phi_>0) then
6613 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6614 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6615 if(b0field) then
6616 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))
6617 endif
6618 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6619 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6620 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6621 if(b0field) then
6622 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))
6623 endif
6624 if(.not.stagger_grid) then
6625 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6626 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6627 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6628 if(b0field) then
6629 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6630 (block%B0(ix^d,phi_,0)*wprim(ix^d,mr_) &
6631 -block%B0(ix^d,r_,0)*wprim(ix^d,mphi_))
6632 endif
6633 end if
6634 else
6635 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6636 end if
6637 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6638 {end do\}
6639 case (spherical)
6640 {do ix^db=ixomin^db,ixomax^db\}
6641 ! include dt in invr, invr is always used with qdt
6642 if(local_timestep) then
6643 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6644 else
6645 invr=qdt/x(ix^d,1)
6646 end if
6647 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6648 if(b0field) tmp2=(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
6649 ! m1
6650 {^ifonec
6651 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6652 if(b0field) w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp2*invr
6653 }
6654 {^noonec
6655 if(b0field) then
6656 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6657 (two*(tmp1+tmp2)+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+)- &
6658 (^ce&two*block%B0(ix^d,^ce,0)*wprim(ix^d,b^ce_)+))
6659 else
6660 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6661 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6662 end if
6663 }
6664 ! b1
6665 if(mhd_glm) then
6666 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6667 end if
6668 {^ifoned
6669 cot=0.d0
6670 }
6671 {^nooned
6672 cot=1.d0/tan(x(ix^d,2))
6673 }
6674 {^iftwoc
6675 ! m2
6676 if(b0field) then
6677 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6678 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
6679 +wprim(ix^d,b1_)*block%B0(ix^d,2,0))
6680 else
6681 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6682 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6683 end if
6684 ! b2
6685 if(.not.stagger_grid) then
6686 if(b0field) then
6687 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
6688 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
6689 else
6690 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6691 end if
6692 if(mhd_glm) then
6693 tmp=tmp+wprim(ix^d,psi_)*cot
6694 end if
6695 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6696 end if
6697 }
6698 {^ifthreec
6699 ! m2
6700 if(b0field) then
6701 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6702 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
6703 +wprim(ix^d,b1_)*block%B0(ix^d,2,0)&
6704 +(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)
6705 else
6706 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6707 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
6708 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
6709 end if
6710 ! b2
6711 if(.not.stagger_grid) then
6712 if(b0field) then
6713 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
6714 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
6715 else
6716 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6717 end if
6718 if(mhd_glm) then
6719 tmp=tmp+wprim(ix^d,psi_)*cot
6720 end if
6721 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6722 end if
6723 ! m3
6724 if(b0field) then
6725 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6726 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6727 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6728 +block%B0(ix^d,1,0)*wprim(ix^d,b3_) &
6729 +wprim(ix^d,b1_)*block%B0(ix^d,3,0) &
6730 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6731 -wprim(ix^d,b2_)*wprim(ix^d,b3_) &
6732 +block%B0(ix^d,2,0)*wprim(ix^d,b3_) &
6733 +wprim(ix^d,b2_)*block%B0(ix^d,3,0))*cot)
6734 else
6735 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6736 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6737 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6738 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6739 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
6740 end if
6741 ! b3
6742 if(.not.stagger_grid) then
6743 if(b0field) then
6744 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6745 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6746 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6747 +wprim(ix^d,m1_)*block%B0(ix^d,3,0) &
6748 -wprim(ix^d,m3_)*block%B0(ix^d,1,0) &
6749 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6750 -wprim(ix^d,m2_)*wprim(ix^d,b3_) &
6751 +wprim(ix^d,m3_)*block%B0(ix^d,2,0) &
6752 -wprim(ix^d,m2_)*block%B0(ix^d,3,0))*cot)
6753 else
6754 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6755 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6756 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6757 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6758 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6759 end if
6760 end if
6761 }
6762 {end do\}
6763 end select
6764
6765 if (mhd_rotating_frame) then
6766 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6767 end if
6768
6769 end subroutine mhd_add_source_geom_split
6770
6771 !> Compute 2 times total magnetic energy
6772 function mhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
6774 integer, intent(in) :: ixi^l, ixo^l
6775 double precision, intent(in) :: w(ixi^s, nw)
6776 double precision :: mge(ixo^s)
6777
6778 if (b0field) then
6779 mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
6780 else
6781 mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
6782 end if
6783 end function mhd_mag_en_all
6784
6785 subroutine mhd_getv_hall(w,x,ixI^L,ixO^L,vHall,partial)
6787 use mod_geometry
6788
6789 integer, intent(in) :: ixi^l, ixo^l
6790 double precision, intent(in) :: w(ixi^s,nw)
6791 double precision, intent(in) :: x(ixi^s,1:ndim)
6792 double precision, intent(inout) :: vhall(ixi^s,1:ndir)
6793 logical, intent(in), optional :: partial
6794
6795 double precision :: current(ixi^s,7-2*ndir:3)
6796 double precision :: rho(ixi^s)
6797 integer :: idir, idirmin, ix^d
6798 logical :: use_partial
6799
6800 use_partial=.false.
6801 if(present(partial)) use_partial=partial
6802 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
6803 if(.not.use_partial)then
6804 ! Calculate current density and idirmin, including J0 when split
6805 call get_current(w,ixi^l,ixo^l,idirmin,current)
6806 else
6807 if(slab_uniform) then
6808 ! fourth order CD in cartesian
6809 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
6810 else
6811 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir)
6812 endif
6813 endif
6814 do idir = idirmin, ndir
6815 {do ix^db=ixomin^db,ixomax^db\}
6816 vhall(ix^d,idir)=-mhd_etah*current(ix^d,idir)/rho(ix^d)
6817 {end do\}
6818 end do
6819
6820 end subroutine mhd_getv_hall
6821
6822 subroutine mhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
6824 use mod_usr_methods
6825 integer, intent(in) :: ixi^l, ixo^l, idir
6826 double precision, intent(in) :: qt
6827 double precision, intent(inout) :: wlc(ixi^s,1:nw), wrc(ixi^s,1:nw)
6828 double precision, intent(inout) :: wlp(ixi^s,1:nw), wrp(ixi^s,1:nw)
6829 type(state) :: s
6830
6831 double precision :: db(ixo^s), dpsi(ixo^s)
6832 integer :: ix^d
6833
6834 if(stagger_grid) then
6835 {do ix^db=ixomin^db,ixomax^db\}
6836 wlc(ix^d,mag(idir))=s%ws(ix^d,idir)
6837 wrc(ix^d,mag(idir))=s%ws(ix^d,idir)
6838 wlp(ix^d,mag(idir))=s%ws(ix^d,idir)
6839 wrp(ix^d,mag(idir))=s%ws(ix^d,idir)
6840 {end do\}
6841 else
6842 ! Solve the Riemann problem for the linear 2x2 system for normal
6843 ! B-field and GLM_Psi according to Dedner 2002:
6844 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
6845 ! Gives the Riemann solution on the interface
6846 ! for the normal B component and Psi in the GLM-MHD system.
6847 ! 23/04/2013 Oliver Porth
6848 {do ix^db=ixomin^db,ixomax^db\}
6849 db(ix^d)=wrp(ix^d,mag(idir))-wlp(ix^d,mag(idir))
6850 dpsi(ix^d)=wrp(ix^d,psi_)-wlp(ix^d,psi_)
6851 wlp(ix^d,mag(idir))=half*(wrp(ix^d,mag(idir))+wlp(ix^d,mag(idir))-dpsi(ix^d)/cmax_global)
6852 wlp(ix^d,psi_)=half*(wrp(ix^d,psi_)+wlp(ix^d,psi_)-db(ix^d)*cmax_global)
6853 wrp(ix^d,mag(idir))=wlp(ix^d,mag(idir))
6854 wrp(ix^d,psi_)=wlp(ix^d,psi_)
6855 if(total_energy) then
6856 wrc(ix^d,e_)=wrc(ix^d,e_)-half*wrc(ix^d,mag(idir))**2
6857 wlc(ix^d,e_)=wlc(ix^d,e_)-half*wlc(ix^d,mag(idir))**2
6858 end if
6859 wrc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
6860 wrc(ix^d,psi_)=wlp(ix^d,psi_)
6861 wlc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
6862 wlc(ix^d,psi_)=wlp(ix^d,psi_)
6863 ! modify total energy according to the change of magnetic field
6864 if(total_energy) then
6865 wrc(ix^d,e_)=wrc(ix^d,e_)+half*wrc(ix^d,mag(idir))**2
6866 wlc(ix^d,e_)=wlc(ix^d,e_)+half*wlc(ix^d,mag(idir))**2
6867 end if
6868 {end do\}
6869 end if
6870
6871 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
6872
6873 end subroutine mhd_modify_wlr
6874
6875 subroutine mhd_boundary_adjust(igrid,psb)
6877 integer, intent(in) :: igrid
6878 type(state), target :: psb(max_blocks)
6879
6880 integer :: ib, idims, iside, ixo^l, i^d
6881
6882 block=>ps(igrid)
6883 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
6884 do idims=1,ndim
6885 ! to avoid using as yet unknown corner info in more than 1D, we
6886 ! fill only interior mesh ranges of the ghost cell ranges at first,
6887 ! and progressively enlarge the ranges to include corners later
6888 do iside=1,2
6889 i^d=kr(^d,idims)*(2*iside-3);
6890 if (neighbor_type(i^d,igrid)/=1) cycle
6891 ib=(idims-1)*2+iside
6892 if(.not.boundary_divbfix(ib)) cycle
6893 if(any(typeboundary(:,ib)==bc_special)) then
6894 ! MF nonlinear force-free B field extrapolation and data driven
6895 ! require normal B of the first ghost cell layer to be untouched by
6896 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
6897 select case (idims)
6898 {case (^d)
6899 if (iside==2) then
6900 ! maximal boundary
6901 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
6902 ixomax^dd=ixghi^dd;
6903 else
6904 ! minimal boundary
6905 ixomin^dd=ixglo^dd;
6906 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
6907 end if \}
6908 end select
6909 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
6910 end if
6911 end do
6912 end do
6913
6914 end subroutine mhd_boundary_adjust
6915
6916 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
6918
6919 integer, intent(in) :: ixg^l,ixo^l,ib
6920 double precision, intent(inout) :: w(ixg^s,1:nw)
6921 double precision, intent(in) :: x(ixg^s,1:ndim)
6922
6923 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
6924 integer :: ix^d,ixf^l
6925
6926 select case(ib)
6927 case(1)
6928 ! 2nd order CD for divB=0 to set normal B component better
6929 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
6930 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
6931 {^iftwod
6932 ixfmin1=ixomin1+1
6933 ixfmax1=ixomax1+1
6934 ixfmin2=ixomin2+1
6935 ixfmax2=ixomax2-1
6936 if(slab_uniform) then
6937 dx1x2=dxlevel(1)/dxlevel(2)
6938 do ix1=ixfmax1,ixfmin1,-1
6939 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
6940 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
6941 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
6942 enddo
6943 else
6944 do ix1=ixfmax1,ixfmin1,-1
6945 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
6946 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
6947 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
6948 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
6949 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
6950 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
6951 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
6952 end do
6953 end if
6954 }
6955 {^ifthreed
6956 ixfmin1=ixomin1+1
6957 ixfmax1=ixomax1+1
6958 ixfmin2=ixomin2+1
6959 ixfmax2=ixomax2-1
6960 ixfmin3=ixomin3+1
6961 ixfmax3=ixomax3-1
6962 if(slab_uniform) then
6963 dx1x2=dxlevel(1)/dxlevel(2)
6964 dx1x3=dxlevel(1)/dxlevel(3)
6965 do ix1=ixfmax1,ixfmin1,-1
6966 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
6967 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
6968 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
6969 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
6970 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
6971 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
6972 end do
6973 else
6974 do ix1=ixfmax1,ixfmin1,-1
6975 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
6976 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
6977 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
6978 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
6979 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
6980 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
6981 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
6982 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
6983 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
6984 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
6985 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
6986 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
6987 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
6988 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
6989 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
6990 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
6991 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
6992 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
6993 end do
6994 end if
6995 }
6996 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
6997 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
6998 case(2)
6999 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7000 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7001 {^iftwod
7002 ixfmin1=ixomin1-1
7003 ixfmax1=ixomax1-1
7004 ixfmin2=ixomin2+1
7005 ixfmax2=ixomax2-1
7006 if(slab_uniform) then
7007 dx1x2=dxlevel(1)/dxlevel(2)
7008 do ix1=ixfmin1,ixfmax1
7009 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
7010 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7011 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7012 enddo
7013 else
7014 do ix1=ixfmin1,ixfmax1
7015 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
7016 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
7017 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7018 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7019 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7020 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7021 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7022 end do
7023 end if
7024 }
7025 {^ifthreed
7026 ixfmin1=ixomin1-1
7027 ixfmax1=ixomax1-1
7028 ixfmin2=ixomin2+1
7029 ixfmax2=ixomax2-1
7030 ixfmin3=ixomin3+1
7031 ixfmax3=ixomax3-1
7032 if(slab_uniform) then
7033 dx1x2=dxlevel(1)/dxlevel(2)
7034 dx1x3=dxlevel(1)/dxlevel(3)
7035 do ix1=ixfmin1,ixfmax1
7036 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7037 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7038 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7039 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7040 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7041 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7042 end do
7043 else
7044 do ix1=ixfmin1,ixfmax1
7045 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7046 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7047 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7048 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7049 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7050 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7051 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7052 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7053 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7054 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7055 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7056 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7057 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7058 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7059 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7060 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7061 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7062 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7063 end do
7064 end if
7065 }
7066 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7067 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7068 case(3)
7069 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7070 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7071 {^iftwod
7072 ixfmin1=ixomin1+1
7073 ixfmax1=ixomax1-1
7074 ixfmin2=ixomin2+1
7075 ixfmax2=ixomax2+1
7076 if(slab_uniform) then
7077 dx2x1=dxlevel(2)/dxlevel(1)
7078 do ix2=ixfmax2,ixfmin2,-1
7079 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
7080 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7081 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7082 enddo
7083 else
7084 do ix2=ixfmax2,ixfmin2,-1
7085 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
7086 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
7087 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7088 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7089 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7090 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7091 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7092 end do
7093 end if
7094 }
7095 {^ifthreed
7096 ixfmin1=ixomin1+1
7097 ixfmax1=ixomax1-1
7098 ixfmin3=ixomin3+1
7099 ixfmax3=ixomax3-1
7100 ixfmin2=ixomin2+1
7101 ixfmax2=ixomax2+1
7102 if(slab_uniform) then
7103 dx2x1=dxlevel(2)/dxlevel(1)
7104 dx2x3=dxlevel(2)/dxlevel(3)
7105 do ix2=ixfmax2,ixfmin2,-1
7106 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7107 ix2+1,ixfmin3:ixfmax3,mag(2)) &
7108 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7109 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7110 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7111 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7112 end do
7113 else
7114 do ix2=ixfmax2,ixfmin2,-1
7115 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
7116 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
7117 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7118 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
7119 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7120 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7121 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7122 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7123 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7124 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7125 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7126 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7127 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7128 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7129 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7130 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7131 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
7132 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7133 end do
7134 end if
7135 }
7136 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7137 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7138 case(4)
7139 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7140 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7141 {^iftwod
7142 ixfmin1=ixomin1+1
7143 ixfmax1=ixomax1-1
7144 ixfmin2=ixomin2-1
7145 ixfmax2=ixomax2-1
7146 if(slab_uniform) then
7147 dx2x1=dxlevel(2)/dxlevel(1)
7148 do ix2=ixfmin2,ixfmax2
7149 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
7150 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7151 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7152 end do
7153 else
7154 do ix2=ixfmin2,ixfmax2
7155 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
7156 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
7157 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7158 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7159 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7160 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7161 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7162 end do
7163 end if
7164 }
7165 {^ifthreed
7166 ixfmin1=ixomin1+1
7167 ixfmax1=ixomax1-1
7168 ixfmin3=ixomin3+1
7169 ixfmax3=ixomax3-1
7170 ixfmin2=ixomin2-1
7171 ixfmax2=ixomax2-1
7172 if(slab_uniform) then
7173 dx2x1=dxlevel(2)/dxlevel(1)
7174 dx2x3=dxlevel(2)/dxlevel(3)
7175 do ix2=ixfmin2,ixfmax2
7176 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7177 ix2-1,ixfmin3:ixfmax3,mag(2)) &
7178 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7179 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7180 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7181 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7182 end do
7183 else
7184 do ix2=ixfmin2,ixfmax2
7185 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
7186 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
7187 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7188 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
7189 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7190 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7191 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7192 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7193 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7194 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7195 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7196 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7197 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7198 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7199 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7200 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7201 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
7202 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7203 end do
7204 end if
7205 }
7206 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7207 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7208 {^ifthreed
7209 case(5)
7210 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7211 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7212 ixfmin1=ixomin1+1
7213 ixfmax1=ixomax1-1
7214 ixfmin2=ixomin2+1
7215 ixfmax2=ixomax2-1
7216 ixfmin3=ixomin3+1
7217 ixfmax3=ixomax3+1
7218 if(slab_uniform) then
7219 dx3x1=dxlevel(3)/dxlevel(1)
7220 dx3x2=dxlevel(3)/dxlevel(2)
7221 do ix3=ixfmax3,ixfmin3,-1
7222 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
7223 ixfmin2:ixfmax2,ix3+1,mag(3)) &
7224 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7225 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7226 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7227 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7228 end do
7229 else
7230 do ix3=ixfmax3,ixfmin3,-1
7231 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
7232 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
7233 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7234 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
7235 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7236 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7237 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7238 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7239 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7240 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7241 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7242 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7243 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7244 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7245 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7246 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7247 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
7248 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7249 end do
7250 end if
7251 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7252 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7253 case(6)
7254 ! if(total_energy) call eos%to_primitive(ixG^L,ixO^L,w,x)
7255 if(total_energy) call eos%to_primitive(ixg^l,ixo^l,w,x)
7256 ixfmin1=ixomin1+1
7257 ixfmax1=ixomax1-1
7258 ixfmin2=ixomin2+1
7259 ixfmax2=ixomax2-1
7260 ixfmin3=ixomin3-1
7261 ixfmax3=ixomax3-1
7262 if(slab_uniform) then
7263 dx3x1=dxlevel(3)/dxlevel(1)
7264 dx3x2=dxlevel(3)/dxlevel(2)
7265 do ix3=ixfmin3,ixfmax3
7266 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
7267 ixfmin2:ixfmax2,ix3-1,mag(3)) &
7268 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7269 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7270 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7271 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7272 end do
7273 else
7274 do ix3=ixfmin3,ixfmax3
7275 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
7276 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
7277 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7278 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
7279 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7280 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7281 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7282 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7283 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7284 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7285 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7286 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7287 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7288 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7289 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7290 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7291 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
7292 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7293 end do
7294 end if
7295 ! if(total_energy) call eos%to_conserved(ixG^L,ixO^L,w,x)
7296 if(total_energy) call eos%to_conserved(ixg^l,ixo^l,w,x)
7297 }
7298 case default
7299 call mpistop("Special boundary is not defined for this region")
7300 end select
7301
7302 end subroutine fixdivb_boundary
7303
7304 {^nooned
7305 subroutine mhd_clean_divb_multigrid(qdt, qt, active)
7306 use mod_forest
7309 use mod_geometry
7310
7311 double precision, intent(in) :: qdt !< Current time step
7312 double precision, intent(in) :: qt !< Current time
7313 logical, intent(inout) :: active !< Output if the source is active
7314
7315 integer :: id
7316 integer, parameter :: max_its = 50
7317 double precision :: residual_it(max_its), max_divb
7318 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
7319 double precision :: res
7320 double precision, parameter :: max_residual = 1d-3
7321 double precision, parameter :: residual_reduction = 1d-10
7322 integer :: iigrid, igrid
7323 integer :: n, nc, lvl, ix^l, ixc^l, idim
7324 type(tree_node), pointer :: pnode
7325
7326 mg%operator_type = mg_laplacian
7327
7328 ! Set boundary conditions
7329 do n = 1, 2*ndim
7330 idim = (n+1)/2
7331 select case (typeboundary(mag(idim), n))
7332 case (bc_symm)
7333 ! d/dx B = 0, take phi = 0
7334 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7335 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7336 case (bc_asymm)
7337 ! B = 0, so grad(phi) = 0
7338 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
7339 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7340 case (bc_cont)
7341 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7342 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7343 case (bc_special)
7344 ! Assume Dirichlet boundary conditions, derivative zero
7345 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7346 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7347 case (bc_periodic)
7348 ! Nothing to do here
7349 case default
7350 write(*,*) "mhd_clean_divb_multigrid warning: unknown boundary type"
7351 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7352 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7353 end select
7354 end do
7355
7356 ix^l=ixm^ll^ladd1;
7357 max_divb = 0.0d0
7358
7359 ! Store divergence of B as right-hand side
7360 do iigrid = 1, igridstail
7361 igrid = igrids(iigrid);
7362 pnode => igrid_to_node(igrid, mype)%node
7363 id = pnode%id
7364 lvl = mg%boxes(id)%lvl
7365 nc = mg%box_size_lvl(lvl)
7366
7367 ! Geometry subroutines expect this to be set
7368 block => ps(igrid)
7369 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7370
7371 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
7373 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
7374 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
7375 end do
7376
7377 ! Solve laplacian(phi) = divB
7378 if(stagger_grid) then
7379 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
7380 mpi_max, icomm, ierrmpi)
7381
7382 if (mype == 0) print *, "Performing multigrid divB cleaning"
7383 if (mype == 0) print *, "iteration vs residual"
7384 ! Solve laplacian(phi) = divB
7385 do n = 1, max_its
7386 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
7387 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
7388 if (residual_it(n) < residual_reduction * max_divb) exit
7389 end do
7390 if (mype == 0 .and. n > max_its) then
7391 print *, "divb_multigrid warning: not fully converged"
7392 print *, "current amplitude of divb: ", residual_it(max_its)
7393 print *, "multigrid smallest grid: ", &
7394 mg%domain_size_lvl(:, mg%lowest_lvl)
7395 print *, "note: smallest grid ideally has <= 8 cells"
7396 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
7397 print *, "note: dx/dy/dz should be similar"
7398 end if
7399 else
7400 do n = 1, max_its
7401 call mg_fas_vcycle(mg, max_res=res)
7402 if (res < max_residual) exit
7403 end do
7404 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
7405 end if
7406
7407
7408 ! Correct the magnetic field
7409 do iigrid = 1, igridstail
7410 igrid = igrids(iigrid);
7411 pnode => igrid_to_node(igrid, mype)%node
7412 id = pnode%id
7413
7414 ! Geometry subroutines expect this to be set
7415 block => ps(igrid)
7416 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7417
7418 ! Compute the gradient of phi
7419 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
7420
7421 if(stagger_grid) then
7422 do idim =1, ndim
7423 ixcmin^d=ixmlo^d-kr(idim,^d);
7424 ixcmax^d=ixmhi^d;
7425 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
7426 ! Apply the correction B* = B - gradient(phi)
7427 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
7428 end do
7429 ! store cell-center magnetic energy
7430 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
7431 ! change cell-center magnetic field
7432 call mhd_face_to_center(ixm^ll,ps(igrid))
7433 else
7434 do idim = 1, ndim
7435 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
7436 end do
7437 ! store cell-center magnetic energy
7438 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
7439 ! Apply the correction B* = B - gradient(phi)
7440 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
7441 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
7442 end if
7443
7444 if(total_energy) then
7445 ! Determine magnetic energy difference
7446 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
7447 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
7448 ! Keep thermal pressure the same
7449 ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
7450 end if
7451 end do
7452
7453 active = .true.
7454
7455 end subroutine mhd_clean_divb_multigrid
7456 }
7457
7458 !> get electric field through averaging neighors to update faces in CT
7459 subroutine mhd_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
7461 use mod_usr_methods
7462
7463 integer, intent(in) :: ixi^l, ixo^l
7464 double precision, intent(in) :: qt,qdt
7465 ! cell-center primitive variables
7466 double precision, intent(in) :: wp(ixi^s,1:nw)
7467 type(state) :: sct, s
7468 type(ct_velocity) :: vcts
7469 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
7470 double precision, intent(inout) :: fe(ixi^s,sdim:3)
7471
7472 double precision :: circ(ixi^s,1:ndim)
7473 ! non-ideal electric field on cell edges
7474 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
7475 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
7476 integer :: idim1,idim2,idir,iwdim1,iwdim2
7477
7478 associate(bfaces=>s%ws,x=>s%x)
7479
7480 ! Calculate contribution to FEM of each edge,
7481 ! that is, estimate value of line integral of
7482 ! electric field in the positive idir direction.
7483
7484 ! if there is resistivity, get eta J
7485 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
7486
7487 ! if there is ambipolar diffusion, get E_ambi
7488 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
7489
7490 do idim1=1,ndim
7491 iwdim1 = mag(idim1)
7492 i1kr^d=kr(idim1,^d);
7493 do idim2=1,ndim
7494 iwdim2 = mag(idim2)
7495 i2kr^d=kr(idim2,^d);
7496 do idir=sdim,3! Direction of line integral
7497 ! Allow only even permutations
7498 if (lvc(idim1,idim2,idir)==1) then
7499 ixcmax^d=ixomax^d;
7500 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7501 ! average cell-face electric field to cell edges
7502 {do ix^db=ixcmin^db,ixcmax^db\}
7503 fe(ix^d,idir)=quarter*&
7504 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
7505 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
7506 ! add resistive electric field at cell edges E=-vxB+eta J
7507 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
7508 ! add ambipolar electric field
7509 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
7510
7511 ! times time step and edge length
7512 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
7513 {end do\}
7514 end if
7515 end do
7516 end do
7517 end do
7518
7519 ! allow user to change inductive electric field, especially for boundary driven applications
7520 if(associated(usr_set_electric_field)) &
7521 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
7522
7523 circ(ixi^s,1:ndim)=zero
7524
7525 ! Calculate circulation on each face
7526 do idim1=1,ndim ! Coordinate perpendicular to face
7527 ixcmax^d=ixomax^d;
7528 ixcmin^d=ixomin^d-kr(idim1,^d);
7529 do idim2=1,ndim
7530 ixa^l=ixc^l-kr(idim2,^d);
7531 do idir=sdim,3 ! Direction of line integral
7532 ! Assemble indices
7533 if(lvc(idim1,idim2,idir)==1) then
7534 ! Add line integrals in direction idir
7535 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7536 +(fe(ixc^s,idir)&
7537 -fe(ixa^s,idir))
7538 else if(lvc(idim1,idim2,idir)==-1) then
7539 ! Add line integrals in direction idir
7540 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7541 -(fe(ixc^s,idir)&
7542 -fe(ixa^s,idir))
7543 end if
7544 end do
7545 end do
7546 {do ix^db=ixcmin^db,ixcmax^db\}
7547 ! Divide by the area of the face to get dB/dt
7548 if(s%surfaceC(ix^d,idim1) > smalldouble) then
7549 ! Time update cell-face magnetic field component
7550 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
7551 end if
7552 {end do\}
7553 end do
7554
7555 end associate
7556
7557 end subroutine mhd_update_faces_average
7558
7559 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
7560 subroutine mhd_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
7562 use mod_usr_methods
7563 use mod_geometry
7564
7565 integer, intent(in) :: ixi^l, ixo^l
7566 double precision, intent(in) :: qt, qdt
7567 ! cell-center primitive variables
7568 double precision, intent(in) :: wp(ixi^s,1:nw)
7569 type(state) :: sct, s
7570 type(ct_velocity) :: vcts
7571 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
7572 double precision, intent(inout) :: fe(ixi^s,sdim:3)
7573
7574 double precision :: circ(ixi^s,1:ndim)
7575 ! electric field at cell centers
7576 double precision :: ecc(ixi^s,sdim:3)
7577 double precision :: ein(ixi^s,sdim:3)
7578 ! gradient of E at left and right side of a cell face
7579 double precision :: el(ixi^s),er(ixi^s)
7580 ! gradient of E at left and right side of a cell corner
7581 double precision :: elc,erc
7582 ! non-ideal electric field on cell edges
7583 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
7584 ! current on cell edges
7585 double precision :: jce(ixi^s,sdim:3)
7586 ! location at cell faces
7587 double precision :: xs(ixgs^t,1:ndim)
7588 double precision :: gradi(ixgs^t)
7589 integer :: ixc^l,ixa^l
7590 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
7591
7592 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
7593
7594 ! if there is resistivity, get eta J
7595 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
7596
7597 ! if there is ambipolar diffusion, get E_ambi
7598 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
7599
7600 if(b0field) then
7601 {do ix^db=iximin^db,iximax^db\}
7602 ! Calculate electric field at cell centers
7603 {^ifthreed
7604 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_)
7605 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_)
7606 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_)
7607 }
7608 {^iftwod
7609 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7610 }
7611 {^ifoned
7612 ecc(ix^d,3)=0.d0
7613 }
7614 {end do\}
7615 else
7616 {do ix^db=iximin^db,iximax^db\}
7617 ! Calculate electric field at cell centers
7618 {^ifthreed
7619 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
7620 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
7621 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7622 }
7623 {^iftwod
7624 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7625 }
7626 {^ifoned
7627 ecc(ix^d,3)=0.d0
7628 }
7629 {end do\}
7630 end if
7631
7632 ! Calculate contribution to FEM of each edge,
7633 ! that is, estimate value of line integral of
7634 ! electric field in the positive idir direction.
7635 ! evaluate electric field along cell edges according to equation (41)
7636 do idim1=1,ndim
7637 iwdim1 = mag(idim1)
7638 i1kr^d=kr(idim1,^d);
7639 do idim2=1,ndim
7640 iwdim2 = mag(idim2)
7641 i2kr^d=kr(idim2,^d);
7642 do idir=sdim,3 ! Direction of line integral
7643 ! Allow only even permutations
7644 if (lvc(idim1,idim2,idir)==1) then
7645 ixcmax^d=ixomax^d;
7646 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7647 ! Assemble indices
7648 ! average cell-face electric field to cell edges
7649 {do ix^db=ixcmin^db,ixcmax^db\}
7650 fe(ix^d,idir)=quarter*&
7651 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
7652 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
7653 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)
7654 {end do\}
7655 ! add slope in idim2 direction from equation (50)
7656 ixamin^d=ixcmin^d;
7657 ixamax^d=ixcmax^d+i1kr^d;
7658 {do ix^db=ixamin^db,ixamax^db\}
7659 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
7660 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
7661 {end do\}
7662 {!dir$ ivdep
7663 do ix^db=ixcmin^db,ixcmax^db\}
7664 if(vnorm(ix^d,idim1)>0.d0) then
7665 elc=el(ix^d)
7666 else if(vnorm(ix^d,idim1)<0.d0) then
7667 elc=el({ix^d+i1kr^d})
7668 else
7669 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
7670 end if
7671 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
7672 erc=er(ix^d)
7673 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
7674 erc=er({ix^d+i1kr^d})
7675 else
7676 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
7677 end if
7678 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
7679 {end do\}
7680
7681 ! add slope in idim1 direction from equation (50)
7682 ixamin^d=ixcmin^d;
7683 ixamax^d=ixcmax^d+i2kr^d;
7684 {do ix^db=ixamin^db,ixamax^db\}
7685 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
7686 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
7687 {end do\}
7688 {!dir$ ivdep
7689 do ix^db=ixcmin^db,ixcmax^db\}
7690 if(vnorm(ix^d,idim2)>0.d0) then
7691 elc=el(ix^d)
7692 else if(vnorm(ix^d,idim2)<0.d0) then
7693 elc=el({ix^d+i2kr^d})
7694 else
7695 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
7696 end if
7697 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
7698 erc=er(ix^d)
7699 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
7700 erc=er({ix^d+i2kr^d})
7701 else
7702 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
7703 end if
7704 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
7705 ! difference between average and upwind interpolated E
7706 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)-ein(ix^d,idir)
7707 ! add resistive electric field at cell edges E=-vxB+eta J
7708 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
7709 ! add ambipolar electric field
7710 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
7711
7712 ! times time step and edge length
7713 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
7714 {end do\}
7715 end if
7716 end do
7717 end do
7718 end do
7719
7721 ! add upwind diffused magnetic energy back to energy
7722 ! calculate current density at cell edges
7723 jce=0.d0
7724 do idim1=1,ndim
7725 do idim2=1,ndim
7726 do idir=sdim,3
7727 if (lvc(idim1,idim2,idir)==0) cycle
7728 ixcmax^d=ixomax^d;
7729 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7730 ixamax^d=ixcmax^d-kr(idir,^d)+1;
7731 ixamin^d=ixcmin^d;
7732 ! current at transverse faces
7733 xs(ixa^s,:)=x(ixa^s,:)
7734 xs(ixa^s,idim2)=x(ixa^s,idim2)+half*s%dx(ixa^s,idim2)
7735 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi)
7736 if (lvc(idim1,idim2,idir)==1) then
7737 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
7738 else
7739 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
7740 end if
7741 end do
7742 end do
7743 end do
7744 do idir=sdim,3
7745 ixcmax^d=ixomax^d;
7746 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7747 ! E dot J on cell edges
7748 ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
7749 ! average from cell edge to cell center
7750 {^ifthreed
7751 if(idir==1) then
7752 {do ix^db=ixomin^db,ixomax^db\}
7753 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1,ix2-1,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
7754 +ein(ix1,ix2-1,ix3-1,idir))
7755 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7756 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7757 {end do\}
7758 else if(idir==2) then
7759 {do ix^db=ixomin^db,ixomax^db\}
7760 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
7761 +ein(ix1-1,ix2,ix3-1,idir))
7762 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7763 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7764 {end do\}
7765 else
7766 {do ix^db=ixomin^db,ixomax^db\}
7767 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2-1,ix3,idir)&
7768 +ein(ix1-1,ix2-1,ix3,idir))
7769 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7770 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7771 {end do\}
7772 end if
7773 }
7774 {^iftwod
7775 !idir=3
7776 {do ix^db=ixomin^db,ixomax^db\}
7777 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,idir)+ein(ix1,ix2-1,idir)&
7778 +ein(ix1-1,ix2-1,idir))
7779 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7780 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7781 {end do\}
7782 }
7783 ! save additional numerical resistive heating to an extra variable
7784 !! if(nwextra>0) then
7785 !! block%w(ixO^S,nw)=block%w(ixO^S,nw)+jce(ixO^S,idir)
7786 !! end if
7787 end do
7788 end if
7789
7790 ! allow user to change inductive electric field, especially for boundary driven applications
7791 if(associated(usr_set_electric_field)) &
7792 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
7793
7794 circ(ixi^s,1:ndim)=zero
7795
7796 ! Calculate circulation on each face
7797 do idim1=1,ndim ! Coordinate perpendicular to face
7798 ixcmax^d=ixomax^d;
7799 ixcmin^d=ixomin^d-kr(idim1,^d);
7800 do idim2=1,ndim
7801 ixa^l=ixc^l-kr(idim2,^d);
7802 do idir=sdim,3 ! Direction of line integral
7803 ! Assemble indices
7804 if(lvc(idim1,idim2,idir)==1) then
7805 ! Add line integrals in direction idir
7806 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7807 +(fe(ixc^s,idir)&
7808 -fe(ixa^s,idir))
7809 else if(lvc(idim1,idim2,idir)==-1) then
7810 ! Add line integrals in direction idir
7811 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7812 -(fe(ixc^s,idir)&
7813 -fe(ixa^s,idir))
7814 end if
7815 end do
7816 end do
7817 {do ix^db=ixcmin^db,ixcmax^db\}
7818 ! Divide by the area of the face to get dB/dt
7819 if(s%surfaceC(ix^d,idim1) > smalldouble) then
7820 ! Time update cell-face magnetic field component
7821 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
7822 end if
7823 {end do\}
7824 end do
7825
7826 end associate
7827
7828 end subroutine mhd_update_faces_contact
7829
7830 !> update faces
7831 subroutine mhd_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
7833 use mod_usr_methods
7835
7836 integer, intent(in) :: ixi^l, ixo^l
7837 double precision, intent(in) :: qt, qdt
7838 ! cell-center primitive variables
7839 double precision, intent(in) :: wp(ixi^s,1:nw)
7840 type(state) :: sct, s
7841 type(ct_velocity) :: vcts
7842 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
7843 double precision, intent(inout) :: fe(ixi^s,sdim:3)
7844
7845 double precision :: vtill(ixi^s,2)
7846 double precision :: vtilr(ixi^s,2)
7847 double precision :: bfacetot(ixi^s,ndim)
7848 double precision :: btill(ixi^s,ndim)
7849 double precision :: btilr(ixi^s,ndim)
7850 double precision :: cp(ixi^s,2)
7851 double precision :: cm(ixi^s,2)
7852 double precision :: circ(ixi^s,1:ndim)
7853 ! non-ideal electric field on cell edges
7854 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
7855 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
7856 integer :: idim1,idim2,idir,ix^d
7857
7858 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
7859 cbarmax=>vcts%cbarmax)
7860
7861 ! Calculate contribution to FEM of each edge,
7862 ! that is, estimate value of line integral of
7863 ! electric field in the positive idir direction.
7864
7865 ! Loop over components of electric field
7866
7867 ! idir: electric field component we need to calculate
7868 ! idim1: directions in which we already performed the reconstruction
7869 ! idim2: directions in which we perform the reconstruction
7870
7871 ! if there is resistivity, get eta J
7872 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
7873
7874 ! if there is ambipolar diffusion, get E_ambi
7875 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
7876
7877 do idir=sdim,3
7878 ! Indices
7879 ! idir: electric field component
7880 ! idim1: one surface
7881 ! idim2: the other surface
7882 ! cyclic permutation: idim1,idim2,idir=1,2,3
7883 ! Velocity components on the surface
7884 ! follow cyclic premutations:
7885 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
7886
7887 ixcmax^d=ixomax^d;
7888 ixcmin^d=ixomin^d-1+kr(idir,^d);
7889
7890 ! Set indices and directions
7891 idim1=mod(idir,3)+1
7892 idim2=mod(idir+1,3)+1
7893
7894 jxc^l=ixc^l+kr(idim1,^d);
7895 ixcp^l=ixc^l+kr(idim2,^d);
7896
7897 ! Reconstruct transverse transport velocities
7898 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
7899 vtill(ixi^s,2),vtilr(ixi^s,2))
7900
7901 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
7902 vtill(ixi^s,1),vtilr(ixi^s,1))
7903
7904 ! Reconstruct magnetic fields
7905 ! Eventhough the arrays are larger, reconstruct works with
7906 ! the limits ixG.
7907 if(b0field) then
7908 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
7909 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
7910 else
7911 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
7912 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
7913 end if
7914 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
7915 btill(ixi^s,idim1),btilr(ixi^s,idim1))
7916
7917 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
7918 btill(ixi^s,idim2),btilr(ixi^s,idim2))
7919
7920 ! Take the maximum characteristic
7921
7922 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
7923 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
7924
7925 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
7926 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
7927
7928
7929 ! Calculate eletric field
7930 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
7931 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
7932 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
7933 /(cp(ixc^s,1)+cm(ixc^s,1)) &
7934 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
7935 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
7936 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
7937 /(cp(ixc^s,2)+cm(ixc^s,2))
7938
7939 ! add resistive electric field at cell edges E=-vxB+eta J
7940 if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
7941 ! add ambipolar electric field
7942 if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
7943
7944 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
7945
7946 if (.not.slab) then
7947 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
7948 fe(ixc^s,idir)=zero
7949 end where
7950 end if
7951
7952 end do
7953
7954 ! allow user to change inductive electric field, especially for boundary driven applications
7955 if(associated(usr_set_electric_field)) &
7956 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
7957
7958 circ(ixi^s,1:ndim)=zero
7959
7960 ! Calculate circulation on each face: interal(fE dot dl)
7961 do idim1=1,ndim ! Coordinate perpendicular to face
7962 ixcmax^d=ixomax^d;
7963 ixcmin^d=ixomin^d-kr(idim1,^d);
7964 do idim2=1,ndim
7965 do idir=sdim,3 ! Direction of line integral
7966 ! Assemble indices
7967 if(lvc(idim1,idim2,idir)/=0) then
7968 hxc^l=ixc^l-kr(idim2,^d);
7969 ! Add line integrals in direction idir
7970 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7971 +lvc(idim1,idim2,idir)&
7972 *(fe(ixc^s,idir)&
7973 -fe(hxc^s,idir))
7974 end if
7975 end do
7976 end do
7977 {do ix^db=ixcmin^db,ixcmax^db\}
7978 ! Divide by the area of the face to get dB/dt
7979 if(s%surfaceC(ix^d,idim1) > smalldouble) then
7980 ! Time update cell-face magnetic field component
7981 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
7982 end if
7983 {end do\}
7984 end do
7985
7986 end associate
7987 end subroutine mhd_update_faces_hll
7988
7989 !> calculate eta J at cell edges
7990 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
7992 use mod_usr_methods
7993 use mod_geometry
7994
7995 integer, intent(in) :: ixi^l, ixo^l
7996 ! cell-center primitive variables
7997 double precision, intent(in) :: wp(ixi^s,1:nw)
7998 type(state), intent(in) :: sct, s
7999 ! current on cell edges
8000 double precision :: jce(ixi^s,sdim:3)
8001
8002 ! current on cell centers
8003 double precision :: jcc(ixi^s,7-2*ndir:3)
8004 ! location at cell faces
8005 double precision :: xs(ixgs^t,1:ndim)
8006 ! resistivity
8007 double precision :: eta(ixi^s)
8008 double precision :: gradi(ixgs^t)
8009 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
8010
8011 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
8012 ! calculate current density at cell edges
8013 jce=0.d0
8014 do idim1=1,ndim
8015 do idim2=1,ndim
8016 do idir=sdim,3
8017 if (lvc(idim1,idim2,idir)==0) cycle
8018 ixcmax^d=ixomax^d;
8019 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8020 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
8021 ixbmin^d=ixcmin^d;
8022 ! current at transverse faces
8023 xs(ixb^s,:)=x(ixb^s,:)
8024 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
8025 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
8026 if (lvc(idim1,idim2,idir)==1) then
8027 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8028 else
8029 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8030 end if
8031 end do
8032 end do
8033 end do
8034 ! get resistivity
8035 if(mhd_eta>zero)then
8036 jce(ixi^s,:)=jce(ixi^s,:)*mhd_eta
8037 else
8038 ixa^l=ixo^l^ladd1;
8039 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
8040 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
8041 ! calculate eta on cell edges
8042 do idir=sdim,3
8043 ixcmax^d=ixomax^d;
8044 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8045 jcc(ixc^s,idir)=0.d0
8046 {do ix^db=0,1\}
8047 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8048 ixamin^d=ixcmin^d+ix^d;
8049 ixamax^d=ixcmax^d+ix^d;
8050 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
8051 {end do\}
8052 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
8053 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
8054 end do
8055 end if
8056
8057 end associate
8058 end subroutine get_resistive_electric_field
8059
8060 !> get ambipolar electric field on cell edges
8061 subroutine get_ambipolar_electric_field(ixI^L,ixO^L,w,x,fE)
8063
8064 integer, intent(in) :: ixi^l, ixo^l
8065 double precision, intent(in) :: w(ixi^s,1:nw)
8066 double precision, intent(in) :: x(ixi^s,1:ndim)
8067 double precision, intent(out) :: fe(ixi^s,sdim:3)
8068
8069 double precision :: jxbxb(ixi^s,1:3)
8070 integer :: idir,ixa^l,ixc^l,ix^d
8071
8072 ixa^l=ixo^l^ladd1;
8073 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,jxbxb)
8074 ! calculate electric field on cell edges from cell centers
8075 do idir=sdim,3
8076 ! set ambipolar electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
8077 ! E_ambi(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
8078 call multiplyambicoef(ixi^l,ixa^l,jxbxb(ixi^s,idir),w,x)
8079 ixcmax^d=ixomax^d;
8080 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8081 fe(ixc^s,idir)=0.d0
8082 {do ix^db=0,1\}
8083 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8084 ixamin^d=ixcmin^d+ix^d;
8085 ixamax^d=ixcmax^d+ix^d;
8086 fe(ixc^s,idir)=fe(ixc^s,idir)+jxbxb(ixa^s,idir)
8087 {end do\}
8088 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0
8089 end do
8090
8091 end subroutine get_ambipolar_electric_field
8092
8093 !> calculate cell-center values from face-center values
8094 subroutine mhd_face_to_center(ixO^L,s)
8096 ! Non-staggered interpolation range
8097 integer, intent(in) :: ixo^l
8098 type(state) :: s
8099
8100 integer :: ix^d
8101
8102 ! calculate cell-center values from face-center values in 2nd order
8103 ! because the staggered arrays have an additional place to the left.
8104 ! Interpolate to cell barycentre using arithmetic average
8105 ! This might be done better later, to make the method less diffusive.
8106 {!dir$ ivdep
8107 do ix^db=ixomin^db,ixomax^db\}
8108 {^ifthreed
8109 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8110 +s%ws(ix1-1,ix2,ix3,1)*s%surfaceC(ix1-1,ix2,ix3,1))
8111 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8112 +s%ws(ix1,ix2-1,ix3,2)*s%surfaceC(ix1,ix2-1,ix3,2))
8113 s%w(ix^d,b3_)=half/s%surface(ix^d,3)*(s%ws(ix^d,3)*s%surfaceC(ix^d,3)&
8114 +s%ws(ix1,ix2,ix3-1,3)*s%surfaceC(ix1,ix2,ix3-1,3))
8115 }
8116 {^iftwod
8117 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8118 +s%ws(ix1-1,ix2,1)*s%surfaceC(ix1-1,ix2,1))
8119 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8120 +s%ws(ix1,ix2-1,2)*s%surfaceC(ix1,ix2-1,2))
8121 }
8122 {end do\}
8123
8124 ! calculate cell-center values from face-center values in 4th order
8125 !do idim=1,ndim
8126 ! gxO^L=ixO^L-2*kr(idim,^D);
8127 ! hxO^L=ixO^L-kr(idim,^D);
8128 ! jxO^L=ixO^L+kr(idim,^D);
8129
8130 ! ! Interpolate to cell barycentre using fourth order central formula
8131 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
8132 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8133 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8134 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8135 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
8136 !end do
8137
8138 ! calculate cell-center values from face-center values in 6th order
8139 !do idim=1,ndim
8140 ! fxO^L=ixO^L-3*kr(idim,^D);
8141 ! gxO^L=ixO^L-2*kr(idim,^D);
8142 ! hxO^L=ixO^L-kr(idim,^D);
8143 ! jxO^L=ixO^L+kr(idim,^D);
8144 ! kxO^L=ixO^L+2*kr(idim,^D);
8145
8146 ! ! Interpolate to cell barycentre using sixth order central formula
8147 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
8148 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
8149 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8150 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8151 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8152 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
8153 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
8154 !end do
8155
8156 end subroutine mhd_face_to_center
8157
8158 !> calculate magnetic field from vector potential
8159 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
8162
8163 integer, intent(in) :: ixis^l, ixi^l, ixo^l
8164 double precision, intent(inout) :: ws(ixis^s,1:nws)
8165 double precision, intent(in) :: x(ixi^s,1:ndim)
8166
8167 double precision :: adummy(ixis^s,1:3)
8168
8169 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
8170
8171 end subroutine b_from_vector_potential
8172
8173end module mod_mhd_phys
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
subroutine cak_init(phys_gamma)
Initialize the module.
subroutine cak_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Check time step for total radiation contribution.
subroutine cak_add_source(qdt, ixil, ixol, wct, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter bigdouble
A very large real number.
subroutine reconstruct(ixil, ixcl, idir, q, ql, qr)
Reconstruct scalar q within ixO^L to 1/2 dx in direction idir Return both left and right reconstructe...
subroutine b_from_vector_potentiala(ixisl, ixil, ixol, ws, x, a)
calculate magnetic field from vector potential A at cell edges
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition mod_convert.t:59
PI (partial-ionisation) ionisation-degree backend for the eos% family.
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
Module for flux conservation near refinement boundaries.
subroutine, public store_flux(igrid, fc, idimlim, nwfluxin)
subroutine, public store_edge(igrid, ixil, fe, idimlim)
Module for flux limited diffusion (FLD)-approximation in Radiation-(Magneto)hydrodynamics simulations...
Definition mod_fld.t:13
logical fld_no_mg
Definition mod_fld.t:33
double precision, public fld_bisect_tol
Tolerance for bisection method for Energy sourceterms This is a percentage of the minimum of gas- and...
Definition mod_fld.t:25
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x, fl)
get dt limit for radiation force and FLD explicit source additions NOTE: w is primitive on entry
Definition mod_fld.t:358
double precision, public fld_diff_tol
Tolerance for radiative Energy diffusion.
Definition mod_fld.t:27
character(len=40) fld_fluxlimiter
flux limiter choice
Definition mod_fld.t:38
character(len=40) fld_opal_table
Definition mod_fld.t:36
double precision, public fld_kappa0
Opacity value when using constant opacity.
Definition mod_fld.t:22
subroutine, public add_fld_rad_force(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
Definition mod_fld.t:220
character(len=40) fld_opacity_law
switches for opacity
Definition mod_fld.t:35
character(len=40) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
Definition mod_fld.t:44
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure, fl)
Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
Definition mod_fld.t:501
logical fld_radforce_split
source split for energy interact and radforce:
Definition mod_fld.t:18
subroutine, public fld_implicit_update(dtfactor, qdt, qtc, psa, psb, fl)
Calling all subroutines to perform the multigrid method Communicates rad_e and diff_coeff to multigri...
Definition mod_fld.t:761
subroutine, public fld_evaluate_implicit(qtc, psa, fl)
inplace update of psa==>F_im(psa)
Definition mod_fld.t:907
subroutine, public fld_init()
Initialising FLD-module Read opacities Initialise Multigrid and adimensionalise kappa.
Definition mod_fld.t:112
integer nth_for_diff_mg
diffusion coefficient stencil control
Definition mod_fld.t:42
Module with basic grid data structures.
Definition mod_forest.t:2
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition mod_forest.t:32
subroutine, public get_divb(w, ixil, ixol, divb, nth_in)
Calculate div B within ixO.
integer, dimension(:), allocatable, public mag
Indices of the magnetic field.
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
integer coordinate
Definition mod_geometry.t:7
subroutine laplacian_of_vector(qvec, ixil, ixol, lapl_qvec)
integer, parameter cylindrical
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
subroutine gradientf(q, x, ixil, ixol, idir, gradq, nth_in, pm_in)
subroutine gradientl(q, ixil, ixol, idir, gradq)
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
double precision arad_norm
Normalised radiation constant.
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
double precision unit_charge
Physical scaling factor for charge.
integer ixghi
Upper index of grid block arrays.
pure subroutine cross_product(ixil, ixol, a, b, axb)
Cross product of two vectors.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
double precision unit_time
Physical scaling factor for time.
double precision unit_density
Physical scaling factor for density.
double precision unit_opacity
Physical scaling factor for Opacity.
integer, parameter unitpar
file handle for IO
double precision unit_mass
Physical scaling factor for mass.
logical use_imex_scheme
whether IMEX in use or not
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
double precision unit_numberdensity
Physical scaling factor for number density.
character(len=std_len) convert_type
Which format to use when converting.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
logical stagger_grid
True for using stagger grid.
double precision const_rad_a
Physical factors useful for radiation fld.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
double precision bdip
amplitude of background dipolar, quadrupolar, octupolar, user's field
integer b0i
background magnetic field location indicator
integer mype
The rank of the current MPI task.
logical local_timestep
each cell has its own timestep or not
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
integer nwauxio
Number of auxiliary variables that are only included in output.
double precision unit_velocity
Physical scaling factor for velocity.
double precision c_norm
Normalised speed of light.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision unit_radflux
Physical scaling factor for radiation flux.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter sdim
starting dimension for electric field
logical phys_trac
Use TRAC for MHD or 1D HD.
logical need_global_cmax
need global maximal wave speed
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical use_multigrid
Use multigrid (only available in 2D and 3D)
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer max_blocks
The maximum number of grid blocks in a processor.
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
integer, parameter unitconvert
double precision unit_erad
Physical scaling factor for radiation energy density.
integer number_equi_vars
number of equilibrium set variables, besides the mag field
integer, parameter ixglo
Lower index of grid block arrays (always 1)
Module for including gravity in (magneto)hydrodynamics simulations.
Definition mod_gravity.t:2
subroutine gravity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Definition mod_gravity.t:81
subroutine gravity_init()
Initialize the module.
Definition mod_gravity.t:26
subroutine gravity_add_source(qdt, ixil, ixol, wct, wctprim, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
Definition mod_gravity.t:43
module mod_magnetofriction.t Purpose: use magnetofrictional method to relax 3D magnetic field to forc...
subroutine magnetofriction_init()
Initialize the module.
Magneto-hydrodynamics module.
Definition mod_mhd_phys.t:2
subroutine, public mhd_get_trad(w, x, ixil, ixol, trad)
Calculates radiation temperature.
integer, public, protected c_
logical, public, protected mhd_gravity
Whether gravity is added.
integer, public, protected fip_
Index of the FIP passive scalar rho*fip in conserved form, fip in primitive form.
logical, public, protected mhd_internal_e
Whether internal energy is solved instead of total energy.
logical, public, protected mhd_glm_extended
Whether extended GLM-MHD is used with additional sources.
logical, public mhd_hyperbolic_tc_constant
character(len=std_len), public, protected type_ct
Method type of constrained transport.
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
subroutine, public mhd_clean_divb_multigrid(qdt, qt, active)
integer, public, protected qpar_
Index of the field-aligned heat flux q_parallel.
logical, public, protected mhd_radiative_cooling
Whether radiative cooling is added.
subroutine, public mhd_e_to_ei(ixil, ixol, w, x)
Transform total energy to internal energy.
double precision, public mhd_adiab
The adiabatic constant.
double precision, public divbdiff
Coefficient of diffusive divB cleaning.
double precision, public mhd_eta_hyper
The MHD hyper-resistivity.
double precision, public, protected mhd_hyperbolic_tc_bmin
Field-strength transition scale for perpendicular closure.
double precision, public, protected rr
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
integer, public, protected mhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
subroutine, public get_normalized_divb(w, ixil, ixol, divb)
get dimensionless div B = |divB| * volume / area / |B|
logical, public numerical_resistive_heating
Whether numerical resistive heating is included when solving partial energy equation.
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
logical, public, protected mhd_rotating_frame
Whether rotating frame is activated.
logical, public, protected mhd_semirelativistic
Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved.
integer, public, protected mhd_divb_nth
Whether divB is computed with a fourth order approximation.
integer, public, protected mhd_n_tracer
Number of tracer species.
integer, public, protected te_
Indices of temperature.
integer, public, protected m
integer, public equi_rho0_
equi vars indices in the stateequi_vars array
integer, public, protected mhd_trac_type
Which TRAC method is used.
logical, public, protected mhd_cak_force
Whether plasma is partially ionized Whether CAK radiation line force is activated.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
integer, public, protected ne_
Index of the electron number density for LTE module.
logical, public, protected mhd_hall
Whether Hall-MHD is used.
type(te_fluid), allocatable, public te_fl_mhd
type of fluid for thermal emission synthesis
logical, public, protected mhd_ambipolar
Whether Ambipolar term is used.
logical, public, protected mhd_hyperbolic_tc
Whether thermal conduction is used.
logical, public, protected mhd_hyperbolic_tc_sat
Whether saturation is considered for hyperbolic TC. When the perpendicular channel is active,...
double precision, public, protected mhd_hyperbolic_tc_kappa_perp_factor
Relative perpendicular hyperbolic-TC coefficient in fixed/strong-field limit: kappa_perp0 = mhd_hyper...
logical, public has_equi_rho_and_p
whether split off equilibrium density and pressure
double precision, public mhd_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
double precision function, dimension(ixo^s), public mhd_mag_en_all(w, ixil, ixol)
Compute 2 times total magnetic energy.
logical, public, protected mhd_radiation_fld
Whether radiation-gas interaction is handled using flux limited diffusion.
subroutine, public multiplyambicoef(ixil, ixol, res, w, x)
multiply res by the ambipolar coefficient The ambipolar coefficient is calculated as -mhd_eta_ambi/rh...
subroutine, public b_from_vector_potential(ixisl, ixil, ixol, ws, x)
calculate magnetic field from vector potential
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
logical, public, protected mhd_viscosity
Whether viscosity is added.
subroutine, public mhd_get_pradiation_from_prim(w, x, ixil, ixol, prad)
Calculate radiation pressure within ixO^L.
double precision, public, protected mhd_reduced_c
Reduced speed of light for semirelativistic MHD: 2% of light speed.
logical, public, protected mhd_energy
Whether an energy equation is used.
logical, public, protected mhd_ambipolar_exp
Whether Ambipolar term is implemented explicitly.
double precision, public mhd_hyperbolic_tc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
logical, public, protected mhd_glm
Whether GLM-MHD is used to control div B.
type(fld_fluid), allocatable, public fld_fl
Radiation fluid object (gas-EoS callbacks for FLD), wired in mhd_link_eos.
logical, public clean_initial_divb
clean initial divB
double precision, public mhd_eta
The MHD resistivity.
logical, public divbwave
Add divB wave in Roe solver.
logical, public, protected mhd_magnetofriction
Whether magnetofriction is added.
double precision, public, protected mhd_trac_mask
Height of the mask used in the TRAC method.
procedure(mask_subroutine), pointer, public usr_mask_ambipolar
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
logical, public, protected mhd_thermal_conduction
Whether thermal conduction is used.
integer, public equi_pe0_
subroutine, public mhd_get_csrad2_prim(w, x, ixil, ixol, csound)
Calculate modified squared fast wave speed for FLD NOTE: w is primitive on entry here!...
integer, public, protected qperp_
Index of the perpendicular heat flux q_perp.
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
character(len=std_len), public, protected mhd_hyperbolic_tc_perp_mode
Perpendicular hyperbolic-TC closure mode: 'off' = disabled 'fixed_reference' = fixed classical ratio ...
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
logical, public, protected mhd_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
logical, public, protected mhd_particles
Whether particles module is added.
integer, public, protected b
subroutine, public mhd_face_to_center(ixol, s)
calculate cell-center values from face-center values
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
subroutine, public get_current(w, ixil, ixol, idirmin, current)
Calculate idirmin and the idirmin:3 components of the common current array make sure that dxlevel(^D)...
double precision, public mhd_etah
Hall resistivity.
subroutine, public mhd_get_v(w, x, ixil, ixol, v)
Calculate v vector.
double precision, public mhd_eta_ambi
The MHD ambipolar coefficient.
logical, public, protected mhd_fip
Whether FIP passive scalar is enabled.
logical, public, protected mhd_hydrodynamic_e
Whether hydrodynamic energy is solved instead of total energy.
integer, public, protected r_e
Index of the radiation energy.
subroutine, public mhd_phys_init()
logical, public, protected mhd_trac
Whether TRAC method is used.
subroutine, public mhd_get_csrad2(w, x, ixil, ixol, csound)
Calculate modified squared sound speed for FLD NOTE: only for diagnostic purposes,...
subroutine, public mhd_get_pthermal_plus_pradiation(w, x, ixil, ixol, pth_plus_prad)
Calculates the sum of the gas pressure and the max Prad tensor element.
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
double precision, public, protected mhd_hyperbolic_tc_coulomb_log
Constant Coulomb logarithm used by the simplified electron-magnetization closure. It is a namelist pa...
integer, public, protected rho_
Index of the density (in the w array)
logical, public, protected b0field_forcefree
B0 field is force-free.
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
integer, public, protected tweight_
logical, public, protected mhd_ambipolar_sts
Whether Ambipolar term is implemented using supertimestepping.
logical, public, protected mhd_hyperbolic_tc_use_perp
Whether the perpendicular hyperbolic-TC channel is enabled.
subroutine, public mhd_ei_to_e(ixil, ixol, w, x)
Transform internal energy to total energy.
integer, public, protected e_
Index of the energy density (-1 if not present)
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
subroutine, public mhd_get_rho(w, x, ixil, ixol, rho)
integer, public, protected psi_
Indices of the GLM psi.
logical, public mhd_equi_thermal
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
Module containing all the particle routines.
subroutine particles_init()
Initialize particle data and parameters.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
Module for including rotating frame in (magneto)hydrodynamics simulations The rotation vector is assu...
subroutine rotating_frame_add_source(qdt, dtfactor, ixil, ixol, wct, w, x)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine rotating_frame_init()
Initialize the module.
Module for handling problematic values in simulations, such as negative pressures.
subroutine, public small_values_average(ixil, ixol, w, x, w_flag, windex)
subroutine, public small_values_error(wprim, x, ixil, ixol, w_flag, subname)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method which can be used for multiple source terms in the governing equatio...
subroutine, public add_sts_method(sts_getdt, sts_set_sources, startvar, nflux, startwbc, nwbc, evolve_b)
subroutine which added programatically a term to be calculated using STS Params: sts_getdt function c...
subroutine, public set_conversion_methods_to_head(sts_before_first_cycle, sts_after_last_cycle)
Set the hooks called before the first cycle and after the last cycle in the STS update This method sh...
subroutine, public set_error_handling_to_head(sts_error_handling)
Set the hook of error handling in the STS update. This method is called before updating the BC....
subroutine, public sts_init()
Initialize sts module.
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
double precision function, public get_tc_dt_mhd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation) Note: also used in 1D MHD (or for neutrals i...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_hd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
double precision time_htc_total
Definition mod_timing.t:27
double precision time_htc0
Definition mod_timing.t:27
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_adiab), pointer usr_set_adiab
procedure(set_adiab), pointer usr_set_gamma
procedure(phys_gravity), pointer usr_gravity
procedure(set_equi_vars), pointer usr_set_equi_vars
procedure(set_electric_field), pointer usr_set_electric_field
The module add viscous source terms and check time step.
subroutine, public viscosity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
procedure(sub_add_source), pointer, public viscosity_add_source
subroutine, public viscosity_init(phys_wider_stencil)
Initialize the module.
Radiation fluid object: gas-EoS callbacks the FLD module needs, wired by the physics module at link t...
Definition mod_fld.t:60
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11