MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_mhd_phys.t
Go to the documentation of this file.
1!> Magneto-hydrodynamics module
3
4#include "amrvac.h"
5
6 use mod_global_parameters, only: std_len, const_c
10 use mod_physics
11 use mod_comm_lib, only: mpistop
13
14 implicit none
15 private
16
17 !> The adiabatic index
18 double precision, public :: mhd_gamma = 5.d0/3.0d0
19 !> The adiabatic constant
20 double precision, public :: mhd_adiab = 1.0d0
21 !> The MHD resistivity
22 double precision, public :: mhd_eta = 0.0d0
23 !> The MHD hyper-resistivity
24 double precision, public :: mhd_eta_hyper = 0.0d0
25 !> Hall resistivity
26 double precision, public :: mhd_etah = 0.0d0
27 !> The MHD ambipolar coefficient
28 double precision, public :: mhd_eta_ambi = 0.0d0
29 !> Height of the mask used in the TRAC method
30 double precision, public, protected :: mhd_trac_mask = 0.d0
31 !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
32 !> taking values within [0, 1]
33 double precision, public :: mhd_glm_alpha = 0.5d0
34 !> Reduced speed of light for semirelativistic MHD: 2% of light speed
35 double precision, public, protected :: mhd_reduced_c = 0.02d0*const_c
36 !> The thermal conductivity kappa in hyperbolic thermal conduction
37 double precision, public :: hypertc_kappa
38 !> Coefficient of diffusive divB cleaning
39 double precision, public :: divbdiff = 0.8d0
40 !> Helium abundance over Hydrogen
41 double precision, public, protected :: he_abundance=0.1d0
42 !> Ionization fraction of H
43 !> H_ion_fr = H+/(H+ + H)
44 double precision, public, protected :: h_ion_fr=1d0
45 !> Ionization fraction of He
46 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
47 double precision, public, protected :: he_ion_fr=1d0
48 !> Ratio of number He2+ / number He+ + He2+
49 !> He_ion_fr2 = He2+/(He2+ + He+)
50 double precision, public, protected :: he_ion_fr2=1d0
51 ! used for eq of state when it is not defined by units,
52 ! the units do not contain terms related to ionization fraction
53 ! and it is p = RR * rho * T
54 double precision, public, protected :: rr=1d0
55 !> gamma minus one and its inverse
56 double precision :: gamma_1, inv_gamma_1
57 !> inverse of squared speed of light c0 and reduced speed of light c
58 double precision :: inv_squared_c0, inv_squared_c
59 !> equi vars indices in the state%equi_vars array
60 integer, public :: equi_rho0_ = -1
61 integer, public :: equi_pe0_ = -1
62 !> Number of tracer species
63 integer, public, protected :: mhd_n_tracer = 0
64 !> Index of the density (in the w array)
65 integer, public, protected :: rho_
66 !> Indices of the momentum density
67 integer, allocatable, public, protected :: mom(:)
68 !> Indices of the momentum density for the form of better vectorization
69 integer, public, protected :: ^c&m^C_
70 !> Index of the energy density (-1 if not present)
71 integer, public, protected :: e_
72 !> Indices of the magnetic field for the form of better vectorization
73 integer, public, protected :: ^c&b^C_
74 !> Index of the gas pressure (-1 if not present) should equal e_
75 integer, public, protected :: p_
76 !> Index of the heat flux q
77 integer, public, protected :: q_
78 !> Indices of the GLM psi
79 integer, public, protected :: psi_
80 !> Index of the radiation energy
81 integer, public, protected :: r_e
82 !> Indices of temperature
83 integer, public, protected :: te_
84 !> Index of the cutoff temperature for the TRAC method
85 integer, public, protected :: tcoff_
86 integer, public, protected :: tweight_
87 !> Indices of the tracers
88 integer, allocatable, public, protected :: tracer(:)
89 !> The number of waves
90 integer :: nwwave=8
91 !> Method type of divb in a integer for good performance
92 integer :: type_divb
93 !> To skip * layer of ghost cells during divB=0 fix for boundary
94 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
95 ! DivB cleaning methods
96 integer, parameter :: divb_none = 0
97 integer, parameter :: divb_multigrid = -1
98 integer, parameter :: divb_glm = 1
99 integer, parameter :: divb_powel = 2
100 integer, parameter :: divb_janhunen = 3
101 integer, parameter :: divb_linde = 4
102 integer, parameter :: divb_lindejanhunen = 5
103 integer, parameter :: divb_lindepowel = 6
104 integer, parameter :: divb_lindeglm = 7
105 integer, parameter :: divb_ct = 8
106 !> Whether an energy equation is used
107 logical, public, protected :: mhd_energy = .true.
108 !> Whether thermal conduction is used
109 logical, public, protected :: mhd_thermal_conduction = .false.
110 !> Whether radiative cooling is added
111 logical, public, protected :: mhd_radiative_cooling = .false.
112 !> Whether thermal conduction is used
113 logical, public, protected :: mhd_hyperbolic_thermal_conduction = .false.
114 !> Whether saturation is considered for hyperbolic TC
115 logical, public, protected :: mhd_htc_sat = .false.
116 !> Whether viscosity is added
117 logical, public, protected :: mhd_viscosity = .false.
118 !> Whether gravity is added
119 logical, public, protected :: mhd_gravity = .false.
120 !> Whether rotating frame is activated
121 logical, public, protected :: mhd_rotating_frame = .false.
122 !> Whether Hall-MHD is used
123 logical, public, protected :: mhd_hall = .false.
124 !> Whether Ambipolar term is used
125 logical, public, protected :: mhd_ambipolar = .false.
126 !> Whether Ambipolar term is implemented using supertimestepping
127 logical, public, protected :: mhd_ambipolar_sts = .false.
128 !> Whether Ambipolar term is implemented explicitly
129 logical, public, protected :: mhd_ambipolar_exp = .false.
130 !> Whether particles module is added
131 logical, public, protected :: mhd_particles = .false.
132 !> Whether magnetofriction is added
133 logical, public, protected :: mhd_magnetofriction = .false.
134 !> Whether GLM-MHD is used to control div B
135 logical, public, protected :: mhd_glm = .false.
136 !> Whether extended GLM-MHD is used with additional sources
137 logical, public, protected :: mhd_glm_extended = .true.
138 !> Whether TRAC method is used
139 logical, public, protected :: mhd_trac = .false.
140 !> Which TRAC method is used
141 integer, public, protected :: mhd_trac_type=1
142 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
143 integer, public, protected :: mhd_trac_finegrid=4
144 !> Whether internal energy is solved instead of total energy
145 logical, public, protected :: mhd_internal_e = .false.
146 !> Whether hydrodynamic energy is solved instead of total energy
147 logical, public, protected :: mhd_hydrodynamic_e = .false.
148 !> Whether divB cleaning sources are added splitting from fluid solver
149 logical, public, protected :: source_split_divb = .false.
150 !> Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved
151 logical, public, protected :: mhd_semirelativistic = .false.
152 !> Whether plasma is partially ionized
153 logical, public, protected :: mhd_partial_ionization = .false.
154 !> Whether CAK radiation line force is activated
155 logical, public, protected :: mhd_cak_force = .false.
156 !> Whether radiation-gas interaction is handled using flux limited diffusion
157 logical, public, protected :: mhd_radiation_fld = .false.
158 !> whether split off equilibrium density and pressure
159 logical, public :: has_equi_rho_and_p = .false.
160 logical, public :: mhd_equi_thermal = .false.
161 !> whether dump full variables (when splitting is used) in a separate dat file
162 logical, public, protected :: mhd_dump_full_vars = .false.
163 !> Whether divB is computed with a fourth order approximation
164 integer, public, protected :: mhd_divb_nth = 1
165 !> Add divB wave in Roe solver
166 logical, public :: divbwave = .true.
167 !> clean initial divB
168 logical, public :: clean_initial_divb = .false.
169 ! remove the below flag and assume default value = .false.
170 ! when eq state properly implemented everywhere
171 ! and not anymore through units
172 logical, public, protected :: eq_state_units = .true.
173 !> To control divB=0 fix for boundary
174 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
175 !> B0 field is force-free
176 logical, public, protected :: b0field_forcefree=.true.
177 !> Whether an total energy equation is used
178 logical :: total_energy = .true.
179 !> Whether numerical resistive heating is included when solving partial energy equation
180 logical, public :: numerical_resistive_heating = .false.
181 !> Whether gravity work is included in energy equation
182 logical :: gravity_energy
183 !> Method type to clean divergence of B
184 character(len=std_len), public, protected :: typedivbfix = 'linde'
185 !> Method type of constrained transport
186 character(len=std_len), public, protected :: type_ct = 'uct_contact'
187 !> Update all equations due to divB cleaning
188 character(len=std_len) :: typedivbdiff = 'all'
189 !> type of fluid for thermal conduction
190 type(tc_fluid), public, allocatable :: tc_fl
191 !> type of fluid for thermal emission synthesis
192 type(te_fluid), public, allocatable :: te_fl_mhd
193 !> type of fluid for radiative cooling
194 type(rc_fluid), public, allocatable :: rc_fl
195
196 !define the subroutine interface for the ambipolar mask
197 abstract interface
198
199 subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
201 integer, intent(in) :: ixi^l, ixo^l
202 double precision, intent(in) :: x(ixi^s,1:ndim)
203 double precision, intent(in) :: w(ixi^s,1:nw)
204 double precision, intent(inout) :: res(ixi^s)
205 end subroutine mask_subroutine
206
207 end interface
208
209 procedure(mask_subroutine), pointer :: usr_mask_ambipolar => null()
210 procedure(sub_convert), pointer :: mhd_to_primitive => null()
211 procedure(sub_convert), pointer :: mhd_to_conserved => null()
212 procedure(sub_small_values), pointer :: mhd_handle_small_values => null()
213 procedure(sub_get_pthermal), pointer :: mhd_get_pthermal => null()
214 procedure(sub_get_pthermal), pointer :: mhd_get_rfactor => null()
215 procedure(sub_get_pthermal), pointer :: mhd_get_temperature=> null()
216 ! Public methods
217 public :: usr_mask_ambipolar
218 public :: mhd_phys_init
219 public :: mhd_get_pthermal
220 public :: mhd_get_temperature
221 public :: mhd_get_v
222 public :: mhd_get_rho
223 public :: mhd_to_conserved
224 public :: mhd_to_primitive
225 public :: mhd_e_to_ei
226 public :: mhd_ei_to_e
227 public :: mhd_face_to_center
228 public :: get_divb
229 public :: get_current
230 !> needed public if we want to use the ambipolar coefficient in the user file
231 public :: multiplyambicoef
232 public :: get_normalized_divb
234 public :: mhd_mag_en_all
235 {^nooned
237 }
238 ! Begin: following relevant for radiative MHD using FLD
239 ! first four are local and only of interest for mod_usr applications
240 ! where they can be used in diagnostics
241 ! NOTE those with _prim expect primitives on entry
243 public :: mhd_get_csrad2
244 public :: mhd_get_trad
246 ! the following used in FLD module
247 ! as pointer phys_get_Rfactor
248 public :: mhd_get_rfactor
249 ! as pointer phys_get_csrad2
250 public :: mhd_get_csrad2_prim
251 ! the following used in FLD modules
252 ! as pointer phys_get_tgas
254 ! End: following relevant for radiative MHD using FLD
256
257contains
258
259 !> Read this module"s parameters from a file
260 subroutine mhd_read_params(files)
262 use mod_particles, only: particles_eta, particles_etah
263 character(len=*), intent(in) :: files(:)
264 integer :: n
265
266 namelist /mhd_list/ mhd_energy, mhd_n_tracer, mhd_gamma, mhd_adiab,&
270 typedivbdiff, type_ct, divbwave, he_abundance, &
273 particles_eta, particles_etah,has_equi_rho_and_p,mhd_equi_thermal,&
279
280 do n = 1, size(files)
281 open(unitpar, file=trim(files(n)), status="old")
282 read(unitpar, mhd_list, end=111)
283111 close(unitpar)
284 end do
285
286 end subroutine mhd_read_params
287
288 !> Write this module's parameters to a snapsoht
289 subroutine mhd_write_info(fh)
291 integer, intent(in) :: fh
292
293 integer :: er
294 integer, parameter :: n_par = 1
295 double precision :: values(n_par)
296 integer, dimension(MPI_STATUS_SIZE) :: st
297 character(len=name_len) :: names(n_par)
298
299 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
300
301 names(1) = "gamma"
302 values(1) = mhd_gamma
303 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
304 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
305 end subroutine mhd_write_info
306
307 subroutine mhd_phys_init()
312 use mod_gravity, only: gravity_init
317 use mod_cak_force, only: cak_init
319 use mod_geometry
321 {^nooned
323 }
324 use mod_fld
325
326 integer :: itr, idir
327
328 call mhd_read_params(par_files)
329
330 if(mhd_internal_e) then
331 if(mhd_hydrodynamic_e) then
332 mhd_hydrodynamic_e=.false.
333 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_internal_e=T'
334 end if
335 if(has_equi_rho_and_p) then
336 has_equi_rho_and_p=.false.
337 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_internal_e=T'
338 end if
339 end if
340
341 if(mhd_hydrodynamic_e) then
342 if(mhd_internal_e) then
343 mhd_internal_e=.false.
344 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_hydrodynamic_e=T'
345 end if
346 if(b0field) then
347 b0field=.false.
348 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_hydrodynamic_e=T'
349 end if
350 if(has_equi_rho_and_p) then
351 has_equi_rho_and_p=.false.
352 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_hydrodynamic_e=T'
353 end if
354 end if
355
356 if(mhd_semirelativistic) then
357 if(b0field) then
358 b0field=.false.
359 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_semirelativistic=T'
360 endif
361 if(has_equi_rho_and_p) then
362 has_equi_rho_and_p=.false.
363 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_semirelativistic=T'
364 end if
365 if(mhd_hydrodynamic_e) then
366 mhd_hydrodynamic_e=.false.
367 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_semirelativistic=T'
368 end if
369 end if
370
371 if(.not. mhd_energy) then
372 if(mhd_internal_e) then
373 mhd_internal_e=.false.
374 if(mype==0) write(*,*) 'WARNING: set mhd_internal_e=F when mhd_energy=F'
375 end if
376 if(mhd_hydrodynamic_e) then
377 mhd_hydrodynamic_e=.false.
378 if(mype==0) write(*,*) 'WARNING: set mhd_hydrodynamic_e=F when mhd_energy=F'
379 end if
382 if(mype==0) write(*,*) 'WARNING: set mhd_thermal_conduction=F when mhd_energy=F'
383 end if
386 if(mype==0) write(*,*) 'WARNING: set mhd_hyperbolic_thermal_conduction=F when mhd_energy=F'
387 end if
388 if(mhd_radiative_cooling) then
390 if(mype==0) write(*,*) 'WARNING: set mhd_radiative_cooling=F when mhd_energy=F'
391 end if
392 if(mhd_trac) then
393 mhd_trac=.false.
394 if(mype==0) write(*,*) 'WARNING: set mhd_trac=F when mhd_energy=F'
395 end if
398 if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when mhd_energy=F'
399 end if
400 if(b0field) then
401 b0field=.false.
402 if(mype==0) write(*,*) 'WARNING: set B0field=F when mhd_energy=F'
403 end if
404 if(has_equi_rho_and_p) then
405 has_equi_rho_and_p=.false.
406 if(mype==0) write(*,*) 'WARNING: set has_equi_rho_and_p=F when mhd_energy=F'
407 end if
408 end if
409 if(.not.eq_state_units) then
412 if(mype==0) write(*,*) 'WARNING: set mhd_partial_ionization=F when eq_state_units=F'
413 end if
414 end if
415
418 if(mype==0) write(*,*) 'WARNING: set either parabolic TC or hyperbolic TC to F'
419 if(mype==0) write(*,*) 'WARNING: defaulting to only mhd_hyperbolic_thermal_conduction=T'
420 end if
421
422
423 physics_type = "mhd"
424 phys_energy=mhd_energy
425 phys_internal_e=mhd_internal_e
428 phys_partial_ionization=mhd_partial_ionization
429
430 phys_gamma = mhd_gamma
432
433 if(mhd_energy) then
435 total_energy=.false.
436 else
438 total_energy=.true.
439 end if
440 else
441 total_energy=.false.
442 end if
443 phys_total_energy=total_energy
444 if(mhd_energy) then
445 if(mhd_internal_e) then
446 gravity_energy=.false.
447 else
448 gravity_energy=.true.
449 end if
450 else
451 gravity_energy=.false.
452 end if
453
454 {^ifoned
455 if(mhd_trac .and. mhd_trac_type .gt. 2) then
457 if(mype==0) write(*,*) 'WARNING: reset mhd_trac_type=1 for 1D simulation'
458 end if
459 }
460 if(mhd_trac .and. mhd_trac_type .le. 4) then
461 mhd_trac_mask=bigdouble
462 if(mype==0) write(*,*) 'WARNING: set mhd_trac_mask==bigdouble for global TRAC method'
463 end if
465
467 if(ndim==1) typedivbfix='none'
468 select case (typedivbfix)
469 case ('none')
470 type_divb = divb_none
471 {^nooned
472 case ('multigrid')
473 if(mhd_radiation_fld) call mpistop('To verify whether mg usage for FLD versus divB can be combined')
474 type_divb = divb_multigrid
475 use_multigrid = .true.
476 mg%operator_type = mg_laplacian
477 phys_global_source_after => mhd_clean_divb_multigrid
478 }
479 case ('glm')
480 mhd_glm = .true.
481 need_global_cmax = .true.
482 type_divb = divb_glm
483 case ('powel', 'powell')
484 type_divb = divb_powel
485 case ('janhunen')
486 type_divb = divb_janhunen
487 case ('linde')
488 type_divb = divb_linde
489 case ('lindejanhunen')
490 type_divb = divb_lindejanhunen
491 case ('lindepowel')
492 type_divb = divb_lindepowel
493 case ('lindeglm')
494 mhd_glm = .true.
495 need_global_cmax = .true.
496 type_divb = divb_lindeglm
497 case ('ct')
498 type_divb = divb_ct
499 stagger_grid = .true.
500 case default
501 call mpistop('Unknown divB fix')
502 end select
503
504
505
506 allocate(start_indices(number_species),stop_indices(number_species))
507 ! set the index of the first flux variable for species 1
508 start_indices(1)=1
509 ! Determine flux variables
510 rho_ = var_set_rho()
511
512 allocate(mom(ndir))
513 mom(:) = var_set_momentum(ndir)
514 m^c_=mom(^c);
515
516 ! Set index of energy variable
517 if (mhd_energy) then
518 nwwave = 8
519 e_ = var_set_energy() ! energy density
520 p_ = e_ ! gas pressure
521 else
522 nwwave = 7
523 e_ = -1
524 p_ = -1
525 end if
526
527 allocate(mag(ndir))
528 mag(:) = var_set_bfield(ndir)
529 b^c_=mag(^c);
530
531 if (mhd_glm) then
532 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
533 else
534 psi_ = -1
535 end if
536
538 ! hyperbolic thermal conduction flux q
539 q_ = var_set_q()
540 need_global_cmax=.true.
541 else
542 q_=-1
543 end if
544
545 allocate(tracer(mhd_n_tracer))
546 ! Set starting index of tracers
547 do itr = 1, mhd_n_tracer
548 tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
549 end do
550
551 if(mhd_radiation_fld)then
552 if(mhd_cak_force)then
553 if(mype==0) then
554 write(*,*)'Warning: CAK force addition together with FLD radiation'
555 endif
556 endif
558 if(mype==0) then
559 write(*,*)'Warning: Optically thin cooling together with FLD radiation'
560 endif
561 endif
562 if(.not.mhd_energy)then
563 call mpistop('using FLD implies the use of an energy equation, set mhd_energy=T')
564 else
566 call mpistop('using FLD not yet with semirelativistic energy formalism')
567 endif
569 call mpistop('using FLD not yet with hydrodynamic or internal energy formalism')
570 endif
571 if(has_equi_rho_and_p)then
572 call mpistop('using FLD not yet with split off rho and p')
573 endif
574 ! Note: so far ok with total energy equation but allow both split or unsplit B0
575 !> set added variable and equation for radiation energy
576 r_e = var_set_radiation_energy()
577 phys_get_tgas => mhd_get_temperature_from_prim
578 phys_get_csrad2 => mhd_get_csrad2_prim
579 !> Initiate radiation-closure module
580 call fld_init(mhd_gamma)
581 endif
582 else
583 r_e=-1
584 endif
585
586 ! set temperature as an auxiliary variable to get ionization degree
588 te_ = var_set_auxvar('Te','Te')
589 else
590 te_ = -1
591 end if
592
593 ! set number of variables which need update ghostcells
594 nwgc=nwflux+nwaux
595
596 ! set the index of the last flux variable for species 1
597 stop_indices(1)=nwflux
598
599 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
600 tweight_ = -1
601 if(mhd_trac) then
602 tcoff_ = var_set_wextra()
603 iw_tcoff=tcoff_
604 if(mhd_trac_type .ge. 3) then
605 tweight_ = var_set_wextra()
606 endif
607 else
608 tcoff_ = -1
609 end if
610
611 ! set indices of equi vars and update number_equi_vars
613 if(has_equi_rho_and_p) then
616 iw_equi_rho = equi_rho0_
619 iw_equi_p = equi_pe0_
620 endif
621 ! determine number of stagger variables
622 nws=ndim
623
624 nvector = 2 ! No. vector vars
625 allocate(iw_vector(nvector))
626 iw_vector(1) = mom(1) - 1
627 iw_vector(2) = mag(1) - 1
628
629 ! Check whether custom flux types have been defined
630 if (.not. allocated(flux_type)) then
631 allocate(flux_type(ndir, nwflux))
632 flux_type = flux_default
633 else if (any(shape(flux_type) /= [ndir, nwflux])) then
634 call mpistop("phys_check error: flux_type has wrong shape")
635 end if
636
637 if(nwflux>mag(ndir)) then
638 ! for flux of tracers, using hll flux
639 flux_type(:,mag(ndir)+1:nwflux)=flux_hll
640 end if
641
642 if(ndim>1) then
643 if(mhd_glm) then
644 flux_type(:,psi_)=flux_special
645 do idir=1,ndir
646 flux_type(idir,mag(idir))=flux_special
647 end do
648 else
649 do idir=1,ndir
650 flux_type(idir,mag(idir))=flux_tvdlf
651 end do
652 end if
653 end if
654
655 phys_get_rho => mhd_get_rho
656 phys_get_dt => mhd_get_dt
657 if(mhd_semirelativistic) then
658 if(mhd_energy) then
659 phys_get_cmax => mhd_get_cmax_semirelati
660 else
661 phys_get_cmax => mhd_get_cmax_semirelati_noe
662 end if
663 else
664 if(mhd_energy) then
665 phys_get_cmax => mhd_get_cmax_origin
666 else
667 phys_get_cmax => mhd_get_cmax_origin_noe
668 end if
669 end if
670 phys_get_tcutoff => mhd_get_tcutoff
671 phys_get_h_speed => mhd_get_h_speed
672 if(has_equi_rho_and_p) then
673 phys_get_cbounds => mhd_get_cbounds_split_rho
674 else if(mhd_semirelativistic) then
675 phys_get_cbounds => mhd_get_cbounds_semirelati
676 else
677 phys_get_cbounds => mhd_get_cbounds
678 end if
679 if(mhd_hydrodynamic_e) then
680 phys_to_primitive => mhd_to_primitive_hde
681 mhd_to_primitive => mhd_to_primitive_hde
682 phys_to_conserved => mhd_to_conserved_hde
683 mhd_to_conserved => mhd_to_conserved_hde
684 else if(mhd_semirelativistic) then
685 if(mhd_energy) then
686 phys_to_primitive => mhd_to_primitive_semirelati
687 mhd_to_primitive => mhd_to_primitive_semirelati
688 phys_to_conserved => mhd_to_conserved_semirelati
689 mhd_to_conserved => mhd_to_conserved_semirelati
690 else
691 phys_to_primitive => mhd_to_primitive_semirelati_noe
692 mhd_to_primitive => mhd_to_primitive_semirelati_noe
693 phys_to_conserved => mhd_to_conserved_semirelati_noe
694 mhd_to_conserved => mhd_to_conserved_semirelati_noe
695 end if
696 else
697 if(has_equi_rho_and_p) then
698 phys_to_primitive => mhd_to_primitive_split_rho
699 mhd_to_primitive => mhd_to_primitive_split_rho
700 phys_to_conserved => mhd_to_conserved_split_rho
701 mhd_to_conserved => mhd_to_conserved_split_rho
702 else if(mhd_internal_e) then
703 phys_to_primitive => mhd_to_primitive_inte
704 mhd_to_primitive => mhd_to_primitive_inte
705 phys_to_conserved => mhd_to_conserved_inte
706 mhd_to_conserved => mhd_to_conserved_inte
707 else if(mhd_energy) then
708 phys_to_primitive => mhd_to_primitive_origin
709 mhd_to_primitive => mhd_to_primitive_origin
710 phys_to_conserved => mhd_to_conserved_origin
711 mhd_to_conserved => mhd_to_conserved_origin
712 else
713 phys_to_primitive => mhd_to_primitive_origin_noe
714 mhd_to_primitive => mhd_to_primitive_origin_noe
715 phys_to_conserved => mhd_to_conserved_origin_noe
716 mhd_to_conserved => mhd_to_conserved_origin_noe
717 end if
718 end if
719 if(mhd_hydrodynamic_e) then
720 phys_get_flux => mhd_get_flux_hde
721 else if(mhd_semirelativistic) then
722 if(mhd_energy) then
723 phys_get_flux => mhd_get_flux_semirelati
724 else
725 phys_get_flux => mhd_get_flux_semirelati_noe
726 end if
727 else
728 if(b0field.or.has_equi_rho_and_p) then
729 phys_get_flux => mhd_get_flux_split
730 else if(mhd_energy) then
731 phys_get_flux => mhd_get_flux
732 else
733 phys_get_flux => mhd_get_flux_noe
734 end if
735 end if
736 phys_get_v => mhd_get_v
737 if(mhd_semirelativistic) then
738 phys_add_source_geom => mhd_add_source_geom_semirelati
739 else if(b0field.or.has_equi_rho_and_p) then
740 phys_add_source_geom => mhd_add_source_geom_split
741 else
742 phys_add_source_geom => mhd_add_source_geom
743 end if
744 phys_add_source => mhd_add_source
745 phys_check_params => mhd_check_params
746 phys_write_info => mhd_write_info
747
748 if(mhd_internal_e) then
749 phys_handle_small_values => mhd_handle_small_values_inte
750 mhd_handle_small_values => mhd_handle_small_values_inte
751 phys_check_w => mhd_check_w_inte
752 else if(mhd_hydrodynamic_e) then
753 phys_handle_small_values => mhd_handle_small_values_hde
754 mhd_handle_small_values => mhd_handle_small_values_hde
755 phys_check_w => mhd_check_w_hde
756 else if(mhd_semirelativistic) then
757 phys_handle_small_values => mhd_handle_small_values_semirelati
758 mhd_handle_small_values => mhd_handle_small_values_semirelati
759 phys_check_w => mhd_check_w_semirelati
760 else if(has_equi_rho_and_p) then
761 phys_handle_small_values => mhd_handle_small_values_split
762 mhd_handle_small_values => mhd_handle_small_values_split
763 phys_check_w => mhd_check_w_split
764 else if(mhd_energy) then
765 phys_handle_small_values => mhd_handle_small_values_origin
766 mhd_handle_small_values => mhd_handle_small_values_origin
767 phys_check_w => mhd_check_w_origin
768 else
769 phys_handle_small_values => mhd_handle_small_values_noe
770 mhd_handle_small_values => mhd_handle_small_values_noe
771 phys_check_w => mhd_check_w_noe
772 end if
773
774 if(mhd_internal_e) then
775 phys_get_pthermal => mhd_get_pthermal_inte
776 mhd_get_pthermal => mhd_get_pthermal_inte
777 else if(mhd_hydrodynamic_e) then
778 phys_get_pthermal => mhd_get_pthermal_hde
779 mhd_get_pthermal => mhd_get_pthermal_hde
780 else if(mhd_semirelativistic) then
781 phys_get_pthermal => mhd_get_pthermal_semirelati
782 mhd_get_pthermal => mhd_get_pthermal_semirelati
783 else if(mhd_energy) then
784 phys_get_pthermal => mhd_get_pthermal_origin
785 mhd_get_pthermal => mhd_get_pthermal_origin
786 else
787 phys_get_pthermal => mhd_get_pthermal_noe
788 mhd_get_pthermal => mhd_get_pthermal_noe
789 end if
790
791 if(number_equi_vars>0) then
792 phys_set_equi_vars => set_equi_vars_grid
793 endif
794
795 if(type_divb==divb_glm) then
796 phys_modify_wlr => mhd_modify_wlr
797 end if
798
799 ! choose Rfactor in ideal gas law
801 mhd_get_rfactor=>rfactor_from_temperature_ionization
802 phys_update_temperature => mhd_update_temperature
803 else if(associated(usr_rfactor)) then
805 else
806 mhd_get_rfactor=>rfactor_from_constant_ionization
807 end if
808
809 phys_get_rfactor=>mhd_get_rfactor
810
812 mhd_get_temperature => mhd_get_temperature_from_te
813 else
814 if(mhd_internal_e) then
815 if(has_equi_rho_and_p) then
816 mhd_get_temperature => mhd_get_temperature_from_eint_with_equi
817 else
818 mhd_get_temperature => mhd_get_temperature_from_eint
819 end if
820 else
822 end if
823 end if
824
825 ! if using ct stagger grid, boundary divb=0 is not done here
826 if(stagger_grid) then
827 select case(type_ct)
828 case('average')
829 transverse_ghost_cells = 1
830 phys_get_ct_velocity => mhd_get_ct_velocity_average
831 phys_update_faces => mhd_update_faces_average
832 case('uct_contact')
833 transverse_ghost_cells = 1
834 phys_get_ct_velocity => mhd_get_ct_velocity_contact
835 phys_update_faces => mhd_update_faces_contact
836 case('uct_hll')
837 transverse_ghost_cells = 2
838 phys_get_ct_velocity => mhd_get_ct_velocity_hll
839 phys_update_faces => mhd_update_faces_hll
840 case default
841 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
842 end select
843 phys_face_to_center => mhd_face_to_center
844 phys_modify_wlr => mhd_modify_wlr
845 else if(ndim>1) then
846 phys_boundary_adjust => mhd_boundary_adjust
847 end if
848
849 {^nooned
850 ! clean initial divb
852 call mpistop('To verify whether mg usage for FLD versus divB can be combined')
853 if(clean_initial_divb) phys_clean_divb => mhd_clean_divb_multigrid
854 }
855
856 ! derive units from basic units
857 call mhd_physical_units()
858
860 if(si_unit)then
861 ! parallel conduction Spitzer
863 else
864 ! in cgs
866 endif
867 end if
868
869 if(mhd_equi_thermal)then
870 if((.not.has_equi_rho_and_p).or.(.not.total_energy))then
871 mhd_equi_thermal=.false.
872 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no splitting or total e in use'
873 else
875 if(mype==0) write(*,*) 'Will subtract thermal balance in TC or RC with mhd_equi_thermal=T'
876 else
877 mhd_equi_thermal=.false.
878 if(mype==0) write(*,*) 'WARNING: turning mhd_equi_thermal=F as no TC or RC in use'
879 endif
880 endif
881 endif
882
883 ! initialize thermal conduction module
884 if (mhd_thermal_conduction) then
885 call sts_init()
887
888 allocate(tc_fl)
889 call tc_get_mhd_params(tc_fl,tc_params_read_mhd)
890 if(ndim==1) then
891 call add_sts_method(mhd_get_tc_dt_hd,mhd_sts_set_source_tc_hd,e_,1,e_,1,.false.)
892 else
893 call add_sts_method(mhd_get_tc_dt_mhd,mhd_sts_set_source_tc_mhd,e_,1,e_,1,.false.)
894 endif
895 if(mhd_internal_e) then
896 if(has_equi_rho_and_p) then
897 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint_with_equi
898 else
899 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_eint
900 end if
901 else
902 tc_fl%get_temperature_from_conserved => mhd_get_temperature_from_etot
903 end if
904 if(has_equi_rho_and_p) then
905 tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint_with_equi
906 if(mhd_equi_thermal) then
907 tc_fl%subtract_equi = .true.
908 tc_fl%get_temperature_equi => mhd_get_temperature_equi
909 tc_fl%get_rho_equi => mhd_get_rho_equi
910 else
911 tc_fl%subtract_equi = .false.
912 end if
913 else
914 tc_fl%get_temperature_from_eint => mhd_get_temperature_from_eint
915 end if
916 if(.not.mhd_internal_e) then
917 if(mhd_hydrodynamic_e) then
918 call set_conversion_methods_to_head(mhd_e_to_ei_hde, mhd_ei_to_e_hde)
919 else if(mhd_semirelativistic) then
920 call set_conversion_methods_to_head(mhd_e_to_ei_semirelati, mhd_ei_to_e_semirelati)
921 else
923 end if
924 end if
925 call set_error_handling_to_head(mhd_tc_handle_small_e)
926 tc_fl%get_rho => mhd_get_rho
927 tc_fl%e_ = e_
928 tc_fl%Tcoff_ = tcoff_
929 end if
930
931 ! Initialize radiative cooling module
932 if (mhd_radiative_cooling) then
934 allocate(rc_fl)
935 call radiative_cooling_init(rc_fl,rc_params_read)
936 rc_fl%get_rho => mhd_get_rho
937 rc_fl%get_pthermal => mhd_get_pthermal
938 rc_fl%get_var_Rfactor => mhd_get_rfactor
939 rc_fl%e_ = e_
940 rc_fl%Tcoff_ = tcoff_
941 rc_fl%has_equi = has_equi_rho_and_p
942 if(mhd_equi_thermal) then
943 rc_fl%subtract_equi = .true.
944 rc_fl%get_rho_equi => mhd_get_rho_equi
945 rc_fl%get_pthermal_equi => mhd_get_pe_equi
946 rc_fl%get_temperature_equi => mhd_get_temperature_equi
947 else
948 rc_fl%subtract_equi = .false.
949 end if
950 end if
951
952{^ifthreed
953 ! for thermal emission images
954 allocate(te_fl_mhd)
955 te_fl_mhd%get_rho=> mhd_get_rho
956 te_fl_mhd%get_pthermal=> mhd_get_pthermal
957 te_fl_mhd%get_var_Rfactor => mhd_get_rfactor
958 phys_te_images => mhd_te_images
959}
960
961 ! consistency check for hyperresistivity implementation
962 if (mhd_eta_hyper>0.0d0) then
963 if(mype==0) then
964 write(*,*) '*****Using hyperresistivity: with mhd_eta_hyper :', mhd_eta_hyper
965 endif
966 if(b0field) then
967 ! hyperresistivity not ok yet with splitting
968 call mpistop("Must have B0field=F when using hyperresistivity")
969 end if
970 endif
971 if (mhd_eta_hyper<0.0d0) then
972 call mpistop("Must have mhd_eta_hyper positive when using hyperresistivity")
973 endif
974
975 ! Initialize viscosity module
976 if (mhd_viscosity) then
977 call viscosity_init(phys_wider_stencil)
978 end if
979
980 ! Initialize gravity module
981 if(mhd_gravity) then
982 call gravity_init()
983 end if
984
985 ! Initialize rotating frame module
986 if(mhd_rotating_frame) then
987 if(has_equi_rho_and_p) then
988 ! mod_rotating_frame does not handle splitting of density
989 call mpistop("Must have has_equi_rho_and_p=F when mhd_rotating_frame=T")
990 end if
992 endif
993
994
995 ! initialize magnetofriction module
996 if(mhd_magnetofriction) then
998 end if
999
1000 if(mhd_hall) then
1001 if(mhd_semirelativistic) then
1002 ! semirelativistic does not incorporate hall terms
1003 call mpistop("Must have mhd_hall=F when mhd_semirelativistic=T")
1004 end if
1005 if(coordinate>1)then
1006 ! normal unsplit case or split cases do not have geometric sources for Hall included
1007 call mpistop("Must have Cartesian coordinates for Hall")
1008 endif
1009 ! For Hall, we need one more reconstructed layer since currents are computed
1010 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1011 phys_wider_stencil = 1
1012 end if
1013
1014 if(mhd_ambipolar) then
1015 if(mhd_ambipolar_sts) then
1016 call sts_init()
1018 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mag(1),&
1019 ndir,mag(1),ndir,.true.)
1020 else
1021 ! any total energy or no energy at all case is handled here
1022 call add_sts_method(get_ambipolar_dt,sts_set_source_ambipolar,mom(ndir)+1,&
1023 mag(ndir)-mom(ndir),mag(1),ndir,.true.)
1024 end if
1025 else
1026 mhd_ambipolar_exp=.true.
1027 ! For flux ambipolar term, we need one more reconstructed layer since currents are computed
1028 ! in mhd_get_flux: assuming one additional ghost layer added in nghostcells.
1029 phys_wider_stencil = 1
1030 end if
1031 end if
1032
1033 ! initialize ionization degree table
1035
1036 ! Initialize CAK radiation force module
1037 if (mhd_cak_force) then
1039 call mpistop("CAK implementation not available in internal or semirelativistic variants")
1040 endif
1041 if(has_equi_rho_and_p) then
1042 call mpistop("CAK force implementation not available for split off pressure and density")
1043 endif
1044 call cak_init(mhd_gamma)
1045 endif
1046
1047 end subroutine mhd_phys_init
1048
1049{^ifthreed
1050 subroutine mhd_te_images
1053
1054 select case(convert_type)
1055 case('EIvtiCCmpi','EIvtuCCmpi')
1057 case('ESvtiCCmpi','ESvtuCCmpi')
1059 case('SIvtiCCmpi','SIvtuCCmpi')
1061 case('WIvtiCCmpi','WIvtuCCmpi')
1063 case default
1064 call mpistop("Error in synthesize emission: Unknown convert_type")
1065 end select
1066 end subroutine mhd_te_images
1067}
1068
1069!!start th cond
1070 ! wrappers for STS functions in thermal_conductivity module
1071 ! which take as argument the tc_fluid (defined in the physics module)
1072 subroutine mhd_sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1076 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1077 double precision, intent(in) :: x(ixi^s,1:ndim)
1078 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1079 double precision, intent(in) :: my_dt
1080 logical, intent(in) :: fix_conserve_at_step
1081 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1082 end subroutine mhd_sts_set_source_tc_mhd
1083
1084 subroutine mhd_sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
1088 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1089 double precision, intent(in) :: x(ixi^s,1:ndim)
1090 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
1091 double precision, intent(in) :: my_dt
1092 logical, intent(in) :: fix_conserve_at_step
1093 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
1094 end subroutine mhd_sts_set_source_tc_hd
1095
1096 function mhd_get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1097 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1098 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1099 !and T=p/rho
1102
1103 integer, intent(in) :: ixi^l, ixo^l
1104 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1105 double precision, intent(in) :: w(ixi^s,1:nw)
1106 double precision :: dtnew
1107
1108 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1109 end function mhd_get_tc_dt_mhd
1110
1111 function mhd_get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
1112 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1113 !where tc_k_para_i=tc_k_para*B_i**2/B**2
1114 !and T=p/rho
1117
1118 integer, intent(in) :: ixi^l, ixo^l
1119 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1120 double precision, intent(in) :: w(ixi^s,1:nw)
1121 double precision :: dtnew
1122
1123 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
1124 end function mhd_get_tc_dt_hd
1125
1126 subroutine mhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
1128
1129 integer, intent(in) :: ixi^l,ixo^l
1130 double precision, intent(inout) :: w(ixi^s,1:nw)
1131 double precision, intent(in) :: x(ixi^s,1:ndim)
1132 integer, intent(in) :: step
1133 character(len=140) :: error_msg
1134
1135 write(error_msg,"(a,i3)") "Thermal conduction step ", step
1136 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
1137 end subroutine mhd_tc_handle_small_e
1138
1139 ! fill in tc_fluid fields from namelist
1140 subroutine tc_params_read_mhd(fl)
1142 type(tc_fluid), intent(inout) :: fl
1143
1144 double precision :: tc_k_para=0d0
1145 double precision :: tc_k_perp=0d0
1146 integer :: n
1147 ! list parameters
1148 logical :: tc_perpendicular=.false.
1149 logical :: tc_saturate=.false.
1150 character(len=std_len) :: tc_slope_limiter="MC"
1151
1152 namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp
1153
1154 do n = 1, size(par_files)
1155 open(unitpar, file=trim(par_files(n)), status="old")
1156 read(unitpar, tc_list, end=111)
1157111 close(unitpar)
1158 end do
1159
1160 fl%tc_perpendicular = tc_perpendicular
1161 fl%tc_saturate = tc_saturate
1162 fl%tc_k_para = tc_k_para
1163 fl%tc_k_perp = tc_k_perp
1164 select case(tc_slope_limiter)
1165 case ('no','none')
1166 fl%tc_slope_limiter = 0
1167 case ('MC')
1168 ! monotonized central limiter Woodward and Collela limiter (eq.3.51h)
1169 fl%tc_slope_limiter = 1
1170 case('minmod')
1171 ! minmod limiter
1172 fl%tc_slope_limiter = 2
1173 case ('superbee')
1174 ! Roes superbee limiter (eq.3.51i)
1175 fl%tc_slope_limiter = 3
1176 case ('koren')
1177 ! Barry Koren Right variant
1178 fl%tc_slope_limiter = 4
1179 case ('vanleer')
1180 ! van Leer limiter
1181 fl%tc_slope_limiter = 5
1182 case default
1183 call mpistop("Unknown tc_slope_limiter, choose MC, minmod, superbee, koren, vanleer")
1184 end select
1185 end subroutine tc_params_read_mhd
1186!!end th cond
1187
1188!!rad cool
1189 subroutine rc_params_read(fl)
1191 use mod_constants, only: bigdouble
1192 type(rc_fluid), intent(inout) :: fl
1193
1194 !> Lower limit of temperature
1195 double precision :: tlow=bigdouble
1196 double precision :: rad_cut_hgt=0.5d0
1197 double precision :: rad_cut_dey=0.15d0
1198 integer :: n
1199 ! list parameters
1200 integer :: ncool = 4000
1201 !> Fixed temperature not lower than tlow
1202 logical :: tfix=.false.
1203 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1204 logical :: rc_split=.false.
1205 logical :: rad_cut=.false.
1206 !> Name of cooling curve
1207 character(len=std_len) :: coolcurve='JCcorona'
1208
1209 namelist /rc_list/ coolcurve, ncool, tlow, tfix, rc_split,rad_cut,rad_cut_hgt,rad_cut_dey
1210
1211 do n = 1, size(par_files)
1212 open(unitpar, file=trim(par_files(n)), status="old")
1213 read(unitpar, rc_list, end=111)
1214111 close(unitpar)
1215 end do
1216
1217 fl%ncool=ncool
1218 fl%coolcurve=coolcurve
1219 fl%tlow=tlow
1220 fl%Tfix=tfix
1221 fl%rc_split=rc_split
1222 fl%rad_cut=rad_cut
1223 fl%rad_cut_hgt=rad_cut_hgt
1224 fl%rad_cut_dey=rad_cut_dey
1225 end subroutine rc_params_read
1226!! end rad cool
1227
1228 !> sets the equilibrium variables
1229 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1231 use mod_usr_methods
1232 integer, intent(in) :: igrid, ixi^l, ixo^l
1233 double precision, intent(in) :: x(ixi^s,1:ndim)
1234
1235 double precision :: delx(ixi^s,1:ndim)
1236 double precision :: xc(ixi^s,1:ndim),xshift^d
1237 integer :: idims, ixc^l, hxo^l, ix, idims2
1238
1239 if(slab_uniform)then
1240 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1241 else
1242 ! for all non-cartesian and stretched cartesian coordinates
1243 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1244 endif
1245
1246 do idims=1,ndim
1247 hxo^l=ixo^l-kr(idims,^d);
1248 if(stagger_grid) then
1249 ! ct needs all transverse cells
1250 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1251 else
1252 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1253 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1254 end if
1255 ! always xshift=0 or 1/2
1256 xshift^d=half*(one-kr(^d,idims));
1257 do idims2=1,ndim
1258 select case(idims2)
1259 {case(^d)
1260 do ix = ixc^lim^d
1261 ! xshift=half: this is the cell center coordinate
1262 ! xshift=0: this is the cell edge i+1/2 coordinate
1263 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1264 end do\}
1265 end select
1266 end do
1267 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1268 end do
1269
1270 end subroutine set_equi_vars_grid_faces
1271
1272 !> sets the equilibrium variables
1273 subroutine set_equi_vars_grid(igrid)
1275 use mod_usr_methods
1276
1277 integer, intent(in) :: igrid
1278
1279 !values at the center
1280 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1281
1282 !values at the interfaces
1283 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1284
1285 end subroutine set_equi_vars_grid
1286
1287 ! w, wnew conserved, add splitted variables back to wnew
1288 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1290 integer, intent(in) :: ixi^l,ixo^l, nwc
1291 double precision, intent(in) :: w(ixi^s, 1:nw)
1292 double precision, intent(in) :: x(ixi^s,1:ndim)
1293 double precision :: wnew(ixo^s, 1:nwc)
1294
1295 if(has_equi_rho_and_p) then
1296 wnew(ixo^s,rho_)=w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0)
1297 else
1298 wnew(ixo^s,rho_)=w(ixo^s,rho_)
1299 endif
1300 wnew(ixo^s,mom(:))=w(ixo^s,mom(:))
1301
1302 if (b0field) then
1303 ! add background magnetic field B0 to B
1304 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
1305 else
1306 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))
1307 end if
1308
1309 if(mhd_energy) then
1310 wnew(ixo^s,e_)=w(ixo^s,e_)
1311 if(has_equi_rho_and_p) then
1312 wnew(ixo^s,e_)=wnew(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
1313 end if
1314 if(b0field .and. total_energy) then
1315 wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1316 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1317 end if
1318 end if
1319
1320 end function convert_vars_splitting
1321
1322 subroutine mhd_check_params
1324 use mod_usr_methods
1325 use mod_geometry, only: coordinate
1327 use mod_particles, only: particles_init, particles_eta, particles_etah
1328 use mod_particles, only: npayload,nusrpayload, &
1329 ngridvars,num_particles,physics_type_particles
1330 use mod_fld
1331
1332 double precision :: a,b,xfrac,yfrac
1333
1334 ! Initialize particles module here, so all extra and user vars are sample
1335 if(mhd_particles) then
1336 call particles_init()
1337 if (particles_eta < zero) particles_eta = mhd_eta
1338 if (particles_etah < zero) particles_eta = mhd_etah
1339 end if
1340
1341 ! after user parameter setting
1342 gamma_1=mhd_gamma-1.d0
1343 if (.not. mhd_energy) then
1344 if (mhd_gamma <= 0.0d0) call mpistop ("Error: mhd_gamma <= 0")
1345 if (mhd_adiab < 0.0d0) call mpistop ("Error: mhd_adiab < 0")
1347 else
1348 if (mhd_gamma <= 0.0d0 .or. mhd_gamma == 1.0d0) &
1349 call mpistop ("Error: mhd_gamma <= 0 or mhd_gamma == 1")
1350 inv_gamma_1=1.d0/gamma_1
1351 small_e = small_pressure * inv_gamma_1
1352 small_r_e = small_pressure*inv_gamma_1
1353 end if
1354
1355 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1356 call mpistop("usr_set_equi_vars has to be implemented in the user file")
1357 endif
1358 if(convert .or. autoconvert) then
1359 if(convert_type .eq. 'dat_generic_mpi') then
1360 if(mhd_dump_full_vars) then
1361 if(mype .eq. 0) print*, " add conversion method: split -> full "
1362 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1363 endif
1364 endif
1365 endif
1366
1367 if(mhd_radiation_fld) then
1368 if(.not.use_imex_scheme)then
1369 call mpistop('select IMEX scheme for FLD radiation use')
1370 endif
1371 if(use_multigrid)then
1372 call phys_set_mg_bounds()
1373 else
1374 if(.not.fld_no_mg)call mpistop('multigrid must have BCs for IMEX and FLD radiation use')
1375 endif
1376 if(mype==0)then
1377 write(*,*)'==FLD SETUP======================'
1378 write(*,*)'Using FLD with settings:'
1379 write(*,*)'Using FLD with settings: mhd_radiation_fld=',mhd_radiation_fld
1380 write(*,*)'Using FLD with settings: fld_fluxlimiter=',fld_fluxlimiter
1381 write(*,*)'Using FLD with settings: fld_interaction_method=',fld_interaction_method
1382 write(*,*)'Using FLD with settings: fld_opacity_law=',fld_opacity_law
1383 write(*,*)'Using FLD with settings: fld_kappa0=',fld_kappa0
1384 write(*,*)'Using FLD with settings: fld_opal_table=',fld_opal_table
1385 write(*,*)'Using FLD with settings: fld_Radforce_split=',fld_radforce_split
1386 write(*,*)'Using FLD with settings: fld_bisect_tol=',fld_bisect_tol
1387 write(*,*)'Using FLD with settings: fld_diff_tol=',fld_diff_tol
1388 write(*,*)'Using FLD with settings: nth_for_diff_mg=',nth_for_diff_mg
1389 write(*,*)' FLD has use_imex_scheme and use_multigrid=',use_imex_scheme,use_multigrid
1390 print *,'const_rad_a =',const_rad_a
1391 print *,'NORMALIZED arad_norm=',arad_norm
1392 print *,'NORMALIZED c_norm=',c_norm
1393 print *,'const_kappae =',const_kappae
1394 if(trim(fld_opacity_law).eq.'const_norm')then
1395 print *,'NORMALIZED fld_kappa0 =',fld_kappa0
1396 print *,'physical value (in cgs or SI) =',fld_kappa0*unit_opacity
1397 endif
1398 if(trim(fld_opacity_law).eq.'const')then
1399 print *,'physical fld_kappa (in cgs or SI) =',fld_kappa0
1400 print *,'NORMALIZED value =',fld_kappa0/unit_opacity
1401 endif
1402 if(fld_gamma/=mhd_gamma)call mpistop("you must set fld_gamma and mhd_gamma equal!")
1403 write(*,*)'===FLD SETUP====================='
1404 endif
1405 endif
1406
1407 if(mype==0)then
1408 write(*,*)'====MHD run with settings===================='
1409 write(*,*)'Using mod_mhd_phys with settings:'
1410 write(*,*)'SI_unit=',si_unit
1411 write(*,*)'Dimensionality :',ndim
1412 write(*,*)'vector components:',ndir
1413 write(*,*)'coordinate set to type,slab:',coordinate,slab
1414 write(*,*)'number of variables nw=',nw
1415 write(*,*)' start index iwstart=',iwstart
1416 write(*,*)'number of vector variables=',nvector
1417 write(*,*)'number of stagger variables nws=',nws
1418 write(*,*)'number of variables with BCs=',nwgc
1419 write(*,*)'number of vars with fluxes=',nwflux
1420 write(*,*)'number of vars with flux + BC=',nwfluxbc
1421 write(*,*)'number of auxiliary variables=',nwaux
1422 write(*,*)'number of extra vars without flux=',nwextra
1423 write(*,*)'number of extra vars for wextra=',nw_extra
1424 write(*,*)'number of auxiliary I/O variables=',nwauxio
1425 write(*,*)'number of mhd_n_tracer=',mhd_n_tracer
1426 write(*,*)' mhd_energy=',mhd_energy,' with total_energy=',total_energy
1427 write(*,*)' mhd_semirelativistic=',mhd_semirelativistic
1428 write(*,*)' mhd_internal_e=',mhd_internal_e
1429 write(*,*)' mhd_hydrodynamic_e=',mhd_hydrodynamic_e
1430 write(*,*)' mhd_gravity=',mhd_gravity
1431 write(*,*)' mhd_eta=',mhd_eta,' nonzero implies resistivity'
1432 write(*,*)' mhd_viscosity=',mhd_viscosity
1433 write(*,*)' mhd_radiative_cooling=',mhd_radiative_cooling
1434 write(*,*)' mhd_cak_force=',mhd_cak_force
1435 write(*,*)' mhd_radiation_fld=',mhd_radiation_fld
1436 write(*,*)' mhd_thermal_conduction=',mhd_thermal_conduction
1437 write(*,*)' mhd_hyperbolic_thermal_conduction=',mhd_hyperbolic_thermal_conduction
1438 write(*,*)' mhd_trac=',mhd_trac
1439 write(*,*)' mhd_hall=',mhd_hall
1440 write(*,*)' mhd_ambipolar=',mhd_ambipolar
1441 write(*,*)' mhd_eta_hyper=',mhd_eta_hyper
1442 write(*,*)' mhd_rotating_frame=',mhd_rotating_frame
1443 write(*,*)' mhd_particles=',mhd_particles
1444 if(mhd_particles) then
1445 write(*,*) '*****Using particles: with mhd_eta, mhd_etah :', mhd_eta, mhd_etah
1446 write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
1447 write(*,*) '*****Using particles: npayload,ngridvars :', npayload,ngridvars
1448 write(*,*) '*****Using particles: nusrpayload :', nusrpayload
1449 write(*,*) '*****Using particles: num_particles :', num_particles
1450 write(*,*) '*****Using particles: physics_type_particles=',physics_type_particles
1451 end if
1452 write(*,*)'number of ghostcells=',nghostcells
1453 write(*,*)'number due to phys_wider_stencil=',phys_wider_stencil
1454 write(*,*)'==========================================='
1455 print *,'========EOS and UNITS==========='
1456 print *,'SI_unit =',si_unit
1457 print *,'gamma=',mhd_gamma
1458 print *,'eq_state_units=',eq_state_units
1459 print *,'He_abundance =',he_abundance
1460 print *,'RR =',rr
1461 print *,'========EOS and UNITS==========='
1462 print *,'unit_time =',unit_time
1463 print *,'unit_length =',unit_length
1464 print *,'unit_velocity =',unit_velocity
1465 print *,'unit_pressure =',unit_pressure
1466 print *,'unit_numberdensity =',unit_numberdensity
1467 print *,'unit_density =',unit_density
1468 print *,'unit_temperature =',unit_temperature
1469 print *,'unit_mass =',unit_mass
1470 print *,'unit_Erad =',unit_erad
1471 print *,'unit_radflux =',unit_radflux
1472 print *,'unit_magneticfield =',unit_magneticfield
1473 if(si_unit)then
1474 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/miu0_si
1475 else
1476 print *,'CHECK that p_u',unit_pressure,' equals ',unit_magneticfield**2/(4.0d0*dpi)
1477 endif
1478 print *, 'CHECK that p_u ',unit_pressure,' equals ',unit_density*unit_velocity**2
1479 print *, 'CHECK that L_u ',unit_length,' equals ',unit_velocity*unit_time
1480 print *, 'CHECK that M_u',unit_mass,' equals ',unit_density*unit_length**3
1481 print *, 'density to numberdensity has factor ',unit_density/unit_numberdensity
1482 if(si_unit)then
1483 print *, ' compare this to ',mp_si*(1.d0+4.d0*he_abundance)
1484 else
1485 print *, ' compare this to ',mp_cgs*(1.d0+4.d0*he_abundance)
1486 endif
1487 print *, 'pressure to n T has factor ',unit_pressure/(unit_numberdensity*unit_temperature)
1488 if(si_unit)then
1489 print *, ' compare this to ',kb_si*(2.d0+3.d0*he_abundance)
1492 else
1493 print *, ' compare this to ',kb_cgs*(2.d0+3.d0*he_abundance)
1496 endif
1497 if(eq_state_units)then
1498 print *, 'mean molecular weight mu is =',a/b,' = ', (1.d0+4.d0*he_abundance)/(2.d0+3.d0*he_abundance)
1499 xfrac=1.d0/a
1500 yfrac=4.d0*he_abundance/(1.d0+4.d0*he_abundance)
1501 print *, 'mass fraction hydrogen X is =',1/a,' and this equals ', 1.d0/(1.d0+4.d0*he_abundance)
1502 print *, 'mass fraction helium Y is =',yfrac
1503 print *, ' check that 1/mu', b/a,' is equal to 2X+3Y/4=',2.d0*xfrac+3.d0*yfrac/4.d0
1504 print *, ' ratio n_e/n_p=',1.d0+2.0d0*he_abundance
1505 endif
1506 print *,'========UNITS==========='
1507 endif
1508
1509 end subroutine mhd_check_params
1510
1511 subroutine mhd_physical_units()
1513 double precision :: mp,kb,miu0,c_lightspeed,xfrac,sigma_telectron
1514 double precision :: a,b
1515 ! Derive scaling units
1516 if(si_unit) then
1517 mp=mp_si
1518 kb=kb_si
1519 miu0=miu0_si
1520 const_sigmasb=sigma_sb_si
1521 c_lightspeed=c_si
1522 sigma_telectron=sigma_te_si
1523 else
1524 mp=mp_cgs
1525 kb=kb_cgs
1526 miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
1527 const_sigmasb=sigma_sb_cgs
1528 c_lightspeed=const_c
1529 sigma_telectron=sigma_te_cgs
1530 end if
1531 if(eq_state_units) then
1532 a=1d0+4d0*he_abundance
1533 if(mhd_partial_ionization) then
1535 else
1536 b=2d0+3d0*he_abundance
1537 end if
1538 rr=1d0
1539 xfrac=1.d0/a
1540 else
1541 a=1d0
1542 b=1d0
1543 rr=(1d0+h_ion_fr+he_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0))/(1d0+4d0*he_abundance)
1544 end if
1545 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
1546 if(unit_density/=1.d0) then
1548 else if(unit_numberdensity/=1.d0) then
1550 end if
1551 if(unit_temperature/=1.d0) then
1555 if(unit_length/=1.d0) then
1557 else if(unit_time/=1.d0) then
1559 end if
1560 else if(unit_magneticfield/=1.d0) then
1564 if(unit_length/=1.d0) then
1566 else if(unit_time/=1.d0) then
1568 end if
1569 else if(unit_pressure/=1.d0) then
1573 if(unit_length/=1.d0) then
1575 else if(unit_time/=1.d0) then
1577 end if
1578 else if(unit_velocity/=1.d0) then
1582 if(unit_length/=1.d0) then
1584 else if(unit_time/=1.d0) then
1586 end if
1587 else if(unit_time/=1.d0) then
1592 end if
1593 else if(unit_temperature/=1.d0) then
1594 ! units of temperature and velocity are dependent
1595 if(unit_magneticfield/=1.d0) then
1600 if(unit_length/=1.d0) then
1602 else if(unit_time/=1.d0) then
1604 end if
1605 else if(unit_pressure/=1.d0) then
1610 if(unit_length/=1.d0) then
1612 else if(unit_time/=1.d0) then
1614 end if
1615 end if
1616 else if(unit_magneticfield/=1.d0) then
1617 ! units of magnetic field and pressure are dependent
1618 if(unit_velocity/=1.d0) then
1623 if(unit_length/=1.d0) then
1625 else if(unit_time/=1.d0) then
1627 end if
1628 else if(unit_time/=0.d0) then
1634 end if
1635 else if(unit_pressure/=1.d0) then
1636 if(unit_velocity/=1.d0) then
1641 if(unit_length/=1.d0) then
1643 else if(unit_time/=1.d0) then
1645 end if
1646 else if(unit_time/=0.d0) then
1652 end if
1653 end if
1654 ! Additional units needed for the particles
1655 c_norm=c_lightspeed/unit_velocity
1657 if (.not. si_unit) unit_charge = unit_charge*const_c
1659
1660 if(mhd_semirelativistic) then
1661 if(mhd_reduced_c<1.d0) then
1662 ! dimensionless speed
1663 inv_squared_c0=1.d0
1664 inv_squared_c=1.d0/mhd_reduced_c**2
1665 else
1666 inv_squared_c0=(unit_velocity/c_lightspeed)**2
1667 inv_squared_c=(unit_velocity/mhd_reduced_c)**2
1668 end if
1669 end if
1670
1671 !> Units for radiative flux and opacity as used in FLD
1672 ! this is the radiation constant in either cgs or SI units
1673 const_rad_a=4.d0*const_sigmasb/c_lightspeed
1674 ! this is the dimensionless conversion factor for Erad to Trad
1676 ! This is the Thomson scattering opacity in the correct units
1677 ! note that the hydrogen mass fraction X=1/a in eq_state_units
1678 if(eq_state_units) then
1679 const_kappae=sigma_telectron*(1.d0+xfrac)/(2.0d0*mp)
1680 else
1681 const_kappae=0.34d0 ! specific value in cm^2/g for He=0.1 in cgs
1682 endif
1683 ! these are the units
1687
1688 end subroutine mhd_physical_units
1689
1690 subroutine mhd_check_w_semirelati(primitive,ixI^L,ixO^L,w,flag)
1692
1693 logical, intent(in) :: primitive
1694 logical, intent(inout) :: flag(ixi^s,1:nw)
1695 integer, intent(in) :: ixi^l, ixo^l
1696 double precision, intent(in) :: w(ixi^s,nw)
1697
1698 double precision :: tmp,b(1:ndir),v(1:ndir),factor
1699 integer :: ix^d
1700
1701 flag=.false.
1702 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
1703
1704 if(mhd_energy) then
1705 if(primitive) then
1706 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
1707 else
1708 if(mhd_internal_e) then
1709 {do ix^db=ixomin^db,ixomax^db \}
1710 if(w(ix^d,e_) < small_e) flag(ix^d,e_) = .true.
1711 {end do\}
1712 else
1713 {do ix^db=ixomin^db,ixomax^db \}
1714 ! Convert momentum to velocity
1715 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
1716 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
1717 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
1718 ! E=Bxv
1719 {^ifthreec
1720 b(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
1721 b(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
1722 b(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1723 }
1724 {^iftwoc
1725 b(1)=zero
1726 ! switch 3 with 2 to allow ^C from 1 to 2
1727 b(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
1728 }
1729 {^ifonec
1730 b(1)=zero
1731 }
1732 ! Calculate internal e = e-eK-eB-eE
1733 tmp=w(ix^d,e_)-half*((^c&v(^c)**2+)*w(ix^d,rho_)&
1734 +(^c&w(ix^d,b^c_)**2+)+(^c&b(^c)**2+)*inv_squared_c)
1735 if(tmp<small_e) flag(ix^d,e_)=.true.
1736 {end do\}
1737 end if
1738 end if
1739 end if
1740
1741 end subroutine mhd_check_w_semirelati
1742
1743 subroutine mhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1745
1746 logical, intent(in) :: primitive
1747 integer, intent(in) :: ixi^l, ixo^l
1748 double precision, intent(in) :: w(ixi^s,nw)
1749 logical, intent(inout) :: flag(ixi^s,1:nw)
1750
1751 integer :: ix^d
1752
1753 flag=.false.
1754 {do ix^db=ixomin^db,ixomax^db\}
1755 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1756 if(primitive) then
1757 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1758 else
1759 if(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+&
1760 (^c&w(ix^d,b^c_)**2+))<small_e) flag(ix^d,e_) = .true.
1761 end if
1762 if(mhd_radiation_fld)then
1763 if(w(ix^d,r_e)<small_r_e) flag(ix^d,r_e) = .true.
1764 endif
1765 {end do\}
1766
1767 end subroutine mhd_check_w_origin
1768
1769 subroutine mhd_check_w_split(primitive,ixI^L,ixO^L,w,flag)
1771
1772 logical, intent(in) :: primitive
1773 integer, intent(in) :: ixi^l, ixo^l
1774 double precision, intent(in) :: w(ixi^s,nw)
1775 logical, intent(inout) :: flag(ixi^s,1:nw)
1776
1777 double precision :: tmp
1778 integer :: ix^d
1779
1780 flag=.false.
1781 {do ix^db=ixomin^db,ixomax^db\}
1782 tmp=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1783 if(tmp<small_density) flag(ix^d,rho_) = .true.
1784 if(primitive) then
1785 if(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)<small_pressure) flag(ix^d,e_) = .true.
1786 else
1787 tmp=w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/tmp+(^c&w(ix^d,b^c_)**2+))
1788 if(tmp+block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1<small_e) flag(ix^d,e_) = .true.
1789 end if
1790 {end do\}
1791
1792 end subroutine mhd_check_w_split
1793
1794 subroutine mhd_check_w_noe(primitive,ixI^L,ixO^L,w,flag)
1796
1797 logical, intent(in) :: primitive
1798 integer, intent(in) :: ixi^l, ixo^l
1799 double precision, intent(in) :: w(ixi^s,nw)
1800 logical, intent(inout) :: flag(ixi^s,1:nw)
1801
1802 integer :: ix^d
1803
1804 flag=.false.
1805 {do ix^db=ixomin^db,ixomax^db\}
1806 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1807 {end do\}
1808
1809 end subroutine mhd_check_w_noe
1810
1811 subroutine mhd_check_w_inte(primitive,ixI^L,ixO^L,w,flag)
1813
1814 logical, intent(in) :: primitive
1815 integer, intent(in) :: ixi^l, ixo^l
1816 double precision, intent(in) :: w(ixi^s,nw)
1817 logical, intent(inout) :: flag(ixi^s,1:nw)
1818
1819 integer :: ix^d
1820
1821 flag=.false.
1822 {do ix^db=ixomin^db,ixomax^db\}
1823 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1824 if(primitive) then
1825 if(w(ix^d,p_) < small_pressure) flag(ix^d,e_) = .true.
1826 else
1827 if(w(ix^d,e_)<small_e) flag(ix^d,e_) = .true.
1828 end if
1829 {end do\}
1830
1831 end subroutine mhd_check_w_inte
1832
1833 subroutine mhd_check_w_hde(primitive,ixI^L,ixO^L,w,flag)
1835
1836 logical, intent(in) :: primitive
1837 integer, intent(in) :: ixi^l, ixo^l
1838 double precision, intent(in) :: w(ixi^s,nw)
1839 logical, intent(inout) :: flag(ixi^s,1:nw)
1840
1841 integer :: ix^d
1842
1843 flag=.false.
1844 {do ix^db=ixomin^db,ixomax^db\}
1845 if(w(ix^d,rho_)<small_density) flag(ix^d,rho_) = .true.
1846 if(primitive) then
1847 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1848 else
1849 if(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)<small_e) flag(ix^d,e_) = .true.
1850 end if
1851 {end do\}
1852
1853 end subroutine mhd_check_w_hde
1854
1855 !> Transform primitive variables into conservative ones
1856 subroutine mhd_to_conserved_origin(ixI^L,ixO^L,w,x)
1858 integer, intent(in) :: ixi^l, ixo^l
1859 double precision, intent(inout) :: w(ixi^s, nw)
1860 double precision, intent(in) :: x(ixi^s, 1:ndim)
1861
1862 integer :: ix^d
1863
1864 {do ix^db=ixomin^db,ixomax^db\}
1865 ! Calculate total energy from pressure, kinetic and magnetic energy
1866 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1867 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
1868 +(^c&w(ix^d,b^c_)**2+))
1869 ! Convert velocity to momentum
1870 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1871 {end do\}
1872
1873 end subroutine mhd_to_conserved_origin
1874
1875 !> Transform primitive variables into conservative ones
1876 subroutine mhd_to_conserved_origin_noe(ixI^L,ixO^L,w,x)
1878 integer, intent(in) :: ixi^l, ixo^l
1879 double precision, intent(inout) :: w(ixi^s, nw)
1880 double precision, intent(in) :: x(ixi^s, 1:ndim)
1881
1882 integer :: ix^d
1883
1884 {do ix^db=ixomin^db,ixomax^db\}
1885 ! Convert velocity to momentum
1886 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1887 {end do\}
1888
1889 end subroutine mhd_to_conserved_origin_noe
1890
1891 !> Transform primitive variables into conservative ones
1892 subroutine mhd_to_conserved_hde(ixI^L,ixO^L,w,x)
1894 integer, intent(in) :: ixi^l, ixo^l
1895 double precision, intent(inout) :: w(ixi^s, nw)
1896 double precision, intent(in) :: x(ixi^s, 1:ndim)
1897
1898 integer :: ix^d
1899
1900 {do ix^db=ixomin^db,ixomax^db\}
1901 ! Calculate total energy from pressure, kinetic and magnetic energy
1902 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1903 +half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)
1904 ! Convert velocity to momentum
1905 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1906 {end do\}
1907
1908 end subroutine mhd_to_conserved_hde
1909
1910 !> Transform primitive variables into conservative ones
1911 subroutine mhd_to_conserved_inte(ixI^L,ixO^L,w,x)
1913 integer, intent(in) :: ixi^l, ixo^l
1914 double precision, intent(inout) :: w(ixi^s, nw)
1915 double precision, intent(in) :: x(ixi^s, 1:ndim)
1916
1917 integer :: ix^d
1918
1919 {do ix^db=ixomin^db,ixomax^db\}
1920 ! Calculate total energy from pressure, kinetic and magnetic energy
1921 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1
1922 ! Convert velocity to momentum
1923 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1924 {end do\}
1925
1926 end subroutine mhd_to_conserved_inte
1927
1928 !> Transform primitive variables into conservative ones
1929 subroutine mhd_to_conserved_split_rho(ixI^L,ixO^L,w,x)
1931 integer, intent(in) :: ixi^l, ixo^l
1932 double precision, intent(inout) :: w(ixi^s, nw)
1933 double precision, intent(in) :: x(ixi^s, 1:ndim)
1934
1935 double precision :: rho
1936 integer :: ix^d
1937
1938 {do ix^db=ixomin^db,ixomax^db\}
1939 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i)
1940 ! Calculate total energy from pressure, kinetic and magnetic energy
1941 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1942 +half*((^c&w(ix^d,m^c_)**2+)*rho&
1943 +(^c&w(ix^d,b^c_)**2+))
1944 ! Convert velocity to momentum
1945 ^c&w(ix^d,m^c_)=rho*w(ix^d,m^c_)\
1946 {end do\}
1947
1948 end subroutine mhd_to_conserved_split_rho
1949
1950 !> Transform primitive variables into conservative ones
1951 subroutine mhd_to_conserved_semirelati(ixI^L,ixO^L,w,x)
1953 integer, intent(in) :: ixi^l, ixo^l
1954 double precision, intent(inout) :: w(ixi^s, nw)
1955 double precision, intent(in) :: x(ixi^s, 1:ndim)
1956
1957 ! electric field and poynting flux S
1958 double precision :: ef(ixo^s,1:ndir), s(ixo^s,1:ndir)
1959 integer :: ix^d
1960
1961 {do ix^db=ixomin^db,ixomax^db\}
1962 {^ifthreec
1963 ef(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
1964 ef(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
1965 ef(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
1966 s(ix^d,1)=ef(ix^d,2)*w(ix^d,b3_)-ef(ix^d,3)*w(ix^d,b2_)
1967 s(ix^d,2)=ef(ix^d,3)*w(ix^d,b1_)-ef(ix^d,1)*w(ix^d,b3_)
1968 s(ix^d,3)=ef(ix^d,1)*w(ix^d,b2_)-ef(ix^d,2)*w(ix^d,b1_)
1969 }
1970 {^iftwoc
1971 ef(ix^d,1)=zero
1972 ! switch 3 with 2 to add 3 when ^C from 1 to 2
1973 ef(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
1974 s(ix^d,1)=-ef(ix^d,2)*w(ix^d,b2_)
1975 s(ix^d,2)=ef(ix^d,2)*w(ix^d,b1_)
1976 }
1977 {^ifonec
1978 ef(ix^d,1)=zero
1979 s(ix^d,1)=zero
1980 }
1981 if(mhd_internal_e) then
1982 ! internal energy
1983 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1
1984 else
1985 ! equation (9)
1986 ! Calculate total energy from internal, kinetic and magnetic energy
1987 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1988 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
1989 +(^c&w(ix^d,b^c_)**2+)&
1990 +(^c&ef(ix^d,^c)**2+)*inv_squared_c)
1991 end if
1992
1993 ! Convert velocity to momentum, equation (9)
1994 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*inv_squared_c\
1995
1996 {end do\}
1997
1998 end subroutine mhd_to_conserved_semirelati
1999
2000 subroutine mhd_to_conserved_semirelati_noe(ixI^L,ixO^L,w,x)
2002 integer, intent(in) :: ixi^l, ixo^l
2003 double precision, intent(inout) :: w(ixi^s, nw)
2004 double precision, intent(in) :: x(ixi^s, 1:ndim)
2005
2006 double precision :: e(ixo^s,1:ndir), s(ixo^s,1:ndir)
2007 integer :: ix^d
2008
2009 {do ix^db=ixomin^db,ixomax^db\}
2010 {^ifthreec
2011 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
2012 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
2013 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2014 s(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
2015 s(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
2016 s(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
2017 }
2018 {^iftwoc
2019 e(ix^d,1)=zero
2020 ! switch 3 with 2 to add 3 when ^C from 1 to 2
2021 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2022 s(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
2023 s(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
2024 }
2025 {^ifonec
2026 s(ix^d,1)=zero
2027 }
2028 ! Convert velocity to momentum, equation (9)
2029 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)+s(ix^d,^c)*inv_squared_c\
2030
2031 {end do\}
2032
2033 end subroutine mhd_to_conserved_semirelati_noe
2034
2035 !> Transform conservative variables into primitive ones
2036 subroutine mhd_to_primitive_origin(ixI^L,ixO^L,w,x)
2038 integer, intent(in) :: ixi^l, ixo^l
2039 double precision, intent(inout) :: w(ixi^s, nw)
2040 double precision, intent(in) :: x(ixi^s, 1:ndim)
2041
2042 double precision :: inv_rho
2043 integer :: ix^d
2044
2045 if (fix_small_values) then
2046 ! fix small values preventing NaN numbers in the following converting
2047 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin')
2048 end if
2049
2050 {do ix^db=ixomin^db,ixomax^db\}
2051 inv_rho = 1.d0/w(ix^d,rho_)
2052 ! Convert momentum to velocity
2053 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2054 ! Calculate pressure = (gamma-1) * (e-ek-eb)
2055 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2056 -half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)&
2057 +(^c&w(ix^d,b^c_)**2+)))
2058 {end do\}
2059
2060 end subroutine mhd_to_primitive_origin
2061
2062 !> Transform conservative variables into primitive ones
2063 subroutine mhd_to_primitive_origin_noe(ixI^L,ixO^L,w,x)
2065 integer, intent(in) :: ixi^l, ixo^l
2066 double precision, intent(inout) :: w(ixi^s, nw)
2067 double precision, intent(in) :: x(ixi^s, 1:ndim)
2068
2069 double precision :: inv_rho
2070 integer :: ix^d
2071
2072 if (fix_small_values) then
2073 ! fix small values preventing NaN numbers in the following converting
2074 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_origin_noe')
2075 end if
2076
2077 {do ix^db=ixomin^db,ixomax^db\}
2078 inv_rho = 1.d0/w(ix^d,rho_)
2079 ! Convert momentum to velocity
2080 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2081 {end do\}
2082
2083 end subroutine mhd_to_primitive_origin_noe
2084
2085 !> Transform conservative variables into primitive ones
2086 subroutine mhd_to_primitive_hde(ixI^L,ixO^L,w,x)
2088 integer, intent(in) :: ixi^l, ixo^l
2089 double precision, intent(inout) :: w(ixi^s, nw)
2090 double precision, intent(in) :: x(ixi^s, 1:ndim)
2091
2092 double precision :: inv_rho
2093 integer :: ix^d
2094
2095 if (fix_small_values) then
2096 ! fix small values preventing NaN numbers in the following converting
2097 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_hde')
2098 end if
2099
2100 {do ix^db=ixomin^db,ixomax^db\}
2101 inv_rho = 1d0/w(ix^d,rho_)
2102 ! Convert momentum to velocity
2103 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2104 ! Calculate pressure = (gamma-1) * (e-ek)
2105 w(ix^d,p_)=gamma_1*(w(ix^d,e_)-half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+))
2106 {end do\}
2107
2108 end subroutine mhd_to_primitive_hde
2109
2110 !> Transform conservative variables into primitive ones
2111 subroutine mhd_to_primitive_inte(ixI^L,ixO^L,w,x)
2113 integer, intent(in) :: ixi^l, ixo^l
2114 double precision, intent(inout) :: w(ixi^s, nw)
2115 double precision, intent(in) :: x(ixi^s, 1:ndim)
2116
2117 double precision :: inv_rho
2118 integer :: ix^d
2119
2120 if (fix_small_values) then
2121 ! fix small values preventing NaN numbers in the following converting
2122 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_inte')
2123 end if
2124
2125 {do ix^db=ixomin^db,ixomax^db\}
2126 ! Calculate pressure = (gamma-1) * e_internal
2127 w(ix^d,p_)=w(ix^d,e_)*gamma_1
2128 ! Convert momentum to velocity
2129 inv_rho = 1.d0/w(ix^d,rho_)
2130 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2131 {end do\}
2132
2133 end subroutine mhd_to_primitive_inte
2134
2135 !> Transform conservative variables into primitive ones
2136 subroutine mhd_to_primitive_split_rho(ixI^L,ixO^L,w,x)
2138 integer, intent(in) :: ixi^l, ixo^l
2139 double precision, intent(inout) :: w(ixi^s, nw)
2140 double precision, intent(in) :: x(ixi^s, 1:ndim)
2141
2142 double precision :: inv_rho
2143 integer :: ix^d
2144
2145 if (fix_small_values) then
2146 ! fix small values preventing NaN numbers in the following converting
2147 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_split_rho')
2148 end if
2149
2150 {do ix^db=ixomin^db,ixomax^db\}
2151 inv_rho=1.d0/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2152 ! Convert momentum to velocity
2153 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
2154 ! Calculate pressure = (gamma-1) * (e-ek-eb)
2155 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2156 -half*((w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))*&
2157 (^c&w(ix^d,m^c_)**2+)+(^c&w(ix^d,b^c_)**2+)))
2158 {end do\}
2159
2160 end subroutine mhd_to_primitive_split_rho
2161
2162 !> Transform conservative variables into primitive ones
2163 subroutine mhd_to_primitive_semirelati(ixI^L,ixO^L,w,x)
2165 integer, intent(in) :: ixi^l, ixo^l
2166 double precision, intent(inout) :: w(ixi^s, nw)
2167 double precision, intent(in) :: x(ixi^s, 1:ndim)
2168
2169 double precision :: e(1:ndir), tmp, factor
2170 integer :: ix^d
2171
2172 if (fix_small_values) then
2173 ! fix small values preventing NaN numbers in the following converting
2174 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati')
2175 end if
2176
2177 {do ix^db=ixomin^db,ixomax^db\}
2178 ! Convert momentum to velocity
2179 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2180 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2181 ^c&w(ix^d,m^c_)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2182
2183 if(mhd_internal_e) then
2184 ! internal energy to pressure
2185 w(ix^d,p_)=gamma_1*w(ix^d,e_)
2186 else
2187 ! E=Bxv
2188 {^ifthreec
2189 e(1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
2190 e(2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
2191 e(3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2192 }
2193 {^iftwoc
2194 e(1)=zero
2195 e(2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
2196 }
2197 {^ifonec
2198 e(1)=zero
2199 }
2200 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2201 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2202 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
2203 +(^c&w(ix^d,b^c_)**2+)&
2204 +(^c&e(^c)**2+)*inv_squared_c))
2205 end if
2206 {end do\}
2207
2208 end subroutine mhd_to_primitive_semirelati
2209
2210 !> Transform conservative variables into primitive ones
2211 subroutine mhd_to_primitive_semirelati_noe(ixI^L,ixO^L,w,x)
2213 integer, intent(in) :: ixi^l, ixo^l
2214 double precision, intent(inout) :: w(ixi^s, nw)
2215 double precision, intent(in) :: x(ixi^s, 1:ndim)
2216
2217 double precision :: tmp, factor
2218 integer :: ix^d
2219
2220 if (fix_small_values) then
2221 ! fix small values preventing NaN numbers in the following converting
2222 call mhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'mhd_to_primitive_semirelati_noe')
2223 end if
2224
2225 {do ix^db=ixomin^db,ixomax^db\}
2226 ! Convert momentum to velocity
2227 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2228 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2229 ^c&w(ix^d,m^c_)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2230 {end do\}
2231
2232 end subroutine mhd_to_primitive_semirelati_noe
2233
2234 !> Transform internal energy to total energy
2235 subroutine mhd_ei_to_e(ixI^L,ixO^L,w,x)
2237 integer, intent(in) :: ixi^l, ixo^l
2238 double precision, intent(inout) :: w(ixi^s, nw)
2239 double precision, intent(in) :: x(ixi^s, 1:ndim)
2240
2241 integer :: ix^d
2242
2243 if(has_equi_rho_and_p) then
2244 {do ix^db=ixomin^db,ixomax^db\}
2245 ! Calculate e = ei + ek + eb
2246 w(ix^d,e_)=w(ix^d,e_)&
2247 +half*((^c&w(ix^d,m^c_)**2+)/&
2248 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2249 +(^c&w(ix^d,b^c_)**2+))
2250 {end do\}
2251 else
2252 {do ix^db=ixomin^db,ixomax^db\}
2253 ! Calculate e = ei + ek + eb
2254 w(ix^d,e_)=w(ix^d,e_)&
2255 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2256 +(^c&w(ix^d,b^c_)**2+))
2257 {end do\}
2258 end if
2259
2260 end subroutine mhd_ei_to_e
2261
2262 !> Transform internal energy to hydrodynamic energy
2263 subroutine mhd_ei_to_e_hde(ixI^L,ixO^L,w,x)
2265 integer, intent(in) :: ixi^l, ixo^l
2266 double precision, intent(inout) :: w(ixi^s, nw)
2267 double precision, intent(in) :: x(ixi^s, 1:ndim)
2268
2269 integer :: ix^d
2270
2271 {do ix^db=ixomin^db,ixomax^db\}
2272 ! Calculate e = ei + ek
2273 w(ix^d,e_)=w(ix^d,e_)&
2274 +half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2275 {end do\}
2276
2277 end subroutine mhd_ei_to_e_hde
2278
2279 !> Transform internal energy to total energy and velocity to momentum
2280 subroutine mhd_ei_to_e_semirelati(ixI^L,ixO^L,w,x)
2282 integer, intent(in) :: ixi^l, ixo^l
2283 double precision, intent(inout) :: w(ixi^s, nw)
2284 double precision, intent(in) :: x(ixi^s, 1:ndim)
2285
2286 w(ixo^s,p_)=w(ixo^s,e_)*gamma_1
2287 call mhd_to_conserved_semirelati(ixi^l,ixo^l,w,x)
2288
2289 end subroutine mhd_ei_to_e_semirelati
2290
2291 !> Transform total energy to internal energy
2292 subroutine mhd_e_to_ei(ixI^L,ixO^L,w,x)
2294 integer, intent(in) :: ixi^l, ixo^l
2295 double precision, intent(inout) :: w(ixi^s, nw)
2296 double precision, intent(in) :: x(ixi^s, 1:ndim)
2297
2298 integer :: ix^d
2299
2300 if(has_equi_rho_and_p) then
2301 {do ix^db=ixomin^db,ixomax^db\}
2302 ! Calculate ei = e - ek - eb
2303 w(ix^d,e_)=w(ix^d,e_)&
2304 -half*((^c&w(ix^d,m^c_)**2+)/&
2305 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
2306 +(^c&w(ix^d,b^c_)**2+))
2307 {end do\}
2308 else
2309 {do ix^db=ixomin^db,ixomax^db\}
2310 ! Calculate ei = e - ek - eb
2311 w(ix^d,e_)=w(ix^d,e_)&
2312 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2313 +(^c&w(ix^d,b^c_)**2+))
2314 {end do\}
2315 end if
2316
2317 if(fix_small_values) then
2318 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei')
2319 end if
2320
2321 end subroutine mhd_e_to_ei
2322
2323 !> Transform hydrodynamic energy to internal energy
2324 subroutine mhd_e_to_ei_hde(ixI^L,ixO^L,w,x)
2326 integer, intent(in) :: ixi^l, ixo^l
2327 double precision, intent(inout) :: w(ixi^s, nw)
2328 double precision, intent(in) :: x(ixi^s, 1:ndim)
2329
2330 integer :: ix^d
2331
2332 {do ix^db=ixomin^db,ixomax^db\}
2333 ! Calculate ei = e - ek
2334 w(ix^d,e_)=w(ix^d,e_)&
2335 -half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2336 {end do\}
2337
2338 if(fix_small_values) then
2339 call mhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'mhd_e_to_ei_hde')
2340 end if
2341
2342 end subroutine mhd_e_to_ei_hde
2343
2344 !> Transform total energy to internal energy and momentum to velocity
2345 subroutine mhd_e_to_ei_semirelati(ixI^L,ixO^L,w,x)
2347 integer, intent(in) :: ixi^l, ixo^l
2348 double precision, intent(inout) :: w(ixi^s, nw)
2349 double precision, intent(in) :: x(ixi^s, 1:ndim)
2350
2351 call mhd_to_primitive_semirelati(ixi^l,ixo^l,w,x)
2352 w(ixo^s,e_)=w(ixo^s,p_)*inv_gamma_1
2353
2354 end subroutine mhd_e_to_ei_semirelati
2355
2356 subroutine mhd_handle_small_values_semirelati(primitive, w, x, ixI^L, ixO^L, subname)
2359 logical, intent(in) :: primitive
2360 integer, intent(in) :: ixi^l,ixo^l
2361 double precision, intent(inout) :: w(ixi^s,1:nw)
2362 double precision, intent(in) :: x(ixi^s,1:ndim)
2363 character(len=*), intent(in) :: subname
2364
2365 double precision :: e(ixi^s,1:ndir), pressure(ixi^s), v(ixi^s,1:ndir)
2366 double precision :: tmp, factor
2367 integer :: ix^d
2368 logical :: flag(ixi^s,1:nw)
2369
2370 flag=.false.
2371 where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
2372
2373 if(mhd_energy) then
2374 if(primitive) then
2375 where(w(ixo^s,p_) < small_pressure) flag(ixo^s,e_) = .true.
2376 else
2377 {do ix^db=ixomin^db,ixomax^db\}
2378 ! Convert momentum to velocity
2379 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
2380 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
2381 ^c&v(ix^d,^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
2382 ! E=Bxv
2383 {^ifthreec
2384 e(ix^d,1)=w(ix^d,b2_)*v(ix^d,3)-w(ix^d,b3_)*v(ix^d,2)
2385 e(ix^d,2)=w(ix^d,b3_)*v(ix^d,1)-w(ix^d,b1_)*v(ix^d,3)
2386 e(ix^d,3)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2387 }
2388 {^iftwoc
2389 e(ix^d,1)=zero
2390 e(ix^d,2)=w(ix^d,b1_)*v(ix^d,2)-w(ix^d,b2_)*v(ix^d,1)
2391 }
2392 {^ifonec
2393 e(ix^d,1)=zero
2394 }
2395 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
2396 pressure(ix^d)=gamma_1*(w(ix^d,e_)&
2397 -half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2398 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c))
2399 if(pressure(ix^d) < small_pressure) flag(ix^d,p_) = .true.
2400 {end do\}
2401 end if
2402 end if
2403
2404 if(any(flag)) then
2405 select case (small_values_method)
2406 case ("replace")
2407 {do ix^db=ixomin^db,ixomax^db\}
2408 if(flag(ix^d,rho_)) then
2409 w(ix^d,rho_) = small_density
2410 ^c&w(ix^d,m^c_)=0.d0\
2411 end if
2412 if(mhd_energy) then
2413 if(primitive) then
2414 if(flag(ix^d,e_)) w(ix^d,p_) = small_pressure
2415 else
2416 if(flag(ix^d,e_)) then
2417 w(ix^d,e_)=small_pressure*inv_gamma_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2418 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2419 end if
2420 end if
2421 end if
2422 {end do\}
2423 case ("average")
2424 ! do averaging of density
2425 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2426 if(mhd_energy) then
2427 if(primitive) then
2428 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2429 else
2430 w(ixo^s,e_)=pressure(ixo^s)
2431 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2432 {do ix^db=ixomin^db,ixomax^db\}
2433 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1+half*((^c&v(ix^d,^c)**2+)*w(ix^d,rho_)&
2434 +(^c&w(ix^d,b^c_)**2+)+(^c&e(ix^d,^c)**2+)*inv_squared_c)
2435 {end do\}
2436 end if
2437 end if
2438 case default
2439 if(.not.primitive) then
2440 ! change to primitive variables
2441 w(ixo^s,mom(1:ndir))=v(ixo^s,1:ndir)
2442 w(ixo^s,e_)=pressure(ixo^s)
2443 end if
2444 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2445 end select
2446 end if
2447
2448 end subroutine mhd_handle_small_values_semirelati
2449
2450 subroutine mhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
2453 logical, intent(in) :: primitive
2454 integer, intent(in) :: ixi^l,ixo^l
2455 double precision, intent(inout) :: w(ixi^s,1:nw)
2456 double precision, intent(in) :: x(ixi^s,1:ndim)
2457 character(len=*), intent(in) :: subname
2458
2459 integer :: ix^d
2460 logical :: flag(ixi^s,1:nw)
2461
2462 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2463
2464 if(any(flag)) then
2465 select case (small_values_method)
2466 case ("replace")
2467 {do ix^db=ixomin^db,ixomax^db\}
2468 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2469 {
2470 if(small_values_fix_iw(m^c_)) then
2471 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2472 end if
2473 \}
2474 if(primitive) then
2475 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2476 else
2477 if(flag(ix^d,e_)) &
2478 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+))
2479 end if
2480 if(mhd_radiation_fld)then
2481 if(small_values_fix_iw(r_e)) then
2482 if(flag(ix^d,r_e)) w(ix^d,r_e)=small_r_e
2483 endif
2484 endif
2485 {end do\}
2486 case ("average")
2487 ! do averaging of density
2488 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2489 if(primitive)then
2490 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2491 else
2492 ! do averaging of internal energy
2493 {do ix^db=iximin^db,iximax^db\}
2494 w(ix^d,e_)=w(ix^d,e_)&
2495 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2496 {end do\}
2497 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2498 ! convert back
2499 {do ix^db=iximin^db,iximax^db\}
2500 w(ix^d,e_)=w(ix^d,e_)&
2501 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+))
2502 {end do\}
2503 end if
2504 if(mhd_radiation_fld) then
2505 call small_values_average(ixi^l, ixo^l, w, x, flag, r_e)
2506 endif
2507 case default
2508 if(.not.primitive) then
2509 !convert w to primitive
2510 {do ix^db=ixomin^db,ixomax^db\}
2511 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2512 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2513 -half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)))
2514 {end do\}
2515 end if
2516 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2517 end select
2518 end if
2519
2520 end subroutine mhd_handle_small_values_origin
2521
2522 subroutine mhd_handle_small_values_split(primitive, w, x, ixI^L, ixO^L, subname)
2525 logical, intent(in) :: primitive
2526 integer, intent(in) :: ixi^l,ixo^l
2527 double precision, intent(inout) :: w(ixi^s,1:nw)
2528 double precision, intent(in) :: x(ixi^s,1:ndim)
2529 character(len=*), intent(in) :: subname
2530
2531 double precision :: rho
2532 integer :: ix^d
2533 logical :: flag(ixi^s,1:nw)
2534
2535 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2536
2537 if(any(flag)) then
2538 select case (small_values_method)
2539 case ("replace")
2540 {do ix^db=ixomin^db,ixomax^db\}
2541 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2542 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density-block%equi_vars(ix^d,equi_rho0_,0)
2543 {
2544 if(small_values_fix_iw(m^c_)) then
2545 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2546 end if
2547 \}
2548 if(primitive) then
2549 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure-block%equi_vars(ix^d,equi_pe0_,0)
2550 else
2551 if(flag(ix^d,e_)) &
2552 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))&
2553 -block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1
2554 end if
2555 {end do\}
2556 case ("average")
2557 ! do averaging of density
2558 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2559 if(primitive)then
2560 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2561 else
2562 ! do averaging of internal energy
2563 {do ix^db=iximin^db,iximax^db\}
2564 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2565 w(ix^d,e_)=w(ix^d,e_)&
2566 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2567 {end do\}
2568 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2569 ! convert back
2570 {do ix^db=iximin^db,iximax^db\}
2571 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2572 w(ix^d,e_)=w(ix^d,e_)&
2573 +half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
2574 {end do\}
2575 end if
2576 case default
2577 if(.not.primitive) then
2578 !convert w to primitive
2579 {do ix^db=ixomin^db,ixomax^db\}
2580 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
2581 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/rho\
2582 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
2583 -half*((^c&w(ix^d,m^c_)**2+)*rho+(^c&w(ix^d,b^c_)**2+)))
2584 {end do\}
2585 end if
2586 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2587 end select
2588 end if
2589
2590 end subroutine mhd_handle_small_values_split
2591
2592 subroutine mhd_handle_small_values_inte(primitive, w, x, ixI^L, ixO^L, subname)
2595 logical, intent(in) :: primitive
2596 integer, intent(in) :: ixi^l,ixo^l
2597 double precision, intent(inout) :: w(ixi^s,1:nw)
2598 double precision, intent(in) :: x(ixi^s,1:ndim)
2599 character(len=*), intent(in) :: subname
2600
2601 integer :: ix^d
2602 logical :: flag(ixi^s,1:nw)
2603
2604 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2605
2606 if(any(flag)) then
2607 select case (small_values_method)
2608 case ("replace")
2609 {do ix^db=ixomin^db,ixomax^db\}
2610 if(flag(ix^d,rho_)) then
2611 w(ix^d,rho_)=small_density
2612 ^c&w(ix^d,m^c_)=0.d0\
2613 end if
2614 if(primitive) then
2615 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2616 else
2617 if(flag(ix^d,e_)) w(ix^d,e_)=small_e
2618 end if
2619 {end do\}
2620 case ("average")
2621 ! do averaging of density
2622 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2623 ! do averaging of internal energy
2624 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
2625 case default
2626 if(.not.primitive) then
2627 !convert w to primitive
2628 {do ix^db=ixomin^db,ixomax^db\}
2629 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2630 w(ix^d,p_)=gamma_1*w(ix^d,e_)
2631 {end do\}
2632 end if
2633 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2634 end select
2635 end if
2636
2637 end subroutine mhd_handle_small_values_inte
2638
2639 subroutine mhd_handle_small_values_noe(primitive, w, x, ixI^L, ixO^L, subname)
2642 logical, intent(in) :: primitive
2643 integer, intent(in) :: ixi^l,ixo^l
2644 double precision, intent(inout) :: w(ixi^s,1:nw)
2645 double precision, intent(in) :: x(ixi^s,1:ndim)
2646 character(len=*), intent(in) :: subname
2647
2648 integer :: ix^d
2649 logical :: flag(ixi^s,1:nw)
2650
2651 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2652
2653 if(any(flag)) then
2654 select case (small_values_method)
2655 case ("replace")
2656 {do ix^db=ixomin^db,ixomax^db\}
2657 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
2658 {
2659 if(small_values_fix_iw(m^c_)) then
2660 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
2661 end if
2662 \}
2663 {end do\}
2664 case ("average")
2665 ! do averaging of density
2666 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2667 case default
2668 if(.not.primitive) then
2669 !convert w to primitive
2670 {do ix^db=ixomin^db,ixomax^db\}
2671 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2672 {end do\}
2673 end if
2674 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2675 end select
2676 end if
2677
2678 end subroutine mhd_handle_small_values_noe
2679
2680 subroutine mhd_handle_small_values_hde(primitive, w, x, ixI^L, ixO^L, subname)
2683 logical, intent(in) :: primitive
2684 integer, intent(in) :: ixi^l,ixo^l
2685 double precision, intent(inout) :: w(ixi^s,1:nw)
2686 double precision, intent(in) :: x(ixi^s,1:ndim)
2687 character(len=*), intent(in) :: subname
2688
2689 integer :: ix^d
2690 logical :: flag(ixi^s,1:nw)
2691
2692 call phys_check_w(primitive, ixi^l, ixo^l, w, flag)
2693
2694 if(any(flag)) then
2695 select case (small_values_method)
2696 case ("replace")
2697 {do ix^db=ixomin^db,ixomax^db\}
2698 if(flag(ix^d,rho_)) then
2699 w(ix^d,rho_)=small_density
2700 ^c&w(ix^d,m^c_)=0.d0\
2701 end if
2702 if(primitive) then
2703 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
2704 else
2705 if(flag(ix^d,e_)) w(ix^d,e_)=small_e+half*(^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)
2706 end if
2707 {end do\}
2708 case ("average")
2709 ! do averaging of density
2710 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
2711 ! do averaging of energy
2712 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
2713 case default
2714 if(.not.primitive) then
2715 !convert w to primitive
2716 {do ix^db=ixomin^db,ixomax^db\}
2717 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/w(ix^d,rho_)\
2718 w(ix^d,p_)=gamma_1*(w(ix^d,e_)-half*(^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_))
2719 {end do\}
2720 end if
2721 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2722 end select
2723 end if
2724
2725 end subroutine mhd_handle_small_values_hde
2726
2727 !> Calculate v vector
2728 subroutine mhd_get_v(w,x,ixI^L,ixO^L,v)
2730
2731 integer, intent(in) :: ixi^l, ixo^l
2732 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
2733 double precision, intent(out) :: v(ixi^s,ndir)
2734
2735 double precision :: rho(ixi^s)
2736 integer :: idir
2737
2738 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
2739
2740 rho(ixo^s)=1.d0/rho(ixo^s)
2741 ! Convert momentum to velocity
2742 do idir = 1, ndir
2743 v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
2744 end do
2745
2746 end subroutine mhd_get_v
2747
2748 !> Calculate csound**2 within ixO^L
2749 subroutine mhd_get_csound2(w,x,ixI^L,ixO^L,cs2)
2751
2752 integer, intent(in) :: ixi^l, ixo^l
2753 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2754 double precision, intent(inout) :: cs2(ixi^s)
2755
2756 double precision :: rho, inv_rho, ploc
2757 integer :: ix^d
2758
2759 {do ix^db=ixomin^db,ixomax^db \}
2760 if(has_equi_rho_and_p) then
2761 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))
2762 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0))
2763 else
2764 rho=w(ix^d,rho_)
2765 ploc=w(ix^d,p_)
2766 end if
2767 inv_rho=1.d0/rho
2768 ! sound speed**2
2769 cs2(ix^d)=mhd_gamma*ploc*inv_rho
2770 {end do\}
2771 end subroutine mhd_get_csound2
2772
2773 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2774 subroutine mhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
2776
2777 integer, intent(in) :: ixi^l, ixo^l, idim
2778 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2779 double precision, intent(inout) :: cmax(ixi^s)
2780
2781 double precision :: rho, inv_rho, ploc, cfast2, avmincs2, b2, kmax
2782 integer :: ix^d
2783
2784 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2785
2786 if(b0field) then
2787 {do ix^db=ixomin^db,ixomax^db \}
2788 if(has_equi_rho_and_p) then
2789 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2790 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2791 else
2792 rho=w(ix^d,rho_)
2793 ploc=w(ix^d,p_)
2794 end if
2795 inv_rho=1.d0/rho
2796 ! sound speed**2
2797 cmax(ix^d)=mhd_gamma*ploc*inv_rho
2798 ! store |B|^2
2799 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
2800 cfast2=b2*inv_rho+cmax(ix^d)
2801 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
2802 if(avmincs2<zero) avmincs2=zero
2803 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2804 if(mhd_hall) then
2805 ! take the Hall velocity into account: most simple estimate, high k limit:
2806 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2807 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2808 end if
2809 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2810 {end do\}
2811 else
2812 {do ix^db=ixomin^db,ixomax^db \}
2813 if(has_equi_rho_and_p) then
2814 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2815 ploc=(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))
2816 else
2817 rho=w(ix^d,rho_)
2818 ploc=w(ix^d,p_)
2819 end if
2820 inv_rho=1.d0/rho
2821 ! sound speed**2
2822 cmax(ix^d)=mhd_gamma*ploc*inv_rho
2823 ! store |B|^2
2824 b2=(^c&w(ix^d,b^c_)**2+)
2825 cfast2=b2*inv_rho+cmax(ix^d)
2826 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2827 if(avmincs2<zero) avmincs2=zero
2828 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2829 if(mhd_hall) then
2830 ! take the Hall velocity into account: most simple estimate, high k limit:
2831 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2832 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2833 end if
2834 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2835 {end do\}
2836 end if
2837
2838 end subroutine mhd_get_cmax_origin
2839
2840 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
2841 subroutine mhd_get_cmax_origin_noe(w,x,ixI^L,ixO^L,idim,cmax)
2844
2845 integer, intent(in) :: ixi^l, ixo^l, idim
2846 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2847 double precision, intent(inout) :: cmax(ixi^s)
2848
2849 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
2850 double precision :: adiabs(ixi^s), gammas(ixi^s)
2851 integer :: ix^d
2852
2853 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2854
2855 if(associated(usr_set_adiab)) then
2856 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
2857 else
2858 adiabs=mhd_adiab
2859 end if
2860 if(associated(usr_set_gamma)) then
2861 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
2862 else
2863 gammas=mhd_gamma
2864 end if
2865 {do ix^db=ixomin^db,ixomax^db \}
2866 rho=w(ix^d,rho_)
2867 inv_rho=1.d0/rho
2868 ! sound speed**2
2869 cmax(ix^d)=gammas(ix^d)*adiabs(ix^d)*rho**(gammas(ix^d)-1.d0)
2870 ! store |B|^2 in v
2871 b2=(^c&w(ix^d,b^c_)**2+)
2872 cfast2=b2*inv_rho+cmax(ix^d)
2873 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2874 if(avmincs2<zero) avmincs2=zero
2875 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2876 if(mhd_hall) then
2877 ! take the Hall velocity into account: most simple estimate, high k limit:
2878 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2879 cmax(ix^d)=max(cmax(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
2880 end if
2881 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
2882 {end do\}
2883
2884 end subroutine mhd_get_cmax_origin_noe
2885
2886 !> Calculate cmax_idim for semirelativistic MHD
2887 subroutine mhd_get_cmax_semirelati(w,x,ixI^L,ixO^L,idim,cmax)
2889
2890 integer, intent(in) :: ixi^l, ixo^l, idim
2891 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2892 double precision, intent(inout):: cmax(ixi^s)
2893
2894 double precision :: csound, avmincs2, idim_alfven_speed2
2895 double precision :: inv_rho, alfven_speed2, gamma2
2896 integer :: ix^d
2897
2898 {do ix^db=ixomin^db,ixomax^db \}
2899 inv_rho=1.d0/w(ix^d,rho_)
2900 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
2901 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2902 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
2903 ! squared sound speed
2904 csound=mhd_gamma*w(ix^d,p_)*inv_rho
2905 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
2906 ! Va_hat^2+a_hat^2 equation (57)
2907 ! equation (69)
2908 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2909 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2910 if(avmincs2<zero) avmincs2=zero
2911 ! equation (68) fast magnetosonic wave speed
2912 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2913 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
2914 {end do\}
2915
2916 end subroutine mhd_get_cmax_semirelati
2917
2918 !> Calculate cmax_idim for semirelativistic MHD
2919 subroutine mhd_get_cmax_semirelati_noe(w,x,ixI^L,ixO^L,idim,cmax)
2922
2923 integer, intent(in) :: ixi^l, ixo^l, idim
2924 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2925 double precision, intent(inout):: cmax(ixi^s)
2926
2927 double precision :: adiabs(ixi^s), gammas(ixi^s)
2928 double precision :: csound, avmincs2, idim_alfven_speed2
2929 double precision :: inv_rho, alfven_speed2, gamma2
2930 integer :: ix^d
2931
2932 if(associated(usr_set_adiab)) then
2933 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
2934 else
2935 adiabs=mhd_adiab
2936 end if
2937 if(associated(usr_set_gamma)) then
2938 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
2939 else
2940 gammas=mhd_gamma
2941 end if
2942
2943 {do ix^db=ixomin^db,ixomax^db \}
2944 inv_rho=1.d0/w(ix^d,rho_)
2945 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
2946 gamma2=1.0d0/(1.d0+alfven_speed2*inv_squared_c)
2947 cmax(ix^d)=1.d0-gamma2*w(ix^d,mom(idim))**2*inv_squared_c
2948 csound=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
2949 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
2950 ! Va_hat^2+a_hat^2 equation (57)
2951 ! equation (69)
2952 alfven_speed2=alfven_speed2*cmax(ix^d)+csound*(1.d0+idim_alfven_speed2*inv_squared_c)
2953 avmincs2=(gamma2*alfven_speed2)**2-4.0d0*gamma2*csound*idim_alfven_speed2*cmax(ix^d)
2954 if(avmincs2<zero) avmincs2=zero
2955 ! equation (68) fast magnetosonic wave speed
2956 csound = sqrt(half*(gamma2*alfven_speed2+sqrt(avmincs2)))
2957 cmax(ix^d)=gamma2*abs(w(ix^d,mom(idim)))+csound
2958 {end do\}
2959
2960 end subroutine mhd_get_cmax_semirelati_noe
2961
2962 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
2963 subroutine mhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
2965 use mod_geometry
2966 integer, intent(in) :: ixi^l,ixo^l
2967 double precision, intent(in) :: x(ixi^s,1:ndim)
2968 ! in primitive form
2969 double precision, intent(inout) :: w(ixi^s,1:nw)
2970 double precision, intent(out) :: tco_local,tmax_local
2971
2972 double precision, parameter :: trac_delta=0.25d0
2973 double precision :: te(ixi^s),lts(ixi^s)
2974 double precision, dimension(1:ndim) :: bdir, bunitvec
2975 double precision, dimension(ixI^S,1:ndim) :: gradt
2976 double precision :: ltrc,ltrp,altr
2977 integer :: idims,ix^d,jxo^l,hxo^l,ixa^d,ixb^d
2978 integer :: jxp^l,hxp^l,ixp^l,ixq^l
2979
2980 if(mhd_partial_ionization) then
2981 call mhd_get_temperature_from_te(w,x,ixi^l,ixi^l,te)
2982 else
2983 call mhd_get_rfactor(w,x,ixi^l,ixi^l,te)
2984 te(ixi^s)=w(ixi^s,p_)/(te(ixi^s)*w(ixi^s,rho_))
2985 end if
2986 tco_local=zero
2987 tmax_local=maxval(te(ixo^s))
2988
2989 {^ifoned
2990 select case(mhd_trac_type)
2991 case(0)
2992 !> test case, fixed cutoff temperature
2993 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
2994 case(1)
2995 do ix1=ixomin1,ixomax1
2996 lts(ix1)=0.5d0*abs(te(ix1+1)-te(ix1-1))/te(ix1)
2997 if(lts(ix1)>trac_delta) then
2998 tco_local=max(tco_local,te(ix1))
2999 end if
3000 end do
3001 case(2)
3002 !> iijima et al. 2021, LTRAC method
3003 ltrc=1.5d0
3004 ltrp=4.d0
3005 ixp^l=ixo^l^ladd1;
3006 hxo^l=ixo^l-1;
3007 jxo^l=ixo^l+1;
3008 hxp^l=ixp^l-1;
3009 jxp^l=ixp^l+1;
3010 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
3011 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
3012 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
3013 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
3014 case default
3015 call mpistop("mhd_trac_type not allowed for 1D simulation")
3016 end select
3017 }
3018 {^nooned
3019 select case(mhd_trac_type)
3020 case(0)
3021 !> test case, fixed cutoff temperature
3022 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
3023 case(1,4,6)
3024 ! temperature gradient at cell centers
3025 do idims=1,ndim
3026 call gradient(te,ixi^l,ixo^l,idims,gradt(ixi^s,idims))
3027 end do
3028 if(mhd_trac_type .gt. 1) then
3029 ! B direction at block center
3030 bdir=zero
3031 if(b0field) then
3032 {do ixa^d=0,1\}
3033 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3034 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))+block%B0(ixb^d,1:ndim,0)
3035 {end do\}
3036 else
3037 {do ixa^d=0,1\}
3038 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
3039 bdir(1:ndim)=bdir(1:ndim)+w(ixb^d,iw_mag(1:ndim))
3040 {end do\}
3041 end if
3042 {^iftwod
3043 if(bdir(1)/=0.d0) then
3044 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3045 else
3046 block%special_values(3)=0.d0
3047 end if
3048 if(bdir(2)/=0.d0) then
3049 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3050 else
3051 block%special_values(4)=0.d0
3052 end if
3053 }
3054 {^ifthreed
3055 if(bdir(1)/=0.d0) then
3056 block%special_values(3)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+&
3057 (bdir(3)/bdir(1))**2)
3058 else
3059 block%special_values(3)=0.d0
3060 end if
3061 if(bdir(2)/=0.d0) then
3062 block%special_values(4)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+&
3063 (bdir(3)/bdir(2))**2)
3064 else
3065 block%special_values(4)=0.d0
3066 end if
3067 if(bdir(3)/=0.d0) then
3068 block%special_values(5)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+&
3069 (bdir(2)/bdir(3))**2)
3070 else
3071 block%special_values(5)=0.d0
3072 end if
3073 }
3074 end if
3075 ! b unit vector: magnetic field direction vector
3076 block%special_values(1)=zero
3077 {do ix^db=ixomin^db,ixomax^db\}
3078 if(b0field) then
3079 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3080 else
3081 ^d&bdir(^d)=w({ix^d},iw_mag(^d))\
3082 end if
3083 {^iftwod
3084 if(bdir(1)/=0.d0) then
3085 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3086 else
3087 bunitvec(1)=0.d0
3088 end if
3089 if(bdir(2)/=0.d0) then
3090 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3091 else
3092 bunitvec(2)=0.d0
3093 end if
3094 ! temperature length scale inversed
3095 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2))*&
3096 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3097 }
3098 {^ifthreed
3099 if(bdir(1)/=0.d0) then
3100 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3101 else
3102 bunitvec(1)=0.d0
3103 end if
3104 if(bdir(2)/=0.d0) then
3105 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3106 else
3107 bunitvec(2)=0.d0
3108 end if
3109 if(bdir(3)/=0.d0) then
3110 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3111 else
3112 bunitvec(3)=0.d0
3113 end if
3114 ! temperature length scale inversed
3115 lts(ix^d)=min(block%ds(ix^d,1),block%ds(ix^d,2),block%ds(ix^d,3))*&
3116 abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3117 }
3118 if(lts(ix^d)>trac_delta) then
3119 block%special_values(1)=max(block%special_values(1),te(ix^d))
3120 end if
3121 {end do\}
3122 block%special_values(2)=tmax_local
3123 case(2)
3124 !> iijima et al. 2021, LTRAC method
3125 ltrc=1.5d0
3126 ltrp=4.d0
3127 ixp^l=ixo^l^ladd2;
3128 ! temperature gradient at cell centers
3129 do idims=1,ndim
3130 ixq^l=ixp^l;
3131 hxp^l=ixp^l;
3132 jxp^l=ixp^l;
3133 select case(idims)
3134 {case(^d)
3135 ixqmin^d=ixqmin^d+1
3136 ixqmax^d=ixqmax^d-1
3137 hxpmax^d=ixpmin^d
3138 jxpmin^d=ixpmax^d
3139 \}
3140 end select
3141 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
3142 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
3143 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
3144 end do
3145 ! b unit vector: magnetic field direction vector
3146 if(b0field) then
3147 {do ix^db=ixpmin^db,ixpmax^db\}
3148 ^d&bdir(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
3149 {^iftwod
3150 if(bdir(1)/=0.d0) then
3151 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2)
3152 else
3153 bunitvec(1)=0.d0
3154 end if
3155 if(bdir(2)/=0.d0) then
3156 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2)
3157 else
3158 bunitvec(2)=0.d0
3159 end if
3160 }
3161 {^ifthreed
3162 if(bdir(1)/=0.d0) then
3163 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
3164 else
3165 bunitvec(1)=0.d0
3166 end if
3167 if(bdir(2)/=0.d0) then
3168 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
3169 else
3170 bunitvec(2)=0.d0
3171 end if
3172 if(bdir(3)/=0.d0) then
3173 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
3174 else
3175 bunitvec(3)=0.d0
3176 end if
3177 }
3178 ! temperature length scale inversed
3179 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3180 ! fraction of cells size to temperature length scale
3181 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3182 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3183 {end do\}
3184 else
3185 {do ix^db=ixpmin^db,ixpmax^db\}
3186 {^iftwod
3187 if(w(ix^d,iw_mag(1))/=0.d0) then
3188 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)
3189 else
3190 bunitvec(1)=0.d0
3191 end if
3192 if(w(ix^d,iw_mag(2))/=0.d0) then
3193 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)
3194 else
3195 bunitvec(2)=0.d0
3196 end if
3197 }
3198 {^ifthreed
3199 if(w(ix^d,iw_mag(1))/=0.d0) then
3200 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+&
3201 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
3202 else
3203 bunitvec(1)=0.d0
3204 end if
3205 if(w(ix^d,iw_mag(2))/=0.d0) then
3206 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+&
3207 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
3208 else
3209 bunitvec(2)=0.d0
3210 end if
3211 if(w(ix^d,iw_mag(3))/=0.d0) then
3212 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+&
3213 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
3214 else
3215 bunitvec(3)=0.d0
3216 end if
3217 }
3218 ! temperature length scale inversed
3219 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec(^d)+)/te(ix^d)
3220 ! fraction of cells size to temperature length scale
3221 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
3222 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
3223 {end do\}
3224 end if
3225
3226 ! need one ghost layer for thermal conductivity
3227 ixp^l=ixo^l^ladd1;
3228 {do ix^db=ixpmin^db,ixpmax^db\}
3229 {^iftwod
3230 altr=0.25d0*((lts(ix1-1,ix2)+two*lts(ix^d)+lts(ix1+1,ix2))*bunitvec(1)**2+&
3231 (lts(ix1,ix2-1)+two*lts(ix^d)+lts(ix1,ix2+1))*bunitvec(2)**2)
3232 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3233 }
3234 {^ifthreed
3235 altr=0.25d0*((lts(ix1-1,ix2,ix3)+two*lts(ix^d)+lts(ix1+1,ix2,ix3))*bunitvec(1)**2+&
3236 (lts(ix1,ix2-1,ix3)+two*lts(ix^d)+lts(ix1,ix2+1,ix3))*bunitvec(2)**2+&
3237 (lts(ix1,ix2,ix3-1)+two*lts(ix^d)+lts(ix1,ix2,ix3+1))*bunitvec(3)**2)
3238 block%wextra(ix^d,tcoff_)=te(ix^d)*altr**0.4d0
3239 }
3240 {end do\}
3241 case(3,5)
3242 !> do nothing here
3243 case default
3244 call mpistop("unknown mhd_trac_type")
3245 end select
3246 }
3247 end subroutine mhd_get_tcutoff
3248
3249 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
3250 subroutine mhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
3252
3253 integer, intent(in) :: ixi^l, ixo^l, idim
3254 double precision, intent(in) :: wprim(ixi^s, nw)
3255 double precision, intent(in) :: x(ixi^s,1:ndim)
3256 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
3257
3258 double precision :: csound(ixi^s,ndim)
3259 double precision, allocatable :: tmp(:^d&)
3260 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
3261
3262 hspeed=0.d0
3263 ixa^l=ixo^l^ladd1;
3264 allocate(tmp(ixa^s))
3265 do id=1,ndim
3266 if(has_equi_rho_and_p) then
3267 call mhd_get_csound_prim_split(wprim,x,ixi^l,ixa^l,id,tmp)
3268 else
3269 call mhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
3270 endif
3271 csound(ixa^s,id)=tmp(ixa^s)
3272 end do
3273 ixcmax^d=ixomax^d;
3274 ixcmin^d=ixomin^d+kr(idim,^d)-1;
3275 jxcmax^d=ixcmax^d+kr(idim,^d);
3276 jxcmin^d=ixcmin^d+kr(idim,^d);
3277 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))
3278
3279 do id=1,ndim
3280 if(id==idim) cycle
3281 ixamax^d=ixcmax^d+kr(id,^d);
3282 ixamin^d=ixcmin^d+kr(id,^d);
3283 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)))
3284 ixamax^d=ixcmax^d-kr(id,^d);
3285 ixamin^d=ixcmin^d-kr(id,^d);
3286 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)))
3287 end do
3288
3289 do id=1,ndim
3290 if(id==idim) cycle
3291 ixamax^d=jxcmax^d+kr(id,^d);
3292 ixamin^d=jxcmin^d+kr(id,^d);
3293 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)))
3294 ixamax^d=jxcmax^d-kr(id,^d);
3295 ixamin^d=jxcmin^d-kr(id,^d);
3296 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)))
3297 end do
3298 deallocate(tmp)
3299
3300 end subroutine mhd_get_h_speed
3301
3302 !> Estimating bounds for the minimum and maximum signal velocities without split
3303 subroutine mhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3305
3306 integer, intent(in) :: ixi^l, ixo^l, idim
3307 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3308 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3309 double precision, intent(in) :: x(ixi^s,1:ndim)
3310 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3311 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3312 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3313
3314 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3315 double precision :: umean, dmean, tmp1, tmp2, tmp3
3316 integer :: ix^d
3317
3318 select case (boundspeed)
3319 case (1)
3320 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3321 ! Methods for Fluid Dynamics" by Toro.
3322 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3323 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3324 if(present(cmin)) then
3325 {do ix^db=ixomin^db,ixomax^db\}
3326 tmp1=sqrt(wlp(ix^d,rho_))
3327 tmp2=sqrt(wrp(ix^d,rho_))
3328 tmp3=1.d0/(tmp1+tmp2)
3329 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3330 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3331 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3332 cmin(ix^d,1)=umean-dmean
3333 cmax(ix^d,1)=umean+dmean
3334 {end do\}
3335 if(h_correction) then
3336 {do ix^db=ixomin^db,ixomax^db\}
3337 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3338 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3339 {end do\}
3340 end if
3341 else
3342 {do ix^db=ixomin^db,ixomax^db\}
3343 tmp1=sqrt(wlp(ix^d,rho_))
3344 tmp2=sqrt(wrp(ix^d,rho_))
3345 tmp3=1.d0/(tmp1+tmp2)
3346 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3347 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3348 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3349 cmax(ix^d,1)=abs(umean)+dmean
3350 {end do\}
3351 end if
3352 case (2)
3353 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3354 call mhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
3355 if(present(cmin)) then
3356 {do ix^db=ixomin^db,ixomax^db\}
3357 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3358 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3359 {end do\}
3360 if(h_correction) then
3361 {do ix^db=ixomin^db,ixomax^db\}
3362 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3363 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3364 {end do\}
3365 end if
3366 else
3367 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3368 end if
3369 case (3)
3370 ! Miyoshi 2005 JCP 208, 315 equation (67)
3371 call mhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
3372 call mhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
3373 if(present(cmin)) then
3374 {do ix^db=ixomin^db,ixomax^db\}
3375 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3376 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3377 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3378 {end do\}
3379 if(h_correction) then
3380 {do ix^db=ixomin^db,ixomax^db\}
3381 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3382 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3383 {end do\}
3384 end if
3385 else
3386 {do ix^db=ixomin^db,ixomax^db\}
3387 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3388 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3389 {end do\}
3390 end if
3391 end select
3392
3393 end subroutine mhd_get_cbounds
3394
3395 !> Estimating bounds for the minimum and maximum signal velocities without split
3396 subroutine mhd_get_cbounds_semirelati(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3398
3399 integer, intent(in) :: ixi^l, ixo^l, idim
3400 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3401 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3402 double precision, intent(in) :: x(ixi^s,1:ndim)
3403 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3404 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3405 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3406
3407 double precision, dimension(ixO^S) :: csoundl, csoundr, gamma2l, gamma2r
3408 integer :: ix^d
3409
3410 ! Miyoshi 2005 JCP 208, 315 equation (67)
3411 if(mhd_energy) then
3412 call mhd_get_csound_semirelati(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3413 call mhd_get_csound_semirelati(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3414 else
3415 call mhd_get_csound_semirelati_noe(wlp,x,ixi^l,ixo^l,idim,csoundl,gamma2l)
3416 call mhd_get_csound_semirelati_noe(wrp,x,ixi^l,ixo^l,idim,csoundr,gamma2r)
3417 end if
3418 if(present(cmin)) then
3419 {do ix^db=ixomin^db,ixomax^db\}
3420 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3421 cmin(ix^d,1)=min(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))-csoundl(ix^d)
3422 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3423 {end do\}
3424 else
3425 {do ix^db=ixomin^db,ixomax^db\}
3426 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3427 cmax(ix^d,1)=max(gamma2l(ix^d)*wlp(ix^d,mom(idim)),gamma2r(ix^d)*wrp(ix^d,mom(idim)))+csoundl(ix^d)
3428 {end do\}
3429 end if
3430
3431 end subroutine mhd_get_cbounds_semirelati
3432
3433 !> Estimating bounds for the minimum and maximum signal velocities with rho split
3434 subroutine mhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
3436
3437 integer, intent(in) :: ixi^l, ixo^l, idim
3438 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
3439 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3440 double precision, intent(in) :: x(ixi^s,1:ndim)
3441 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
3442 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
3443 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
3444
3445 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
3446 double precision :: umean, dmean, tmp1, tmp2, tmp3
3447 integer :: ix^d
3448
3449 select case (boundspeed)
3450 case (1)
3451 ! This implements formula (10.52) from "Riemann Solvers and Numerical
3452 ! Methods for Fluid Dynamics" by Toro.
3453 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3454 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3455 if(present(cmin)) then
3456 {do ix^db=ixomin^db,ixomax^db\}
3457 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3458 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3459 tmp3=1.d0/(tmp1+tmp2)
3460 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3461 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3462 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3463 cmin(ix^d,1)=umean-dmean
3464 cmax(ix^d,1)=umean+dmean
3465 {end do\}
3466 if(h_correction) then
3467 {do ix^db=ixomin^db,ixomax^db\}
3468 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3469 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3470 {end do\}
3471 end if
3472 else
3473 {do ix^db=ixomin^db,ixomax^db\}
3474 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3475 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3476 tmp3=1.d0/(tmp1+tmp2)
3477 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
3478 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
3479 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
3480 cmax(ix^d,1)=abs(umean)+dmean
3481 {end do\}
3482 end if
3483 case (2)
3484 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
3485 call mhd_get_csound_prim_split(wmean,x,ixi^l,ixo^l,idim,csoundr)
3486 if(present(cmin)) then
3487 {do ix^db=ixomin^db,ixomax^db\}
3488 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
3489 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
3490 {end do\}
3491 if(h_correction) then
3492 {do ix^db=ixomin^db,ixomax^db\}
3493 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3494 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3495 {end do\}
3496 end if
3497 else
3498 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
3499 end if
3500 case (3)
3501 ! Miyoshi 2005 JCP 208, 315 equation (67)
3502 call mhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
3503 call mhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
3504 if(present(cmin)) then
3505 {do ix^db=ixomin^db,ixomax^db\}
3506 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3507 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
3508 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3509 {end do\}
3510 if(h_correction) then
3511 {do ix^db=ixomin^db,ixomax^db\}
3512 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
3513 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
3514 {end do\}
3515 end if
3516 else
3517 {do ix^db=ixomin^db,ixomax^db\}
3518 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
3519 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
3520 {end do\}
3521 end if
3522 end select
3523
3524 end subroutine mhd_get_cbounds_split_rho
3525
3526 !> prepare velocities for ct methods
3527 subroutine mhd_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3529
3530 integer, intent(in) :: ixi^l, ixo^l, idim
3531 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3532 double precision, intent(in) :: cmax(ixi^s)
3533 double precision, intent(in), optional :: cmin(ixi^s)
3534 type(ct_velocity), intent(inout):: vcts
3535
3536 end subroutine mhd_get_ct_velocity_average
3537
3538 subroutine mhd_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3540
3541 integer, intent(in) :: ixi^l, ixo^l, idim
3542 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3543 double precision, intent(in) :: cmax(ixi^s)
3544 double precision, intent(in), optional :: cmin(ixi^s)
3545 type(ct_velocity), intent(inout):: vcts
3546
3547 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
3548 ! get average normal velocity at cell faces
3549 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
3550
3551 end subroutine mhd_get_ct_velocity_contact
3552
3553 subroutine mhd_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
3555
3556 integer, intent(in) :: ixi^l, ixo^l, idim
3557 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
3558 double precision, intent(in) :: cmax(ixi^s)
3559 double precision, intent(in), optional :: cmin(ixi^s)
3560 type(ct_velocity), intent(inout):: vcts
3561
3562 integer :: idime,idimn
3563
3564 if(.not.allocated(vcts%vbarC)) then
3565 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
3566 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
3567 end if
3568 ! Store magnitude of characteristics
3569 if(present(cmin)) then
3570 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
3571 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3572 else
3573 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
3574 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
3575 end if
3576
3577 idimn=mod(idim,ndir)+1 ! 'Next' direction
3578 idime=mod(idim+1,ndir)+1 ! Electric field direction
3579 ! Store velocities
3580 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
3581 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
3582 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
3583 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3584 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3585
3586 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
3587 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
3588 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
3589 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
3590 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
3591
3592 end subroutine mhd_get_ct_velocity_hll
3593
3594 !> Calculate modified squared sound speed for FLD
3595 !> NOTE: only for diagnostic purposes, unused subroutine
3596 subroutine mhd_get_csrad2(w,x,ixI^L,ixO^L,csound)
3598
3599 integer, intent(in) :: ixi^l, ixo^l
3600 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3601 double precision, intent(out):: csound(ixi^s)
3602
3603 double precision :: wprim(ixi^s, nw)
3604
3605 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
3606 call mhd_to_primitive(ixi^l,ixo^l,wprim,x)
3607 call mhd_get_csrad2_prim(wprim,x,ixi^l,ixo^l,csound)
3608
3609 end subroutine mhd_get_csrad2
3610
3611
3612 !> Calculate modified squared fast wave speed for FLD
3613 !> NOTE: w is primitive on entry here!
3614 !> NOTE: used in FLD module as phys_get_csrad2
3615 subroutine mhd_get_csrad2_prim(w,x,ixI^L,ixO^L,csound)
3617
3618 integer, intent(in) :: ixi^l, ixo^l
3619 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3620 double precision, intent(out):: csound(ixi^s)
3621
3622 double precision :: inv_rho, b2
3623 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
3624 double precision :: prad_max(ixi^s)
3625 integer :: ix^d
3626
3627 call mhd_get_pradiation_from_prim(w, x, ixi^l, ixo^l, prad_tensor)
3628
3629 if(b0field) then
3630 {do ix^db=ixomin^db,ixomax^db \}
3631 inv_rho=1.d0/w(ix^d,rho_)
3632 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3633 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3634 csound(ix^d)=(mhd_gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3635 {end do\}
3636 else
3637 {do ix^db=ixomin^db,ixomax^db \}
3638 inv_rho=1.d0/w(ix^d,rho_)
3639 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
3640 b2=(^c&w(ix^d,b^c_)**2+)
3641 csound(ix^d)=(mhd_gamma*w(ix^d,p_)+b2+prad_max(ix^d))*inv_rho
3642 {end do\}
3643 end if
3644
3645 if(minval(csound(ixo^s))<smalldouble)then
3646 print *,'issue with squared speed and rad pressure'
3647 print *,minval(csound(ixo^s))
3648 print *,minval(prad_max(ixo^s))
3649 call mpistop("negative squared speed in get_csrad2 for dt")
3650 endif
3651
3652 end subroutine mhd_get_csrad2_prim
3653
3654 !> Calculate fast magnetosonic wave speed
3655 subroutine mhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
3658
3659 integer, intent(in) :: ixi^l, ixo^l, idim
3660 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3661 double precision, intent(out):: csound(ixo^s)
3662
3663 double precision :: adiabs(ixi^s), gammas(ixi^s)
3664 double precision :: inv_rho, cfast2, avmincs2, b2, kmax
3665 integer :: ix^d
3666
3667 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3668
3669 if(.not.mhd_energy) then
3670 if(associated(usr_set_adiab)) then
3671 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3672 else
3673 adiabs=mhd_adiab
3674 end if
3675 if(associated(usr_set_gamma)) then
3676 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3677 else
3678 gammas=mhd_gamma
3679 end if
3680 end if
3681
3682 ! store |B|^2 in v
3683 if(b0field) then
3684 {do ix^db=ixomin^db,ixomax^db \}
3685 inv_rho=1.d0/w(ix^d,rho_)
3686 if(mhd_energy) then
3687 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3688 else
3689 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3690 end if
3691 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3692 cfast2=b2*inv_rho+csound(ix^d)
3693 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3694 block%B0(ix^d,idim,b0i))**2*inv_rho
3695 if(avmincs2<zero) avmincs2=zero
3696 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3697 if(mhd_hall) then
3698 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3699 end if
3700 {end do\}
3701 else
3702 {do ix^db=ixomin^db,ixomax^db \}
3703 inv_rho=1.d0/w(ix^d,rho_)
3704 if(mhd_energy) then
3705 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3706 else
3707 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3708 end if
3709 b2=(^c&w(ix^d,b^c_)**2+)
3710 cfast2=b2*inv_rho+csound(ix^d)
3711 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3712 if(avmincs2<zero) avmincs2=zero
3713 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3714 if(mhd_hall) then
3715 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3716 end if
3717 {end do\}
3718 end if
3719
3720 end subroutine mhd_get_csound_prim
3721
3722 !> Calculate fast magnetosonic wave speed when rho and p are split
3723 !> hence has_equi_rho_and_p=T
3724 subroutine mhd_get_csound_prim_split(w,x,ixI^L,ixO^L,idim,csound)
3726
3727 integer, intent(in) :: ixi^l, ixo^l, idim
3728 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3729 double precision, intent(out):: csound(ixo^s)
3730
3731 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
3732 integer :: ix^d
3733
3734 if(mhd_hall) kmax = dpi/min({dxlevel(^d)},bigdouble)*half
3735
3736 ! store |B|^2 in v
3737 if(b0field) then
3738 {do ix^db=ixomin^db,ixomax^db \}
3739 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3740 inv_rho=1.d0/rho
3741 csound(ix^d)=mhd_gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3742 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
3743 cfast2=b2*inv_rho+csound(ix^d)
3744 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
3745 block%B0(ix^d,idim,b0i))**2*inv_rho
3746 if(avmincs2<zero) avmincs2=zero
3747 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3748 if(mhd_hall) then
3749 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3750 end if
3751 {end do\}
3752 else
3753 {do ix^db=ixomin^db,ixomax^db \}
3754 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
3755 inv_rho=1.d0/rho
3756 csound(ix^d)=mhd_gamma*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i))*inv_rho
3757 b2=(^c&w(ix^d,b^c_)**2+)
3758 cfast2=b2*inv_rho+csound(ix^d)
3759 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
3760 if(avmincs2<zero) avmincs2=zero
3761 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
3762 if(mhd_hall) then
3763 csound(ix^d)=max(csound(ix^d),mhd_etah*sqrt(b2)*inv_rho*kmax)
3764 end if
3765 {end do\}
3766 end if
3767
3768 end subroutine mhd_get_csound_prim_split
3769
3770 !> Calculate cmax_idim for semirelativistic MHD
3771 subroutine mhd_get_csound_semirelati(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3773
3774 integer, intent(in) :: ixi^l, ixo^l, idim
3775 ! here w is primitive variables
3776 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3777 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3778
3779 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3780 integer :: ix^d
3781
3782 {do ix^db=ixomin^db,ixomax^db\}
3783 inv_rho = 1.d0/w(ix^d,rho_)
3784 ! squared sound speed
3785 csound(ix^d)=mhd_gamma*w(ix^d,p_)*inv_rho
3786 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3787 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3788 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3789 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3790 ! Va_hat^2+a_hat^2 equation (57)
3791 ! equation (69)
3792 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3793 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3794 if(avmincs2<zero) avmincs2=zero
3795 ! equation (68) fast magnetosonic speed
3796 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3797 {end do\}
3798
3799 end subroutine mhd_get_csound_semirelati
3800
3801 !> Calculate cmax_idim for semirelativistic MHD
3802 subroutine mhd_get_csound_semirelati_noe(w,x,ixI^L,ixO^L,idim,csound,gamma2)
3805
3806 integer, intent(in) :: ixi^l, ixo^l, idim
3807 ! here w is primitive variables
3808 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
3809 double precision, intent(out):: csound(ixo^s), gamma2(ixo^s)
3810
3811 double precision :: adiabs(ixi^s), gammas(ixi^s)
3812 double precision :: avmincs2, inv_rho, alfven_speed2, idim_alfven_speed2
3813 integer :: ix^d
3814
3815 if(associated(usr_set_adiab)) then
3816 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3817 else
3818 adiabs=mhd_adiab
3819 end if
3820 if(associated(usr_set_gamma)) then
3821 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3822 else
3823 gammas=mhd_gamma
3824 end if
3825 {do ix^db=ixomin^db,ixomax^db\}
3826 inv_rho = 1.d0/w(ix^d,rho_)
3827 ! squared sound speed
3828 csound(ix^d)=gammas(ix^d)*adiabs(ix^d)*w(ix^d,rho_)**(gammas(ix^d)-1.d0)
3829 alfven_speed2=(^c&w(ix^d,b^c_)**2+)*inv_rho
3830 gamma2(ix^d) = 1.0d0/(1.d0+alfven_speed2*inv_squared_c)
3831 avmincs2=1.d0-gamma2(ix^d)*w(ix^d,mom(idim))**2*inv_squared_c
3832 idim_alfven_speed2=w(ix^d,mag(idim))**2*inv_rho
3833 ! Va_hat^2+a_hat^2 equation (57)
3834 ! equation (69)
3835 alfven_speed2=alfven_speed2*avmincs2+csound(ix^d)*(1.d0+idim_alfven_speed2*inv_squared_c)
3836 avmincs2=(gamma2(ix^d)*alfven_speed2)**2-4.0d0*gamma2(ix^d)*csound(ix^d)*idim_alfven_speed2*avmincs2
3837 if(avmincs2<zero) avmincs2=zero
3838 ! equation (68) fast magnetosonic speed
3839 csound(ix^d) = sqrt(half*(gamma2(ix^d)*alfven_speed2+sqrt(avmincs2)))
3840 {end do\}
3841
3842 end subroutine mhd_get_csound_semirelati_noe
3843
3844 !> Calculate thermal pressure from polytropic closure
3845 subroutine mhd_get_pthermal_noe(w,x,ixI^L,ixO^L,pth)
3848
3849 integer, intent(in) :: ixi^l, ixo^l
3850 double precision, intent(in) :: w(ixi^s,nw)
3851 double precision, intent(in) :: x(ixi^s,1:ndim)
3852 double precision, intent(out):: pth(ixi^s)
3853
3854 double precision :: adiabs(ixi^s), gammas(ixi^s)
3855 integer :: ix^d
3856
3857 if(associated(usr_set_adiab)) then
3858 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
3859 else
3860 adiabs=mhd_adiab
3861 end if
3862 if(associated(usr_set_gamma)) then
3863 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
3864 else
3865 gammas=mhd_gamma
3866 end if
3867 {do ix^db=ixomin^db,ixomax^db\}
3868 pth(ix^d)=adiabs(ix^d)*w(ix^d,rho_)**gammas(ix^d)
3869 {end do\}
3870
3871 end subroutine mhd_get_pthermal_noe
3872
3873 !> Calculate thermal pressure from internal energy
3874 subroutine mhd_get_pthermal_inte(w,x,ixI^L,ixO^L,pth)
3877
3878 integer, intent(in) :: ixi^l, ixo^l
3879 double precision, intent(in) :: w(ixi^s,nw)
3880 double precision, intent(in) :: x(ixi^s,1:ndim)
3881 double precision, intent(out):: pth(ixi^s)
3882
3883 integer :: iw, ix^d
3884
3885 {do ix^db= ixomin^db,ixomax^db\}
3886 pth(ix^d)=gamma_1*w(ix^d,e_)
3887 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
3888 {end do\}
3889
3890 if(check_small_values.and..not.fix_small_values) then
3891 {do ix^db= ixomin^db,ixomax^db\}
3892 if(pth(ix^d)<small_pressure) then
3893 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3894 " encountered when call mhd_get_pthermal_inte"
3895 write(*,*) "Iteration: ", it, " Time: ", global_time
3896 write(*,*) "Location: ", x(ix^d,:)
3897 write(*,*) "Cell number: ", ix^d
3898 do iw=1,nw
3899 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3900 end do
3901 ! use erroneous arithmetic operation to crash the run
3902 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3903 write(*,*) "Saving status at the previous time step"
3904 crash=.true.
3905 end if
3906 {end do\}
3907 end if
3908
3909 end subroutine mhd_get_pthermal_inte
3910
3911 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L
3912 subroutine mhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
3915
3916 integer, intent(in) :: ixi^l, ixo^l
3917 double precision, intent(in) :: w(ixi^s,nw)
3918 double precision, intent(in) :: x(ixi^s,1:ndim)
3919 double precision, intent(out):: pth(ixi^s)
3920
3921 integer :: iw, ix^d
3922
3923 {do ix^db=ixomin^db,ixomax^db\}
3924 if(has_equi_rho_and_p) then
3925 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
3926 +(^c&w(ix^d,b^c_)**2+))) +block%equi_vars(ix^d,equi_pe0_,0)
3927 else
3928 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
3929 +(^c&w(ix^d,b^c_)**2+)))
3930 end if
3931 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
3932 {end do\}
3933
3934 if(check_small_values.and..not.fix_small_values) then
3935 {do ix^db=ixomin^db,ixomax^db\}
3936 if(pth(ix^d)<small_pressure) then
3937 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3938 " encountered when call mhd_get_pthermal"
3939 write(*,*) "Iteration: ", it, " Time: ", global_time
3940 write(*,*) "Location: ", x(ix^d,:)
3941 write(*,*) "Cell number: ", ix^d
3942 do iw=1,nw
3943 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3944 end do
3945 ! use erroneous arithmetic operation to crash the run
3946 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3947 write(*,*) "Saving status at the previous time step"
3948 crash=.true.
3949 end if
3950 {end do\}
3951 end if
3952
3953 end subroutine mhd_get_pthermal_origin
3954
3955 !> Calculate thermal pressure
3956 subroutine mhd_get_pthermal_semirelati(w,x,ixI^L,ixO^L,pth)
3959
3960 integer, intent(in) :: ixi^l, ixo^l
3961 double precision, intent(in) :: w(ixi^s,nw)
3962 double precision, intent(in) :: x(ixi^s,1:ndim)
3963 double precision, intent(out):: pth(ixi^s)
3964
3965 double precision :: e(1:ndir), v(1:ndir), tmp, factor
3966 integer :: iw, ix^d
3967
3968 {do ix^db=ixomin^db,ixomax^db\}
3969 ! Convert momentum to velocity
3970 tmp=(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)*inv_squared_c
3971 factor=1.0d0/(w(ix^d,rho_)*(w(ix^d,rho_)+(^c&w(ix^d,b^c_)**2+)*inv_squared_c))
3972 ^c&v(^c)=factor*(w(ix^d,m^c_)*w(ix^d,rho_)+w(ix^d,b^c_)*tmp)\
3973
3974 ! E=Bxv
3975 {^ifthreec
3976 e(1)=w(ix^d,b2_)*v(3)-w(ix^d,b3_)*v(2)
3977 e(2)=w(ix^d,b3_)*v(1)-w(ix^d,b1_)*v(3)
3978 e(3)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
3979 }
3980 {^iftwoc
3981 e(1)=zero
3982 e(2)=w(ix^d,b1_)*v(2)-w(ix^d,b2_)*v(1)
3983 }
3984 {^ifonec
3985 e(1)=zero
3986 }
3987 ! Calculate pressure = (gamma-1) * (e-eK-eB-eE)
3988 pth(ix^d)=gamma_1*(w(ix^d,e_)&
3989 -half*((^c&v(^c)**2+)*w(ix^d,rho_)&
3990 +(^c&w(ix^d,b^c_)**2+)+(^c&e(^c)**2+)*inv_squared_c))
3991 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
3992 {end do\}
3993
3994 if(check_small_values.and..not.fix_small_values) then
3995 {do ix^db=ixomin^db,ixomax^db\}
3996 if(pth(ix^d)<small_pressure) then
3997 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3998 " encountered when call mhd_get_pthermal_semirelati"
3999 write(*,*) "Iteration: ", it, " Time: ", global_time
4000 write(*,*) "Location: ", x(ix^d,:)
4001 write(*,*) "Cell number: ", ix^d
4002 do iw=1,nw
4003 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4004 end do
4005 ! use erroneous arithmetic operation to crash the run
4006 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4007 write(*,*) "Saving status at the previous time step"
4008 crash=.true.
4009 end if
4010 {end do\}
4011 end if
4012
4013 end subroutine mhd_get_pthermal_semirelati
4014
4015 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho) within ixO^L
4016 subroutine mhd_get_pthermal_hde(w,x,ixI^L,ixO^L,pth)
4019
4020 integer, intent(in) :: ixi^l, ixo^l
4021 double precision, intent(in) :: w(ixi^s,nw)
4022 double precision, intent(in) :: x(ixi^s,1:ndim)
4023 double precision, intent(out):: pth(ixi^s)
4024
4025 integer :: iw, ix^d
4026
4027 {do ix^db= ixomin^db,ixomax^db\}
4028 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)))
4029 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
4030 {end do\}
4031 if(check_small_values.and..not.fix_small_values) then
4032 {do ix^db= ixomin^db,ixomax^db\}
4033 if(pth(ix^d)<small_pressure) then
4034 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
4035 " encountered when call mhd_get_pthermal_hde"
4036 write(*,*) "Iteration: ", it, " Time: ", global_time
4037 write(*,*) "Location: ", x(ix^d,:)
4038 write(*,*) "Cell number: ", ix^d
4039 do iw=1,nw
4040 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
4041 end do
4042 ! use erroneous arithmetic operation to crash the run
4043 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
4044 write(*,*) "Saving status at the previous time step"
4045 crash=.true.
4046 end if
4047 {end do\}
4048 end if
4049
4050 end subroutine mhd_get_pthermal_hde
4051
4052 !> copy temperature from stored Te variable
4053 subroutine mhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
4055 integer, intent(in) :: ixi^l, ixo^l
4056 double precision, intent(in) :: w(ixi^s, 1:nw)
4057 double precision, intent(in) :: x(ixi^s, 1:ndim)
4058 double precision, intent(out):: res(ixi^s)
4059 res(ixo^s) = w(ixo^s, te_)
4060 end subroutine mhd_get_temperature_from_te
4061
4062 !> Calculate temperature=p/rho when in e_ the internal energy is stored
4063 subroutine mhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
4065 integer, intent(in) :: ixi^l, ixo^l
4066 double precision, intent(in) :: w(ixi^s, 1:nw)
4067 double precision, intent(in) :: x(ixi^s, 1:ndim)
4068 double precision, intent(out):: res(ixi^s)
4069
4070 double precision :: r(ixi^s)
4071
4072 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4073 res(ixo^s) = gamma_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
4074 end subroutine mhd_get_temperature_from_eint
4075
4076 !> Calculate temperature=p/rho when in e_ the pressure p_ (primitive) is stored
4077 subroutine mhd_get_temperature_from_prim(w, x, ixI^L, ixO^L, res)
4079 integer, intent(in) :: ixi^l, ixo^l
4080 double precision, intent(in) :: w(ixi^s, 1:nw)
4081 double precision, intent(in) :: x(ixi^s, 1:ndim)
4082 double precision, intent(out):: res(ixi^s)
4083
4084 double precision :: r(ixi^s)
4085
4086 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4087 res(ixo^s) = w(ixo^s, p_)/(w(ixo^s,rho_)*r(ixo^s))
4088 end subroutine mhd_get_temperature_from_prim
4089
4090 !> Calculate temperature=p/rho from total energy
4091 subroutine mhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
4093 integer, intent(in) :: ixi^l, ixo^l
4094 double precision, intent(in) :: w(ixi^s, 1:nw)
4095 double precision, intent(in) :: x(ixi^s, 1:ndim)
4096 double precision, intent(out):: res(ixi^s)
4097
4098 double precision :: r(ixi^s),rho(ixi^s)
4099
4100 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4101 call mhd_get_pthermal(w,x,ixi^l,ixo^l,res)
4102 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
4103 res(ixo^s)=res(ixo^s)/(r(ixo^s)*rho(ixo^s))
4104
4105 end subroutine mhd_get_temperature_from_etot
4106
4107 subroutine mhd_get_temperature_from_eint_with_equi(w, x, ixI^L, ixO^L, res)
4109 integer, intent(in) :: ixi^l, ixo^l
4110 double precision, intent(in) :: w(ixi^s, 1:nw)
4111 double precision, intent(in) :: x(ixi^s, 1:ndim)
4112 double precision, intent(out):: res(ixi^s)
4113
4114 double precision :: r(ixi^s)
4115
4116 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4117 res(ixo^s) = (gamma_1 * w(ixo^s, e_) + block%equi_vars(ixo^s,equi_pe0_,b0i)) /&
4118 ((w(ixo^s,rho_) +block%equi_vars(ixo^s,equi_rho0_,b0i))*r(ixo^s))
4119
4120 end subroutine mhd_get_temperature_from_eint_with_equi
4121
4122 subroutine mhd_get_temperature_equi(w,x, ixI^L, ixO^L, res)
4124 integer, intent(in) :: ixi^l, ixo^l
4125 double precision, intent(in) :: w(ixi^s, 1:nw)
4126 double precision, intent(in) :: x(ixi^s, 1:ndim)
4127 double precision, intent(out):: res(ixi^s)
4128
4129 double precision :: r(ixi^s)
4130
4131 !!! somewhat inconsistent: R from w itself, while only equilibrium needed !!!
4132 call mhd_get_rfactor(w,x,ixi^l,ixo^l,r)
4133 res(ixo^s)= block%equi_vars(ixo^s,equi_pe0_,b0i)/(block%equi_vars(ixo^s,equi_rho0_,b0i)*r(ixo^s))
4134
4135 end subroutine mhd_get_temperature_equi
4136
4137 subroutine mhd_get_rho_equi(w, x, ixI^L, ixO^L, res)
4139 integer, intent(in) :: ixi^l, ixo^l
4140 double precision, intent(in) :: w(ixi^s, 1:nw)
4141 double precision, intent(in) :: x(ixi^s, 1:ndim)
4142 double precision, intent(out):: res(ixi^s)
4143 res(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i)
4144 end subroutine mhd_get_rho_equi
4145
4146 subroutine mhd_get_pe_equi(w,x, ixI^L, ixO^L, res)
4148 integer, intent(in) :: ixi^l, ixo^l
4149 double precision, intent(in) :: w(ixi^s, 1:nw)
4150 double precision, intent(in) :: x(ixi^s, 1:ndim)
4151 double precision, intent(out):: res(ixi^s)
4152 res(ixo^s) = block%equi_vars(ixo^s,equi_pe0_,b0i)
4153 end subroutine mhd_get_pe_equi
4154
4155 !> Calculate radiation pressure within ixO^L
4156 subroutine mhd_get_pradiation_from_prim(w, x, ixI^L, ixO^L, prad)
4158 use mod_fld
4159 integer, intent(in) :: ixi^l, ixo^l
4160 double precision, intent(in) :: w(ixi^s, 1:nw)
4161 double precision, intent(in) :: x(ixi^s, 1:ndim)
4162 double precision, intent(out):: prad(ixi^s, 1:ndim, 1:ndim)
4163
4164 call fld_get_radpress(w, x, ixi^l, ixo^l, prad)
4165
4166 end subroutine mhd_get_pradiation_from_prim
4167
4168 !> Calculates the sum of the gas pressure and the max Prad tensor element
4169 subroutine mhd_get_pthermal_plus_pradiation(w, x, ixI^L, ixO^L, pth_plus_prad)
4171 integer, intent(in) :: ixi^l, ixo^l
4172 double precision, intent(in) :: w(ixi^s, 1:nw)
4173 double precision, intent(in) :: x(ixi^s, 1:ndim)
4174 double precision, intent(out) :: pth_plus_prad(ixi^s)
4175
4176 double precision :: wprim(ixi^s, 1:nw)
4177 double precision :: prad_tensor(ixi^s, 1:ndim, 1:ndim)
4178 double precision :: prad_max(ixi^s)
4179 integer :: ix^d
4180
4181 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
4182 call mhd_to_primitive(ixi^l,ixo^l,wprim,x)
4183 call mhd_get_pradiation_from_prim(wprim, x, ixi^l, ixo^l, prad_tensor)
4184 {do ix^d = ixomin^d,ixomax^d\}
4185 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
4186 {enddo\}
4187 pth_plus_prad(ixo^s) = wprim(ixo^s,p_) + prad_max(ixo^s)
4189
4190 !> Calculates radiation temperature
4191 subroutine mhd_get_trad(w, x, ixI^L, ixO^L, trad)
4193 use mod_constants
4194
4195 integer, intent(in) :: ixi^l, ixo^l
4196 double precision, intent(in) :: w(ixi^s, 1:nw)
4197 double precision, intent(in) :: x(ixi^s, 1:ndim)
4198 double precision, intent(out):: trad(ixi^s)
4199
4200 trad(ixi^s) = (w(ixi^s,r_e)/arad_norm)**(1.d0/4.d0)
4201
4202 end subroutine mhd_get_trad
4203
4204 !> Calculate fluxes within ixO^L without any splitting
4205 subroutine mhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
4207 use mod_geometry
4208
4209 integer, intent(in) :: ixi^l, ixo^l, idim
4210 ! conservative w
4211 double precision, intent(in) :: wc(ixi^s,nw)
4212 ! primitive w
4213 double precision, intent(in) :: w(ixi^s,nw)
4214 double precision, intent(in) :: x(ixi^s,1:ndim)
4215 double precision,intent(out) :: f(ixi^s,nwflux)
4216
4217 double precision :: vhall(ixi^s,1:ndir)
4218 double precision :: ptotal
4219 integer :: iw, ix^d
4220
4221 if(mhd_internal_e) then
4222 {do ix^db=ixomin^db,ixomax^db\}
4223 ! Get flux of density
4224 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4225 ! f_i[m_k]=v_i*m_k-b_k*b_i
4226 ^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_)\
4227 ! normal one includes total pressure
4228 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4229 ! Get flux of internal energy
4230 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4231 ! f_i[b_k]=v_i*b_k-v_k*b_i
4232 ^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_)\
4233 {end do\}
4234 else
4235 {do ix^db=ixomin^db,ixomax^db\}
4236 ! Get flux of density
4237 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4238 ! f_i[m_k]=v_i*m_k-b_k*b_i
4239 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-w(ix^d,mag(idim))*w(ix^d,b^c_)\
4240 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4241 ! normal one includes total pressure
4242 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4243 ! Get flux of total energy
4244 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4245 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4246 -w(ix^d,mag(idim))*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4247 ! f_i[b_k]=v_i*b_k-v_k*b_i
4248 ^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_)\
4249 {end do\}
4250 end if
4251 if(mhd_hall) then
4252 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4253 {do ix^db=ixomin^db,ixomax^db\}
4254 if(total_energy) then
4255 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4256 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)**2+)&
4257 -w(ix^d,mag(idim))*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4258 end if
4259 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4260 ^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))\
4261 {end do\}
4262 end if
4263
4264 if(mhd_glm) then
4265 {do ix^db=ixomin^db,ixomax^db\}
4266 f(ix^d,mag(idim))=w(ix^d,psi_)
4267 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4268 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4269 {end do\}
4270 end if
4271
4272 if(mhd_radiation_fld) then
4273 {do ix^db=ixomin^db,ixomax^db\}
4274 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4275 {end do\}
4276 endif
4277
4278 ! Get flux of tracer
4279 do iw=1,mhd_n_tracer
4280 {do ix^db=ixomin^db,ixomax^db\}
4281 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4282 {end do\}
4283 end do
4284
4286 {do ix^db=ixomin^db,ixomax^db\}
4287 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(^c&w({ix^d},b^c_)**2+)+smalldouble)
4288 f(ix^d,q_)=zero
4289 {end do\}
4290 end if
4291
4292 end subroutine mhd_get_flux
4293
4294 !> Calculate fluxes within ixO^L for case without energy equation, hence without splitting
4295 !> and assuming polytropic closure
4296 subroutine mhd_get_flux_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4298 use mod_geometry
4300
4301 integer, intent(in) :: ixi^l, ixo^l, idim
4302 ! conservative w
4303 double precision, intent(in) :: wc(ixi^s,nw)
4304 ! primitive w
4305 double precision, intent(in) :: w(ixi^s,nw)
4306 double precision, intent(in) :: x(ixi^s,1:ndim)
4307 double precision,intent(out) :: f(ixi^s,nwflux)
4308
4309 double precision :: vhall(ixi^s,1:ndir)
4310 double precision :: adiabs(ixi^s), gammas(ixi^s)
4311 integer :: iw, ix^d
4312
4313 if(associated(usr_set_adiab)) then
4314 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4315 else
4316 adiabs=mhd_adiab
4317 end if
4318 if(associated(usr_set_gamma)) then
4319 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4320 else
4321 gammas=mhd_gamma
4322 end if
4323 {do ix^db=ixomin^db,ixomax^db\}
4324 ! Get flux of density
4325 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4326 ! f_i[m_k]=v_i*m_k-b_k*b_i
4327 ^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_)\
4328 ! normal one includes total pressure
4329 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+)
4330 ! f_i[b_k]=v_i*b_k-v_k*b_i
4331 ^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_)\
4332 {end do\}
4333 if(mhd_hall) then
4334 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4335 {do ix^db=ixomin^db,ixomax^db\}
4336 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4337 ^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))\
4338 {end do\}
4339 end if
4340 if(mhd_glm) then
4341 {do ix^db=ixomin^db,ixomax^db\}
4342 f(ix^d,mag(idim))=w(ix^d,psi_)
4343 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4344 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4345 {end do\}
4346 end if
4347 ! Get flux of tracer
4348 do iw=1,mhd_n_tracer
4349 {do ix^db=ixomin^db,ixomax^db\}
4350 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4351 {end do\}
4352 end do
4353
4354 end subroutine mhd_get_flux_noe
4355
4356 !> Calculate fluxes with hydrodynamic energy equation
4357 subroutine mhd_get_flux_hde(wC,w,x,ixI^L,ixO^L,idim,f)
4359 use mod_geometry
4360
4361 integer, intent(in) :: ixi^l, ixo^l, idim
4362 ! conservative w
4363 double precision, intent(in) :: wc(ixi^s,nw)
4364 ! primitive w
4365 double precision, intent(in) :: w(ixi^s,nw)
4366 double precision, intent(in) :: x(ixi^s,1:ndim)
4367 double precision,intent(out) :: f(ixi^s,nwflux)
4368
4369 double precision :: vhall(ixi^s,1:ndir)
4370 integer :: iw, ix^d
4371
4372 {do ix^db=ixomin^db,ixomax^db\}
4373 ! Get flux of density
4374 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4375 ! f_i[m_k]=v_i*m_k-b_k*b_i
4376 ^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_)\
4377 ! normal one includes total pressure
4378 f(ix^d,mom(idim))=f(ix^d,mom(idim))+w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4379 ! Get flux of energy
4380 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+w(ix^d,p_))
4381 ! f_i[b_k]=v_i*b_k-v_k*b_i
4382 ^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_)\
4383 {end do\}
4384 if(mhd_hall) then
4385 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4386 {do ix^db=ixomin^db,ixomax^db\}
4387 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4388 ^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))\
4389 {end do\}
4390 end if
4391 if(mhd_glm) then
4392 {do ix^db=ixomin^db,ixomax^db\}
4393 f(ix^d,mag(idim))=w(ix^d,psi_)
4394 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4395 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4396 {end do\}
4397 end if
4398 ! Get flux of tracer
4399 do iw=1,mhd_n_tracer
4400 {do ix^db=ixomin^db,ixomax^db\}
4401 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4402 {end do\}
4403 end do
4404
4406 {do ix^db=ixomin^db,ixomax^db\}
4407 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(^c&w({ix^d},b^c_)**2+)+smalldouble)
4408 f(ix^d,q_)=zero
4409 {end do\}
4410 end if
4411
4412 end subroutine mhd_get_flux_hde
4413
4414 !> Calculate fluxes within ixO^L with possible splitting
4415 !> this covers four cases: B0field=T and mhd_internal_e=T (where has_equi_rho_and_p=F)
4416 !> B0field=T and has_equi_rho_and_p=F for total_energy=T
4417 !> B0field=F and has_equi_rho_and_p=T for total_energy=T
4418 !> B0field=T and has_equi_rho_and_p=T for total_energy=T
4419 subroutine mhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
4421 use mod_geometry
4422
4423 integer, intent(in) :: ixi^l, ixo^l, idim
4424 ! conservative w
4425 double precision, intent(in) :: wc(ixi^s,nw)
4426 ! primitive w
4427 double precision, intent(in) :: w(ixi^s,nw)
4428 double precision, intent(in) :: x(ixi^s,1:ndim)
4429 double precision,intent(out) :: f(ixi^s,nwflux)
4430
4431 double precision :: vhall(ixi^s,1:ndir)
4432 double precision :: ptotal, btotal(ixo^s,1:ndir)
4433 integer :: iw, ix^d
4434
4435 {do ix^db=ixomin^db,ixomax^db\}
4436 ! Get flux of density
4437 if(has_equi_rho_and_p) then
4438 f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
4439 else
4440 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4441 end if
4442
4443 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
4444
4445 if(b0field) then
4446 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)+block%B0(ix^d,^c,idim)\
4447 ptotal=ptotal+(^c&w(ix^d,b^c_)*block%B0(ix^d,^c,idim)+)
4448 ! Get flux of momentum and magnetic field
4449 ! f_i[m_k]=v_i*m_k-b_k*b_i
4450 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-&
4451 btotal(ix^d,idim)*w(ix^d,b^c_)-w(ix^d,mag(idim))*block%B0(ix^d,^c,idim)\
4452 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4453 else
4454 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)\
4455 ! Get flux of momentum and magnetic field
4456 ! f_i[m_k]=v_i*m_k-b_k*b_i
4457 ^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_)\
4458 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
4459 end if
4460 ! f_i[b_k]=v_i*b_k-v_k*b_i
4461 ^c&f(ix^d,b^c_)=w(ix^d,mom(idim))*btotal(ix^d,^c)-btotal(ix^d,idim)*w(ix^d,m^c_)\
4462
4463 ! Get flux of energy
4464 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
4465 if(mhd_internal_e) then
4466 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4467 else
4468 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
4469 -btotal(ix^d,idim)*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
4470 end if
4471 {end do\}
4472
4473 if(mhd_glm) then
4474 {do ix^db=ixomin^db,ixomax^db\}
4475 f(ix^d,mag(idim))=w(ix^d,psi_)
4476 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4477 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
4478 {end do\}
4479 end if
4480
4481 if(mhd_radiation_fld) then
4482 {do ix^db=ixomin^db,ixomax^db\}
4483 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
4484 {end do\}
4485 endif
4486
4487 if(mhd_hall) then
4488 call mhd_getv_hall(w,x,ixi^l,ixo^l,vhall)
4489 {do ix^db=ixomin^db,ixomax^db\}
4490 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
4491 ^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)\
4492 if(total_energy) then
4493 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
4494 f(ix^d,e_)=f(ix^d,e_)+vhall(ix^d,idim)*(^c&w(ix^d,b^c_)*btotal(ix^d,^c)+)&
4495 -btotal(ix^d,idim)*(^c&vhall(ix^d,^c)*w(ix^d,b^c_)+)
4496 end if
4497 {end do\}
4498 end if
4499 ! Get flux of tracer
4500 do iw=1,mhd_n_tracer
4501 {do ix^db=ixomin^db,ixomax^db\}
4502 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4503 {end do\}
4504 end do
4506 {do ix^db=ixomin^db,ixomax^db\}
4507 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*btotal(ix^d,idim)/(dsqrt(^c&btotal({ix^d},^c)**2+)+smalldouble)
4508 f(ix^d,q_)=zero
4509 {end do\}
4510 end if
4511
4512 end subroutine mhd_get_flux_split
4513
4514 !> Calculate semirelativistic fluxes within ixO^L without any splitting
4515 subroutine mhd_get_flux_semirelati(wC,w,x,ixI^L,ixO^L,idim,f)
4517 use mod_geometry
4518
4519 integer, intent(in) :: ixi^l, ixo^l, idim
4520 ! conservative w
4521 double precision, intent(in) :: wc(ixi^s,nw)
4522 ! primitive w
4523 double precision, intent(in) :: w(ixi^s,nw)
4524 double precision, intent(in) :: x(ixi^s,1:ndim)
4525 double precision,intent(out) :: f(ixi^s,nwflux)
4526
4527 double precision :: sa(ixo^s,1:ndir),e(ixo^s,1:ndir),e2
4528 integer :: iw, ix^d
4529
4530 {do ix^db=ixomin^db,ixomax^db\}
4531 ! Get flux of density
4532 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4533 ! E=Bxv
4534 {^ifthreec
4535 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4536 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4537 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4538 }
4539 {^iftwoc
4540 e(ix^d,1)=zero
4541 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4542 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4543 }
4544 {^ifonec
4545 e(ix^d,1)=zero
4546 }
4547 e2=(^c&e(ix^d,^c)**2+)
4548 if(mhd_internal_e) then
4549 ! Get flux of internal energy
4550 f(ix^d,e_)=w(ix^d,mom(idim))*wc(ix^d,e_)
4551 else
4552 ! S=ExB
4553 {^ifthreec
4554 sa(ix^d,1)=e(ix^d,2)*w(ix^d,b3_)-e(ix^d,3)*w(ix^d,b2_)
4555 sa(ix^d,2)=e(ix^d,3)*w(ix^d,b1_)-e(ix^d,1)*w(ix^d,b3_)
4556 sa(ix^d,3)=e(ix^d,1)*w(ix^d,b2_)-e(ix^d,2)*w(ix^d,b1_)
4557 }
4558 {^iftwoc
4559 sa(ix^d,1)=-e(ix^d,2)*w(ix^d,b2_)
4560 sa(ix^d,2)=e(ix^d,2)*w(ix^d,b1_)
4561 ! set E2 back to 0, after e^2 is stored
4562 e(ix^d,2)=zero
4563 }
4564 {^ifonec
4565 sa(ix^d,1)=zero
4566 }
4567 ! Get flux of total energy
4568 f(ix^d,e_)=w(ix^d,mom(idim))*(half*w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)+&
4569 mhd_gamma*w(ix^d,p_)*inv_gamma_1)+sa(ix^d,idim)
4570 end if
4571 ! Get flux of momentum
4572 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4573 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4574 ! gas pressure + magnetic pressure + electric pressure
4575 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)
4576 ! compute flux of magnetic field
4577 ! f_i[b_k]=v_i*b_k-v_k*b_i
4578 ^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_)\
4579 {end do\}
4580
4581 if(mhd_glm) then
4582 {do ix^db=ixomin^db,ixomax^db\}
4583 f(ix^d,mag(idim))=w(ix^d,psi_)
4584 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4585 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4586 {end do\}
4587 end if
4588 ! Get flux of tracer
4589 do iw=1,mhd_n_tracer
4590 {do ix^db=ixomin^db,ixomax^db\}
4591 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4592 {end do\}
4593 end do
4595 {do ix^db=ixomin^db,ixomax^db\}
4596 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(^c&w({ix^d},b^c_)**2+)+smalldouble)
4597 f(ix^d,q_)=zero
4598 {end do\}
4599 end if
4600
4601 end subroutine mhd_get_flux_semirelati
4602
4603 subroutine mhd_get_flux_semirelati_noe(wC,w,x,ixI^L,ixO^L,idim,f)
4605 use mod_geometry
4607
4608 integer, intent(in) :: ixi^l, ixo^l, idim
4609 ! conservative w
4610 double precision, intent(in) :: wc(ixi^s,nw)
4611 ! primitive w
4612 double precision, intent(in) :: w(ixi^s,nw)
4613 double precision, intent(in) :: x(ixi^s,1:ndim)
4614 double precision,intent(out) :: f(ixi^s,nwflux)
4615
4616 double precision :: adiabs(ixi^s), gammas(ixi^s)
4617 double precision :: e(ixo^s,1:ndir),e2
4618 integer :: iw, ix^d
4619
4620 if(associated(usr_set_adiab)) then
4621 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
4622 else
4623 adiabs=mhd_adiab
4624 end if
4625 if(associated(usr_set_gamma)) then
4626 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
4627 else
4628 gammas=mhd_gamma
4629 end if
4630 {do ix^db=ixomin^db,ixomax^db\}
4631 ! Get flux of density
4632 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
4633 ! E=Bxv
4634 {^ifthreec
4635 e(ix^d,1)=w(ix^d,b2_)*w(ix^d,m3_)-w(ix^d,b3_)*w(ix^d,m2_)
4636 e(ix^d,2)=w(ix^d,b3_)*w(ix^d,m1_)-w(ix^d,b1_)*w(ix^d,m3_)
4637 e(ix^d,3)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4638 e2=(^c&e(ix^d,^c)**2+)
4639 }
4640 {^iftwoc
4641 e(ix^d,1)=zero
4642 ! switch 2 and 3 to add 3 when ^C is from 1 to 2
4643 e(ix^d,2)=w(ix^d,b1_)*w(ix^d,m2_)-w(ix^d,b2_)*w(ix^d,m1_)
4644 e2=e(ix^d,2)**2
4645 e(ix^d,2)=zero
4646 }
4647 {^ifonec
4648 e(ix^d,1)=zero
4649 e2=zero
4650 }
4651 ! Get flux of momentum
4652 ^c&f(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,mom(idim))*w(ix^d,m^c_)&
4653 -w(ix^d,mag(idim))*w(ix^d,b^c_)-e(ix^d,idim)*e(ix^d,^c)*inv_squared_c\
4654 ! gas pressure + magnetic pressure + electric pressure
4655 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)
4656 ! compute flux of magnetic field
4657 ! f_i[b_k]=v_i*b_k-v_k*b_i
4658 ^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_)\
4659 {end do\}
4660
4661 if(mhd_glm) then
4662 {do ix^db=ixomin^db,ixomax^db\}
4663 f(ix^d,mag(idim))=w(ix^d,psi_)
4664 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
4665 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
4666 {end do\}
4667 end if
4668 ! Get flux of tracer
4669 do iw=1,mhd_n_tracer
4670 {do ix^db=ixomin^db,ixomax^db\}
4671 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
4672 {end do\}
4673 end do
4674
4675 end subroutine mhd_get_flux_semirelati_noe
4676
4677 !> Source term J.E_ambi in internal energy
4678 !> For the ambipolar electric field we have E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4679 !> and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4680 !> the source term J.E_ambi = eta_A * B^2 * J_perpB^2 = eta_A * [(JxB)xB]^2/B^2
4681 !> note that J_perpB= - (JxB)xB/B^2
4682 !> multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4683 subroutine add_source_ambipolar_internal_energy(qdt,ixI^L,ixO^L,wCT,w,x)
4685 integer, intent(in) :: ixi^l, ixo^l
4686 double precision, intent(in) :: qdt
4687 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4688 double precision, intent(inout) :: w(ixi^s,1:nw)
4689
4690 double precision :: tmp(ixi^s),btot2(ixi^s)
4691 double precision :: jxbxb(ixi^s,1:3)
4692
4693 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,jxbxb)
4694 ! avoiding nulls here
4695 btot2(ixo^s)=mhd_mag_en_all(wct,ixi^l,ixo^l)
4696 where (btot2(ixo^s)>smalldouble )
4697 tmp(ixo^s) = sum(jxbxb(ixo^s,1:3)**2,dim=ndim+1) / btot2(ixo^s)
4698 elsewhere
4699 tmp(ixo^s) = zero
4700 endwhere
4701 call multiplyambicoef(ixi^l,ixo^l,tmp,wct,x)
4702 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4703 ! hence minus sign here
4704 w(ixo^s,e_)=w(ixo^s,e_)- qdt*tmp(ixo^s)
4705
4706 end subroutine add_source_ambipolar_internal_energy
4707
4708 !> this subroutine computes -J_perpB= (J x B) x B= B(J.B) - J B^2
4709 subroutine mhd_get_jxbxb(w,x,ixI^L,ixO^L,res)
4711
4712 integer, intent(in) :: ixi^l, ixo^l
4713 double precision, intent(in) :: w(ixi^s,nw)
4714 double precision, intent(in) :: x(ixi^s,1:ndim)
4715 double precision, intent(out) :: res(ixi^s,1:3)
4716
4717 double precision :: btot(ixi^s,1:3)
4718 double precision :: current(ixi^s,7-2*ndir:3)
4719 double precision :: tmp(ixi^s),b2(ixi^s)
4720 integer :: idir, idirmin
4721
4722 res=0.d0
4723 ! Calculate current density and idirmin
4724 ! current has nonzero values only for components in the range idirmin, 3
4725 call get_current(w,ixi^l,ixo^l,idirmin,current)
4726
4727 btot=0.d0
4728 if(b0field) then
4729 do idir=1,ndir
4730 btot(ixo^s, idir) = w(ixo^s,mag(idir)) + block%B0(ixo^s,idir,b0i)
4731 enddo
4732 else
4733 do idir=1,ndir
4734 btot(ixo^s, idir) = w(ixo^s,mag(idir))
4735 enddo
4736 endif
4737
4738 tmp(ixo^s)= sum(current(ixo^s,idirmin:3)*btot(ixo^s,idirmin:3),dim=ndim+1) !J.B
4739 b2(ixo^s) = sum(btot(ixo^s,1:3)**2,dim=ndim+1) !B^2
4740 do idir=1,idirmin-1
4741 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s)
4742 enddo
4743 do idir=idirmin,3
4744 res(ixo^s,idir) = btot(ixo^s,idir) * tmp(ixo^s) - current(ixo^s,idir) * b2(ixo^s)
4745 enddo
4746
4747 ! avoid possible issues at nulls
4748 do idir=1,3
4749 where (b2(ixo^s)<smalldouble )
4750 res(ixo^s,idir) = zero
4751 endwhere
4752 enddo
4753 end subroutine mhd_get_jxbxb
4754
4755 !> Sets the sources for the ambipolar terms for the STS method
4756 !> The sources are added directly (instead of fluxes as in the explicit)
4757 !> at the corresponding indices
4758 !> store_flux_var is explicitly called for each of the fluxes one by one
4759 subroutine sts_set_source_ambipolar(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
4762
4763 integer, intent(in) :: ixi^l,ixo^l,igrid,nflux
4764 double precision, intent(in) :: x(ixi^s,1:ndim)
4765 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
4766 double precision, intent(in) :: my_dt
4767 logical, intent(in) :: fix_conserve_at_step
4768
4769 double precision, dimension(ixI^S,1:3) :: tmp,ff
4770 double precision :: fluxall(ixi^s,1:nflux,1:ndim)
4771 double precision :: fe(ixi^s,sdim:3)
4772 double precision :: btot(ixi^s,1:3),tmp2(ixi^s)
4773 integer :: i, ixa^l, ie_
4774
4775 ixa^l=ixo^l^ladd1;
4776
4777 fluxall=zero
4778
4779 ! here we compute (JxB)xB= - B^2 J_perpB
4780 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,tmp)
4781
4782 ! set ambipolar electric field in tmp: E_ambi = -eta_A * JxBxB= eta_A * B^2 (J_perpB)
4783 ! and eta_A is mhd_ambi_coef/rho^2 or is user-defined
4784 ! multiplyAmbiCoef is actually doing multiplication with -mhd_ambi_coef/rho^2
4785 do i=1,3
4786 call multiplyambicoef(ixi^l,ixa^l,tmp(ixi^s,i),w,x)
4787 enddo
4788
4789 ! Note: internal energy case is handled through add_source_internal_e
4790 ! Note: hydrodynamic energy case is handled through add_source_hydrodynamic_e
4791 ! both of the above use add_source_ambipolar_internal_energy
4792 !
4793 ! Note: total energy case without B0field split is ok here and adds div(BxE_ambi)
4794 ! Note: total energy case in semirelativistic variant (hence no B0field split) is ok here
4795 ! Note: total energy with B0field=T here adds div(B_1xE_ambi) which needs correction in add_source_B0split
4796 if(mhd_energy .and. .not.(mhd_internal_e.or.mhd_hydrodynamic_e)) then
4797 btot(ixa^s,1:3) = 0.d0
4798 ! HERE: only uses B_1 if split, otherwise this is B
4799 btot(ixa^s,1:ndir) = w(ixa^s,mag(1:ndir))
4800 ! compute ff= E_ambi x B (where B can be B_1 if B0field=T)
4801 call cross_product(ixi^l,ixa^l,tmp,btot,ff)
4802 ! compute actual cell face fluxes in ff and their divergence in tmp2
4803 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4804 if(fix_conserve_at_step) fluxall(ixi^s,1,1:ndim)=ff(ixi^s,1:ndim)
4805 ! - sign as the source is actually div(BxE_ambi) and we have div(E_ambi x B) in tmp2
4806 wres(ixo^s,e_)=-tmp2(ixo^s)
4807 endif
4808
4809 if(stagger_grid) then
4810 ! always 2D or more (2.5/3D)
4811 if(ndir>ndim) then
4812 !!!Bz
4813 ff(ixa^s,1) = tmp(ixa^s,2)
4814 ff(ixa^s,2) = -tmp(ixa^s,1)
4815 ff(ixa^s,3) = 0.d0
4816 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4817 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
4818 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
4819 end if
4820 fe=0.d0
4821 call update_faces_ambipolar(ixi^l,ixo^l,w,x,tmp,fe,btot)
4822 ixamax^d=ixomax^d;
4823 ixamin^d=ixomin^d-1;
4824 wres(ixa^s,mag(1:ndim))=-btot(ixa^s,1:ndim)
4825 else
4826 !write curl(ele) as the divergence
4827 !m1={0,ele[[3]],-ele[[2]]}
4828 !m2={-ele[[3]],0,ele[[1]]}
4829 !m3={ele[[2]],-ele[[1]],0}
4830
4831 {^ifoned
4832 !!!Bx
4833 ff(ixa^s,1) = 0.d0
4834 ff(ixa^s,2) = tmp(ixa^s,3)
4835 ff(ixa^s,3) = -tmp(ixa^s,2)
4836 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4837 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
4838 !flux divergence is a source now
4839 wres(ixo^s,mag(1))=-tmp2(ixo^s)
4840 if(ndir==2.or.ndir==3)then
4841 !!!By
4842 ff(ixa^s,1) = -tmp(ixa^s,3)
4843 ff(ixa^s,2) = 0.d0
4844 ff(ixa^s,3) = tmp(ixa^s,1)
4845 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4846 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
4847 wres(ixo^s,mag(2))=-tmp2(ixo^s)
4848 endif
4849 }
4850 {^nooned
4851 !!!Bx
4852 ff(ixa^s,1) = 0.d0
4853 ff(ixa^s,2) = tmp(ixa^s,3)
4854 ff(ixa^s,3) = -tmp(ixa^s,2)
4855 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4856 if(fix_conserve_at_step) fluxall(ixi^s,2,1:ndim)=ff(ixi^s,1:ndim)
4857 !flux divergence is a source now
4858 wres(ixo^s,mag(1))=-tmp2(ixo^s)
4859 !!!By
4860 ff(ixa^s,1) = -tmp(ixa^s,3)
4861 ff(ixa^s,2) = 0.d0
4862 ff(ixa^s,3) = tmp(ixa^s,1)
4863 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4864 if(fix_conserve_at_step) fluxall(ixi^s,3,1:ndim)=ff(ixi^s,1:ndim)
4865 wres(ixo^s,mag(2))=-tmp2(ixo^s)
4866 }
4867
4868 if(ndir==3) then
4869 !!!Bz
4870 ff(ixa^s,1) = tmp(ixa^s,2)
4871 ff(ixa^s,2) = -tmp(ixa^s,1)
4872 ff(ixa^s,3) = 0.d0
4873 call get_flux_on_cell_face(ixi^l,ixo^l,ff,tmp2)
4874 if(fix_conserve_at_step) fluxall(ixi^s,1+ndir,1:ndim)=ff(ixi^s,1:ndim)
4875 wres(ixo^s,mag(ndir))=-tmp2(ixo^s)
4876 end if
4877
4878 end if
4879
4880 if(fix_conserve_at_step) then
4881 fluxall=my_dt*fluxall
4882 call store_flux(igrid,fluxall,1,ndim,nflux)
4883 if(stagger_grid) then
4884 call store_edge(igrid,ixi^l,my_dt*fe,1,ndim)
4885 end if
4886 end if
4887
4888 end subroutine sts_set_source_ambipolar
4889
4890 !> get ambipolar electric field and the integrals around cell faces
4891 subroutine update_faces_ambipolar(ixI^L,ixO^L,w,x,ECC,fE,circ)
4893
4894 integer, intent(in) :: ixi^l, ixo^l
4895 double precision, intent(in) :: w(ixi^s,1:nw)
4896 double precision, intent(in) :: x(ixi^s,1:ndim)
4897 ! amibipolar electric field at cell centers
4898 double precision, intent(in) :: ecc(ixi^s,1:3)
4899 double precision, intent(out) :: fe(ixi^s,sdim:3)
4900 double precision, intent(out) :: circ(ixi^s,1:ndim)
4901
4902 integer :: hxc^l,ixc^l,ixa^l
4903 integer :: idim1,idim2,idir,ix^d
4904
4905 fe=zero
4906 ! calculate ambipolar electric field on cell edges from cell centers
4907 do idir=sdim,3
4908 ixcmax^d=ixomax^d;
4909 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4910 {do ix^db=0,1\}
4911 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
4912 ixamin^d=ixcmin^d+ix^d;
4913 ixamax^d=ixcmax^d+ix^d;
4914 fe(ixc^s,idir)=fe(ixc^s,idir)+ecc(ixa^s,idir)
4915 {end do\}
4916 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0*block%dsC(ixc^s,idir)
4917 end do
4918
4919 ! Calculate circulation on each face to get value of line integral of
4920 ! electric field in the positive idir direction.
4921 ixcmax^d=ixomax^d;
4922 ixcmin^d=ixomin^d-1;
4923
4924 circ=zero
4925 do idim1=1,ndim ! Coordinate perpendicular to face
4926 do idim2=1,ndim
4927 do idir=sdim,3 ! Direction of line integral
4928 ! Assemble indices
4929 hxc^l=ixc^l-kr(idim2,^d);
4930 ! Add line integrals in direction idir
4931 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4932 +lvc(idim1,idim2,idir)&
4933 *(fe(ixc^s,idir)&
4934 -fe(hxc^s,idir))
4935 end do
4936 end do
4937 circ(ixc^s,idim1)=circ(ixc^s,idim1)/block%surfaceC(ixc^s,idim1)
4938 end do
4939
4940 end subroutine update_faces_ambipolar
4941
4942 !> use cell-center flux vector to get cell-face flux vector
4943 !> which will be used to add the source term as the divergence of the flux
4944 !> we return fluxes at all faces as well as the divergence of the flux
4945 !> Note that for ndir>ndim, we do not modify the input cell center flux
4946 subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
4948
4949 integer, intent(in) :: ixi^l, ixo^l
4950 double precision, dimension(ixI^S,1:3), intent(inout) :: ff
4951 double precision, intent(out) :: src(ixi^s)
4952
4953 double precision :: ffc(ixi^s,1:ndim)
4954 double precision :: dxinv(ndim)
4955 integer :: idims, ix^d, ixa^l, ixb^l, ixc^l
4956
4957 ixa^l=ixo^l^ladd1;
4958 dxinv=1.d0/dxlevel
4959 ! cell corner flux in ffc
4960 ! TO BE GENERALIZED FOR NON-UNIFORM NON-CARTESIAN MESH
4961 if (slab_uniform)then
4962 ffc=0.d0
4963 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
4964 {do ix^db=0,1\}
4965 ixbmin^d=ixcmin^d+ix^d;
4966 ixbmax^d=ixcmax^d+ix^d;
4967 ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
4968 {end do\}
4969 ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
4970 else
4971 call mpistop("to generalize using volume averaging")
4972 endif
4973 ! now get flux at cell face from corner fluxes in fcc
4974 ff(ixi^s,1:ndim)=0.d0
4975 do idims=1,ndim
4976 ixb^l=ixo^l-kr(idims,^d);
4977 ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
4978 {do ix^db=0,1 \}
4979 if({ ix^d==0 .and. ^d==idims | .or.}) then
4980 ixbmin^d=ixcmin^d-ix^d;
4981 ixbmax^d=ixcmax^d-ix^d;
4982 ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
4983 end if
4984 {end do\}
4985 ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
4986 end do
4987 src=0.d0
4988 if(slab_uniform) then
4989 do idims=1,ndim
4990 ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
4991 ixb^l=ixo^l-kr(idims,^d);
4992 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4993 end do
4994 else
4995 do idims=1,ndim
4996 ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
4997 ixb^l=ixo^l-kr(idims,^d);
4998 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
4999 end do
5000 src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
5001 end if
5002 end subroutine get_flux_on_cell_face
5003
5004 !> Calculates the explicit dt for the ambipolar term
5005 !> This function is used by both explicit scheme and STS method
5006 function get_ambipolar_dt(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
5008
5009 integer, intent(in) :: ixi^l, ixo^l
5010 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
5011 double precision, intent(in) :: w(ixi^s,1:nw)
5012 double precision :: dtnew
5013
5014 double precision :: coef
5015 double precision :: dxarr(ndim)
5016 double precision :: tmp(ixi^s)
5017
5018 ^d&dxarr(^d)=dx^d;
5019 tmp(ixo^s) = mhd_mag_en_all(w, ixi^l, ixo^l)
5020 call multiplyambicoef(ixi^l,ixo^l,tmp,w,x)
5021 ! now we have -mhd_eta_ambi B^2 /rho^2 in tmp
5022 coef = maxval(dabs(tmp(ixo^s)))
5023 if(coef/=0.d0) then
5024 coef=1.d0/coef
5025 else
5026 coef=bigdouble
5027 end if
5028 if(slab_uniform) then
5029 dtnew=minval(dxarr(1:ndim))**2.0d0*coef
5030 else
5031 dtnew=minval(block%ds(ixo^s,1:ndim))**2.0d0*coef
5032 end if
5033
5034 end function get_ambipolar_dt
5035
5036 !> multiply res by the ambipolar coefficient
5037 !> The ambipolar coefficient is calculated as -mhd_eta_ambi/rho^2
5038 !> The user may mask its value in the user file
5039 !> by implementing usr_mask_ambipolar subroutine
5040 subroutine multiplyambicoef(ixI^L,ixO^L,res,w,x)
5042 integer, intent(in) :: ixi^l, ixo^l
5043 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
5044 double precision, intent(inout) :: res(ixi^s)
5045 double precision :: tmp(ixi^s)
5046 double precision :: rho(ixi^s)
5047
5048 call mhd_get_rho(w,x,ixi^l,ixi^l,rho)
5049 tmp(ixi^s)=-mhd_eta_ambi/rho(ixi^s)**2
5050 if (associated(usr_mask_ambipolar)) then
5051 call usr_mask_ambipolar(ixi^l,ixo^l,w,x,tmp)
5052 end if
5053 res(ixo^s) = tmp(ixo^s) * res(ixo^s)
5054
5055 end subroutine multiplyambicoef
5056
5057 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
5058 subroutine mhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5063 use mod_cak_force, only: cak_add_source
5064
5065 integer, intent(in) :: ixi^l, ixo^l
5066 double precision, intent(in) :: qdt,dtfactor
5067 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
5068 double precision, intent(inout) :: w(ixi^s,1:nw)
5069 logical, intent(in) :: qsourcesplit
5070 logical, intent(inout) :: active
5071
5072 !TODO local_timestep support is only added for splitting
5073 ! but not for other nonideal terms such gravity, RC, viscosity,..
5074 ! it will also only work for divbfix 'linde', which does not require
5075 ! modification as it does not use dt in the update
5076
5077 if (.not. qsourcesplit) then
5078 if(mhd_internal_e) then
5079 ! Source for solving internal energy
5080 active = .true.
5081 call add_source_internal_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5082 else
5083 if(has_equi_rho_and_p) then
5084 active = .true.
5085 call add_equi_terms(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5086 end if
5087 end if
5088
5090 active = .true.
5091 call add_hypertc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5092 end if
5093
5094 ! Source for B0 splitting
5095 if (b0field) then
5096 active = .true.
5097 ! this adds source to momentum of type J0 x B0 and to energy equation
5098 ! latter always + J0 * E (electric field being E_ideal, E_hall, E_ambi)
5099 ! used for total energy variants
5100 call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wct,w,x,wctprim)
5101 end if
5102
5103 ! Sources for resistivity in eqs. for e, B1, B2 and B3
5104 if (abs(mhd_eta)>smalldouble)then
5105 active = .true.
5106 call add_source_res_exp(qdt,ixi^l,ixo^l,wct,w,x)
5107 end if
5108
5109 if (mhd_ambipolar_exp)then
5110 active = .true.
5111 call add_source_ambi_exp(qdt,ixi^l,ixo^l,wct,w,x)
5112 end if
5113
5114 if (mhd_eta_hyper>0.d0)then
5115 active = .true.
5116 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
5117 end if
5118
5119 if(mhd_hydrodynamic_e) then
5120 ! Source for solving hydrodynamic energy
5121 active = .true.
5122 call add_source_hydrodynamic_e(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5123 else if (mhd_semirelativistic) then
5124 ! add sources for semirelativistic MHD
5125 active = .true.
5126 call add_source_semirelativistic(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
5127 end if
5128 end if
5129
5130 {^nooned
5131 if(source_split_divb .eqv. qsourcesplit) then
5132 ! Sources related to div B
5133 select case (type_divb)
5134 case (divb_ct)
5135 continue ! Do nothing
5136 case (divb_linde)
5137 active = .true.
5138 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5139 case (divb_glm)
5140 active = .true.
5141 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5142 case (divb_powel)
5143 active = .true.
5144 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5145 case (divb_janhunen)
5146 active = .true.
5147 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5148 case (divb_lindejanhunen)
5149 active = .true.
5150 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5151 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
5152 case (divb_lindepowel)
5153 active = .true.
5154 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5155 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
5156 case (divb_lindeglm)
5157 active = .true.
5158 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
5159 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
5160 case (divb_multigrid)
5161 continue ! Do nothing
5162 case (divb_none)
5163 ! Do nothing
5164 case default
5165 call mpistop('Unknown divB fix')
5166 end select
5167 end if
5168 }
5169
5170 if(mhd_radiative_cooling) then
5171 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5172 w,x,qsourcesplit,active, rc_fl)
5173 end if
5174
5175 if(mhd_viscosity) then
5176 call viscosity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5177 w,x,mhd_energy,qsourcesplit,active)
5178 end if
5179
5180 if(mhd_gravity) then
5181 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
5182 w,x,gravity_energy,qsourcesplit,active)
5183 end if
5184
5185 if (mhd_cak_force) then
5186 call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,mhd_energy,qsourcesplit,active)
5187 end if
5188
5189 ! This is where the radiation force and heating/cooling are added
5190 if (mhd_radiation_fld) then
5191 call mhd_add_radiation_source(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
5192 endif
5193
5194 ! update temperature from new pressure, density, and old ionization degree
5195 if(mhd_partial_ionization) then
5196 if(.not.qsourcesplit) then
5197 active = .true.
5198 call mhd_update_temperature(ixi^l,ixo^l,wct,w,x)
5199 end if
5200 end if
5201
5202 end subroutine mhd_add_source
5203
5204 subroutine mhd_add_radiation_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
5205 use mod_constants
5207 use mod_usr_methods
5208 use mod_fld
5209
5210 integer, intent(in) :: ixi^l, ixo^l
5211 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
5212 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
5213 double precision, intent(inout) :: w(ixi^s,1:nw)
5214 logical, intent(in) :: qsourcesplit
5215 logical, intent(inout) :: active
5216
5217 ! add radiation force and work done by it, changes momentum and gas energy
5218 ! handle photon tiring, heating and cooling exchange between gas and radiation field
5219 call add_fld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
5220
5221 end subroutine mhd_add_radiation_source
5222
5223 !> add some source terms to total energy related to has_equi_rho_and_p=T
5224 subroutine add_equi_terms(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5226 use mod_geometry
5227 use mod_usr_methods
5228
5229 integer, intent(in) :: ixi^l, ixo^l
5230 double precision, intent(in) :: qdt,dtfactor
5231 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5232 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5233 double precision, intent(inout) :: w(ixi^s,1:nw)
5234
5235 double precision :: divv(ixi^s)
5236 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5237 double precision :: gravity_field(ixi^s,1:ndim)
5238 integer :: idir
5239
5240 if(slab_uniform) then
5241 if(nghostcells .gt. 2) then
5242 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,3)
5243 else
5244 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,2)
5245 end if
5246 else
5247 call divvector(wctprim(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv)
5248 end if
5249 divv(ixo^s)=divv(ixo^s)*mhd_gamma*inv_gamma_1
5250 if(local_timestep) then
5251 w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5252 else
5253 w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
5254 end if
5255 if(b0field)then
5256 if(b0field_forcefree.and.mhd_gravity)then
5257 ! add -v dot(rho_0 g)/(gamma-1)
5258 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5259 do idir=1,ndim
5260 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*inv_gamma_1
5261 enddo
5262 else
5263 a=0.d0
5264 b=0.d0
5265 ! store B0 magnetic field in b
5266 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5267 ! store J0 current in a
5268 do idir=7-2*ndir,3
5269 a(ixo^s,idir)=block%J0(ixo^s,idir)
5270 end do
5271 call cross_product(ixi^l,ixo^l,a,b,axb)
5272 ! add -v dot(rho_0 g + J0 x B_0)/(gamma-1)
5273 do idir=1,ndir
5274 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*axb(ixo^s,idir)*inv_gamma_1
5275 enddo
5276 if(mhd_gravity)then
5277 ! add -v dot(rho_0 g)/(gamma-1)
5278 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5279 do idir=1,ndim
5280 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*inv_gamma_1
5281 enddo
5282 endif
5283 endif
5284 else
5285 if(mhd_gravity)then
5286 ! add -v dot(rho_0 g)/(gamma-1)
5287 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
5288 do idir=1,ndim
5289 w(ixo^s,e_)=w(ixo^s,e_)-qdt*wctprim(ixo^s,mom(idir))*block%equi_vars(ixo^s,equi_rho0_,0)*gravity_field(ixo^s,idir)*inv_gamma_1
5290 enddo
5291 endif
5292 endif
5293 end subroutine add_equi_terms
5294
5295 subroutine add_hypertc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5297 integer, intent(in) :: ixi^l,ixo^l
5298 double precision, intent(in) :: qdt
5299 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
5300 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
5301 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
5302
5303 double precision :: r(ixi^s),te(ixi^s),rho_loc(ixi^s),pth_loc(ixi^s)
5304 double precision :: sigma_t5,sigma_t7,f_sat,sigmat5_bgradt,tau,bdir(ndir),bunitvec(ndim)
5305 double precision :: cmax(ndim),c2,cfast2,avmincs2(ndim),inv_rho
5306 integer :: ix^d
5307
5308 call mhd_get_rfactor(wct,x,ixi^l,ixi^l,r)
5309 {do ix^db=iximin^db,iximax^db\}
5310 if(has_equi_rho_and_p) then
5311 rho_loc(ix^d)=wctprim(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
5312 pth_loc(ix^d)=wctprim(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)
5313 else
5314 rho_loc(ix^d)=wctprim(ix^d,rho_)
5315 pth_loc(ix^d)=wctprim(ix^d,p_)
5316 end if
5317 te(ix^d)=pth_loc(ix^d)/(r(ix^d)*rho_loc(ix^d))
5318 {end do\}
5319 ! temperature on face T_(i+1/2)=(7(T_i+T_(i+1))-(T_(i-1)+T_(i+2)))/12
5320 ! T_(i+1/2)-T_(i-1/2)=(8(T_(i+1)-T_(i-1))-T_(i+2)+T_(i-2))/12
5321 {^ifoned
5322 ! assume magnetic field line is along the one dimension
5323 do ix1=ixomin1,ixomax1
5324 if(mhd_trac) then
5325 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
5326 sigma_t5=hypertc_kappa*dsqrt(block%wextra(ix^d,tcoff_)**5)
5327 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
5328 else
5329 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5330 sigma_t7=sigma_t5*te(ix^d)
5331 end if
5332 else
5333 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5334 sigma_t7=sigma_t5*te(ix^d)
5335 end if
5336 sigmat5_bgradt=sigma_t5*(8.d0*(te(ix1+1)-te(ix1-1))-te(ix1+2)+te(ix1-2))/12.d0/block%ds(ix^d,1)
5337 inv_rho=1.d0/rho_loc(ix1)
5338 c2=mhd_gamma*pth_loc(ix1)*inv_rho
5339 cfast2=(^c&bdir(^c)**2+)*inv_rho+c2
5340 avmincs2(1)=cfast2**2-4.0d0*c2*bdir(1)**2*inv_rho
5341 ! local fast wave speed in each dimension
5342 cmax(1)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(1)))))\
5343 if(mhd_htc_sat) then
5344 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
5345 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5346 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*cmax(1)**2))
5347 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
5348 else
5349 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
5350 max(4.d0*dt, sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*cmax(1)**2))
5351 end if
5352 end do
5353 }
5354 {^iftwod
5355 do ix2=ixomin2,ixomax2
5356 do ix1=ixomin1,ixomax1
5357 if(mhd_trac) then
5358 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
5359 sigma_t5=hypertc_kappa*dsqrt(block%wextra(ix^d,tcoff_)**5)
5360 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
5361 else
5362 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5363 sigma_t7=sigma_t5*te(ix^d)
5364 end if
5365 else
5366 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5367 sigma_t7=sigma_t5*te(ix^d)
5368 end if
5369 if(b0field) then
5370 ^c&bdir(^c)=wct({ix^d},mag(^c))+block%B0({ix^d},^c,0)\
5371 else
5372 ^c&bdir(^c)=wct({ix^d},mag(^c))\
5373 end if
5374 if(bdir(1)/=0.d0) then
5375 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(^ce&(bdir(^ce)/bdir(1))**2+))
5376 else
5377 bunitvec(1)=0.d0
5378 end if
5379 if(bdir(2)/=0.d0) then
5380 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(^cf&(bdir(^cf)/bdir(2))**2+))
5381 else
5382 bunitvec(2)=0.d0
5383 end if
5384 sigmat5_bgradt=sigma_t5*(&
5385 bunitvec(1)*((8.d0*(te(ix1+1,ix2)-te(ix1-1,ix2))-te(ix1+2,ix2)+te(ix1-2,ix2))/12.d0)/block%ds(ix^d,1)&
5386 +bunitvec(2)*((8.d0*(te(ix1,ix2+1)-te(ix1,ix2-1))-te(ix1,ix2+2)+te(ix1,ix2-2))/12.d0)/block%ds(ix^d,2))
5387 inv_rho=1.d0/rho_loc(ix^d)
5388 c2=mhd_gamma*pth_loc(ix^d)*inv_rho
5389 cfast2=(^c&bdir(^c)**2+)*inv_rho+c2
5390 ^d&avmincs2(^d)=cfast2**2-4.0d0*c2*bdir(^d)**2*inv_rho\
5391 ! local fast wave speed in each dimension
5392 ^d&cmax(^d)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(^d)))))\
5393 if(mhd_htc_sat) then
5394 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
5395 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5396 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5397 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
5398 else
5399 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
5400 max(4.d0*dt, sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5401 end if
5402 end do
5403 end do
5404 }
5405 {^ifthreed
5406 do ix3=ixomin3,ixomax3
5407 do ix2=ixomin2,ixomax2
5408 do ix1=ixomin1,ixomax1
5409 if(mhd_trac) then
5410 if(te(ix^d)<block%wextra(ix^d,tcoff_)) then
5411 sigma_t5=hypertc_kappa*dsqrt(block%wextra(ix^d,tcoff_)**5)
5412 sigma_t7=sigma_t5*block%wextra(ix^d,tcoff_)
5413 else
5414 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5415 sigma_t7=sigma_t5*te(ix^d)
5416 end if
5417 else
5418 sigma_t5=hypertc_kappa*dsqrt(te(ix^d)**5)
5419 sigma_t7=sigma_t5*te(ix^d)
5420 end if
5421 if(b0field) then
5422 ^d&bdir(^d)=wct({ix^d},mag(^d))+block%B0({ix^d},^d,0)\
5423 else
5424 ^d&bdir(^d)=wct({ix^d},mag(^d))\
5425 end if
5426 if(bdir(1)/=0.d0) then
5427 bunitvec(1)=sign(1.d0,bdir(1))/dsqrt(1.d0+(bdir(2)/bdir(1))**2+(bdir(3)/bdir(1))**2)
5428 else
5429 bunitvec(1)=0.d0
5430 end if
5431 if(bdir(2)/=0.d0) then
5432 bunitvec(2)=sign(1.d0,bdir(2))/dsqrt(1.d0+(bdir(1)/bdir(2))**2+(bdir(3)/bdir(2))**2)
5433 else
5434 bunitvec(2)=0.d0
5435 end if
5436 if(bdir(3)/=0.d0) then
5437 bunitvec(3)=sign(1.d0,bdir(3))/dsqrt(1.d0+(bdir(1)/bdir(3))**2+(bdir(2)/bdir(3))**2)
5438 else
5439 bunitvec(3)=0.d0
5440 end if
5441 sigmat5_bgradt=sigma_t5*(&
5442 bunitvec(1)*((8.d0*(te(ix1+1,ix2,ix3)-te(ix1-1,ix2,ix3))-te(ix1+2,ix2,ix3)+te(ix1-2,ix2,ix3))/12.d0)/block%ds(ix^d,1)&
5443 +bunitvec(2)*((8.d0*(te(ix1,ix2+1,ix3)-te(ix1,ix2-1,ix3))-te(ix1,ix2+2,ix3)+te(ix1,ix2-2,ix3))/12.d0)/block%ds(ix^d,2)&
5444 +bunitvec(3)*((8.d0*(te(ix1,ix2,ix3+1)-te(ix1,ix2,ix3-1))-te(ix1,ix2,ix3+2)+te(ix1,ix2,ix3-2))/12.d0)/block%ds(ix^d,3))
5445 inv_rho=1.d0/rho_loc(ix^d)
5446 c2=mhd_gamma*pth_loc(ix^d)*inv_rho
5447 cfast2=(^c&bdir(^c)**2+)*inv_rho+c2
5448 ^d&avmincs2(^d)=cfast2**2-4.0d0*c2*bdir(^d)**2*inv_rho\
5449 ! local fast wave speed in each dimension
5450 ^d&cmax(^d)=sqrt(half*(cfast2+sqrt(dabs(avmincs2(^d)))))\
5451 if(mhd_htc_sat) then
5452 ! 5 phi rho c^3, phi=0.3, c=sqrt(p/rho) isothermal sound speed
5453 f_sat=one/(one+dabs(sigmat5_bgradt)/(1.5d0*rho_loc(ix^d)*(pth_loc(ix^d)/rho_loc(ix^d))**1.5d0))
5454 tau=max(4.d0*dt, f_sat*sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5455 w(ix^d,q_)=w(ix^d,q_)-qdt*(f_sat*sigmat5_bgradt+wct(ix^d,q_))/tau
5456 else
5457 w(ix^d,q_)=w(ix^d,q_)-qdt*(sigmat5_bgradt+wct(ix^d,q_))/&
5458 max(4.d0*dt, sigma_t7*courantpar**2/(pth_loc(ix^d)*inv_gamma_1*maxval(cmax(:))**2))
5459 end if
5460 end do
5461 end do
5462 end do
5463 }
5464 end subroutine add_hypertc_source
5465
5466 !> Compute the Lorentz force (JxB) Note: Unused subroutine
5467 !> perhaps useful for post-processing when made public
5468 subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
5470 integer, intent(in) :: ixi^l, ixo^l
5471 double precision, intent(in) :: w(ixi^s,1:nw)
5472 double precision, intent(inout) :: jxb(ixi^s,3)
5473 double precision :: a(ixi^s,3), b(ixi^s,3)
5474 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5475 double precision :: current(ixi^s,7-2*ndir:3)
5476 integer :: idir, idirmin
5477
5478 b=0.0d0
5479 if(b0field) then
5480 do idir = 1, ndir
5481 b(ixo^s, idir) = w(ixo^s,mag(idir))+block%B0(ixo^s,idir,0)
5482 end do
5483 else
5484 do idir = 1, ndir
5485 b(ixo^s, idir) = w(ixo^s,mag(idir))
5486 end do
5487 end if
5488
5489 ! store J current in a
5490 call get_current(w,ixi^l,ixo^l,idirmin,current)
5491
5492 a=0.0d0
5493 do idir=7-2*ndir,3
5494 a(ixo^s,idir)=current(ixo^s,idir)
5495 end do
5496
5497 call cross_product(ixi^l,ixo^l,a,b,jxb)
5498 end subroutine get_lorentz_force
5499
5500 subroutine mhd_get_rho(w,x,ixI^L,ixO^L,rho)
5502 integer, intent(in) :: ixi^l, ixo^l
5503 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
5504 double precision, intent(out) :: rho(ixi^s)
5505
5506 if(has_equi_rho_and_p) then
5507 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
5508 else
5509 rho(ixo^s) = w(ixo^s,rho_)
5510 endif
5511
5512 end subroutine mhd_get_rho
5513
5514 !> handle small or negative internal energy
5515 subroutine mhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
5518 integer, intent(in) :: ixi^l,ixo^l, ie
5519 double precision, intent(inout) :: w(ixi^s,1:nw)
5520 double precision, intent(in) :: x(ixi^s,1:ndim)
5521 character(len=*), intent(in) :: subname
5522
5523 double precision :: rho(ixi^s)
5524 integer :: idir
5525 logical :: flag(ixi^s,1:nw)
5526
5527 flag=.false.
5528 if(has_equi_rho_and_p) then
5529 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1<small_e)&
5530 flag(ixo^s,ie)=.true.
5531 else
5532 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
5533 endif
5534 if(any(flag(ixo^s,ie))) then
5535 select case (small_values_method)
5536 case ("replace")
5537 if(has_equi_rho_and_p) then
5538 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
5539 block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
5540 else
5541 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
5542 endif
5543 case ("average")
5544 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
5545 case default
5546 ! small values error shows primitive variables
5547 w(ixo^s,e_)=w(ixo^s,e_)*gamma_1
5548 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
5549 do idir = 1, ndir
5550 w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
5551 end do
5552 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
5553 end select
5554 end if
5555
5556 end subroutine mhd_handle_small_ei
5557
5558 subroutine mhd_update_temperature(ixI^L,ixO^L,wCT,w,x)
5561
5562 integer, intent(in) :: ixi^l, ixo^l
5563 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5564 double precision, intent(inout) :: w(ixi^s,1:nw)
5565
5566 double precision :: iz_h(ixo^s),iz_he(ixo^s), pth(ixi^s)
5567
5568 call ionization_degree_from_temperature(ixi^l,ixo^l,wct(ixi^s,te_),iz_h,iz_he)
5569
5570 call mhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
5571
5572 w(ixo^s,te_)=(2.d0+3.d0*he_abundance)*pth(ixo^s)/(w(ixo^s,rho_)*(1.d0+iz_h(ixo^s)+&
5573 he_abundance*(iz_he(ixo^s)*(iz_he(ixo^s)+1.d0)+1.d0)))
5574
5575 end subroutine mhd_update_temperature
5576
5577 !> Source terms after split off time-independent magnetic field
5578 subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x,wCTprim)
5580
5581 integer, intent(in) :: ixi^l, ixo^l
5582 double precision, intent(in) :: qdt, dtfactor,wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5583 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5584 double precision, intent(inout) :: w(ixi^s,1:nw)
5585
5586 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
5587 integer :: idir
5588
5589 a=0.d0
5590 b=0.d0
5591 ! for force-free field J0xB0 =0
5592 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) then
5593 ! store B0 magnetic field in b
5594 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
5595
5596 ! store J0 current in a
5597 do idir=7-2*ndir,3
5598 a(ixo^s,idir)=block%J0(ixo^s,idir)
5599 end do
5600 call cross_product(ixi^l,ixo^l,a,b,axb)
5601 if(local_timestep) then
5602 do idir=1,3
5603 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5604 enddo
5605 else
5606 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5607 endif
5608 ! add J0xB0 source term in momentum equations
5609 w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
5610 end if
5611
5612 if(total_energy) then
5613 a=0.d0
5614 ! for free-free field -(vxB0) dot J0 =0
5615 b(ixo^s,:)=wctprim(ixo^s,mag(:))
5616 ! store full magnetic field B0+B1 in b
5617 if((.not.b0field_forcefree).and.(.not.has_equi_rho_and_p)) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
5618 ! store velocity in a
5619 a(ixi^s,1:ndir)=wctprim(ixi^s,mom(1:ndir))
5620 ! -E = a x b
5621 call cross_product(ixi^l,ixo^l,a,b,axb)
5622 if(local_timestep) then
5623 do idir=1,3
5624 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5625 enddo
5626 else
5627 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5628 endif
5629 ! add -(vxB) dot J0 source term in energy equation
5630 ! where it is adding -J0 dot (vxB_1) when appropriate
5631 do idir=7-2*ndir,3
5632 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
5633 end do
5634 if(mhd_hall) then
5635 ! store hall velocity in a, only partial current is needed
5636 call mhd_getv_hall(wct,x,ixi^l,ixo^l,a,.true.)
5637 ! -E = a x b
5638 call cross_product(ixi^l,ixo^l,a,b,axb)
5639 if(local_timestep) then
5640 do idir=1,3
5641 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
5642 enddo
5643 else
5644 axb(ixo^s,:)=axb(ixo^s,:)*qdt
5645 endif
5646 ! add -(vxB) dot J0 source term in energy equation
5647 do idir=7-2*ndir,3
5648 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
5649 end do
5650 endif
5651 if(mhd_ambipolar_sts) then
5652 ! in STS variant of ambipolar, we added for split B the term div(B_1xE_ambi)
5653 ! hence needs to add J_0 dot E_ambi
5654 ! to get finally the term etaA (J_perpB)^/B^2-B_1 dot (curl Eambi)
5655 !reuse axb
5656 call mhd_get_jxbxb(wct,x,ixi^l,ixo^l,axb)
5657 ! source J0 * E
5658 do idir=sdim,3
5659 !set electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
5660 call multiplyambicoef(ixi^l,ixo^l,axb(ixi^s,idir),wct,x)
5661 w(ixo^s,e_)=w(ixo^s,e_)+qdt*axb(ixo^s,idir)*block%J0(ixo^s,idir)
5662 enddo
5663 endif
5664 end if
5665
5666
5667 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
5668
5669 end subroutine add_source_b0split
5670
5671 !> Source terms for semirelativistic MHD Gombosi 2002 JCP 177, 176
5672 subroutine add_source_semirelativistic(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5674 use mod_geometry
5675
5676 integer, intent(in) :: ixi^l, ixo^l
5677 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5678 double precision, intent(inout) :: w(ixi^s,1:nw)
5679 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
5680
5681 double precision :: e(ixi^s,1:3),curle(ixi^s,1:3),dive(ixi^s)
5682 integer :: idir, idirmin, ix^d
5683
5684 ! if ndir<3 the source is zero
5685 {^ifthreec
5686 {do ix^db=iximin^db,iximax^db\}
5687 ! E=Bxv
5688 e(ix^d,1)=w(ix^d,b2_)*wctprim(ix^d,m3_)-w(ix^d,b3_)*wctprim(ix^d,m2_)
5689 e(ix^d,2)=w(ix^d,b3_)*wctprim(ix^d,m1_)-w(ix^d,b1_)*wctprim(ix^d,m3_)
5690 e(ix^d,3)=w(ix^d,b1_)*wctprim(ix^d,m2_)-w(ix^d,b2_)*wctprim(ix^d,m1_)
5691 {end do\}
5692 call divvector(e,ixi^l,ixo^l,dive)
5693 ! curl E
5694 call curlvector(e,ixi^l,ixo^l,curle,idirmin,1,3)
5695 ! add source term in momentum equations (1/c0^2-1/c^2)(E divE - E x curlE)
5696 ! equation (26) and (27)
5697 {do ix^db=ixomin^db,ixomax^db\}
5698 w(ix^d,m1_)=w(ix^d,m1_)+qdt*(inv_squared_c0-inv_squared_c)*&
5699 (e(ix^d,1)*dive(ix^d)-e(ix^d,2)*curle(ix^d,3)+e(ix^d,3)*curle(ix^d,2))
5700 w(ix^d,m2_)=w(ix^d,m2_)+qdt*(inv_squared_c0-inv_squared_c)*&
5701 (e(ix^d,2)*dive(ix^d)-e(ix^d,3)*curle(ix^d,1)+e(ix^d,1)*curle(ix^d,3))
5702 w(ix^d,m3_)=w(ix^d,m3_)+qdt*(inv_squared_c0-inv_squared_c)*&
5703 (e(ix^d,3)*dive(ix^d)-e(ix^d,1)*curle(ix^d,2)+e(ix^d,2)*curle(ix^d,1) )
5704 {end do\}
5705 }
5706
5707 end subroutine add_source_semirelativistic
5708
5709 !> Source terms for internal energy version of MHD
5710 subroutine add_source_internal_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5712 use mod_geometry
5713
5714 integer, intent(in) :: ixi^l, ixo^l
5715 double precision, intent(in) :: qdt
5716 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5717 double precision, intent(inout) :: w(ixi^s,1:nw)
5718 double precision, intent(in) :: wctprim(ixi^s,1:nw)
5719
5720 double precision :: divv(ixi^s), tmp
5721 integer :: ix^d
5722
5723 if(slab_uniform) then
5724 if(nghostcells .gt. 2) then
5725 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,3)
5726 else
5727 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv,2)
5728 end if
5729 else
5730 call divvector(wctprim(ixi^s,mom(:)),ixi^l,ixo^l,divv)
5731 end if
5732 {do ix^db=ixomin^db,ixomax^db\}
5733 tmp=w(ix^d,e_)
5734 w(ix^d,e_)=w(ix^d,e_)-qdt*wctprim(ix^d,p_)*divv(ix^d)
5735 if(w(ix^d,e_)<small_e) then
5736 w(ix^d,e_)=tmp
5737 end if
5738 {end do\}
5739 if(mhd_ambipolar_sts)then
5740 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
5741 end if
5742
5743 if(fix_small_values) then
5744 call mhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,'add_source_internal_e')
5745 end if
5746 end subroutine add_source_internal_e
5747
5748 !> Source terms for hydrodynamic energy version of MHD
5749 subroutine add_source_hydrodynamic_e(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
5751 use mod_geometry
5752 use mod_usr_methods, only: usr_gravity
5753
5754 integer, intent(in) :: ixi^l, ixo^l
5755 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5756 double precision, intent(inout) :: w(ixi^s,1:nw)
5757 double precision, intent(in), optional :: wctprim(ixi^s,1:nw)
5758
5759 double precision :: b(ixi^s,3), j(ixi^s,3), jxb(ixi^s,3)
5760 double precision :: current(ixi^s,7-2*ndir:3)
5761 double precision :: bu(ixo^s,1:ndir), tmp(ixo^s), b2(ixo^s)
5762 double precision :: gravity_field(ixi^s,1:ndir), vaoc
5763 integer :: idir, idirmin, idims, ix^d
5764
5765 {^nothreed
5766 b=0.0d0
5767 do idir = 1, ndir
5768 b(ixo^s, idir) = wct(ixo^s,mag(idir))
5769 end do
5770
5771 if(slab_uniform)then
5772 ! get current in fourth order accuracy in Cartesian
5773 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
5774 else
5775 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5776 endif
5777
5778 j=0.0d0
5779 do idir=7-2*ndir,3
5780 j(ixo^s,idir)=current(ixo^s,idir)
5781 end do
5782
5783 ! get Lorentz force JxB
5784 call cross_product(ixi^l,ixo^l,j,b,jxb)
5785 }
5786 {^ifthreed
5787 if(slab_uniform)then
5788 ! get current in fourth order accuracy in Cartesian
5789 call curlvector(wct(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,1,ndir,.true.)
5790 else
5791 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5792 endif
5793 ! get Lorentz force JxB
5794 call cross_product(ixi^l,ixo^l,current,wct(ixi^s,mag(1:ndir)),jxb)
5795 }
5796
5797 ! mhd_semirelativistic does not combine with mhd_hydrodynamic_e
5798 !!if(mhd_semirelativistic) then
5799 !! ! (v . nabla) v
5800 !! do idir=1,ndir
5801 !! do idims=1,ndim
5802 !! call gradient(wCTprim(ixI^S,mom(idir)),ixI^L,ixO^L,idims,J(ixI^S,idims))
5803 !! end do
5804 !! B(ixO^S,idir)=sum(wCTprim(ixO^S,mom(1:ndir))*J(ixO^S,1:ndir),dim=ndim+1)
5805 !! end do
5806 !! ! nabla p
5807 !! do idir=1,ndir
5808 !! call gradient(wCTprim(ixI^S,p_),ixI^L,ixO^L,idir,J(ixI^S,idir))
5809 !! end do
5810 !! if(mhd_gravity) then
5811 !! gravity_field=0.d0
5812 !! call usr_gravity(ixI^L,ixO^L,wCT,x,gravity_field(ixI^S,1:ndim))
5813 !! do idir=1,ndir
5814 !! 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)
5815 !! end do
5816 !! else
5817 !! do idir=1,ndir
5818 !! B(ixO^S,idir)=wCT(ixO^S,rho_)*B(ixO^S,idir)+J(ixO^S,idir)-JxB(ixO^S,idir)
5819 !! end do
5820 !! end if
5821 !! b2(ixO^S)=sum(wCT(ixO^S,mag(:))**2,dim=ndim+1)
5822 !! tmp(ixO^S)=sqrt(b2(ixO^S))
5823 !! where(tmp(ixO^S)>smalldouble)
5824 !! tmp(ixO^S)=1.d0/tmp(ixO^S)
5825 !! else where
5826 !! tmp(ixO^S)=0.d0
5827 !! end where
5828 !! ! unit vector of magnetic field
5829 !! do idir=1,ndir
5830 !! bu(ixO^S,idir)=wCT(ixO^S,mag(idir))*tmp(ixO^S)
5831 !! end do
5832 !! !b2(ixO^S)=b2(ixO^S)/w(ixO^S,rho_)*inv_squared_c
5833 !! !b2(ixO^S)=b2(ixO^S)/(1.d0+b2(ixO^S))
5834 !! {do ix^DB=ixOmin^DB,ixOmax^DB\}
5835 !! ! Va^2/c^2
5836 !! Vaoc=b2(ix^D)/w(ix^D,rho_)*inv_squared_c
5837 !! ! Va^2/c^2 / (1+Va^2/c^2)
5838 !! b2(ix^D)=Vaoc/(1.d0+Vaoc)
5839 !! {end do\}
5840 !! ! bu . F
5841 !! tmp(ixO^S)=sum(bu(ixO^S,1:ndir)*B(ixO^S,1:ndir),dim=ndim+1)
5842 !! ! Rempel 2017 ApJ 834, 10 equation (54)
5843 !! do idir=1,ndir
5844 !! J(ixO^S,idir)=b2(ixO^S)*(B(ixO^S,idir)-bu(ixO^S,idir)*tmp(ixO^S))
5845 !! end do
5846 !! !! Rempel 2017 ApJ 834, 10 equation (29) add SR force at momentum equation
5847 !! do idir=1,ndir
5848 !! w(ixO^S,mom(idir))=w(ixO^S,mom(idir))+qdt*J(ixO^S,idir)
5849 !! end do
5850 !! ! Rempel 2017 ApJ 834, 10 equation (30) add work of Lorentz force and SR force
5851 !! w(ixO^S,e_)=w(ixO^S,e_)+qdt*sum(wCTprim(ixO^S,mom(1:ndir))*&
5852 !! (JxB(ixO^S,1:ndir)+J(ixO^S,1:ndir)),dim=ndim+1)
5853 !!else
5854 ! add work of Lorentz force
5855 w(ixo^s,e_)=w(ixo^s,e_)+qdt*sum(wctprim(ixo^s,mom(1:ndir))*jxb(ixo^s,1:ndir),dim=ndim+1)
5856 !!end if
5857
5858 if(mhd_ambipolar_sts)then
5859 call add_source_ambipolar_internal_energy(qdt,ixi^l,ixo^l,wct,w,x)
5860 end if
5861
5862 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hydrodynamic_e')
5863
5864 end subroutine add_source_hydrodynamic_e
5865
5866 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
5867 !> each direction, non-conservative. Uses the generic Laplacian
5868 !> with fourth order central difference (on uniform cartesian) for the laplacian. Then the
5869 !> stencil is 5 (2 neighbours). NOTE: Unused subroutine!
5870 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
5872 use mod_usr_methods
5873 use mod_geometry
5874
5875 integer, intent(in) :: ixi^l, ixo^l
5876 double precision, intent(in) :: qdt
5877 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5878 double precision, intent(inout) :: w(ixi^s,1:nw)
5879
5880 integer :: ixa^l,idir,jdir,kdir,idirmin,idim
5881 double precision :: tmp(ixi^s),tmp2(ixi^s)
5882
5883 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5884 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
5885 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
5886 double precision :: lapl_vec(ixi^s,1:ndir)
5887
5888 ! Calculating resistive sources involves one extra layer
5889 ! asking here for two, so Cartesian works with 4th order CD
5890 ixa^l=ixo^l^ladd2;
5891
5892 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5893 call mpistop("Error in add_source_res1: Non-conforming input limits")
5894
5895 ! Calculate current density and idirmin
5896 call get_current(wct,ixi^l,ixo^l,idirmin,current)
5897
5898 if (mhd_eta>zero)then
5899 eta(ixa^s)=mhd_eta
5900 gradeta(ixo^s,1:ndim)=zero
5901 else
5902 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
5903 do idim=1,ndim
5904 call gradient(eta,ixi^l,ixo^l,idim,tmp)
5905 gradeta(ixo^s,idim)=tmp(ixo^s)
5906 end do
5907 end if
5908
5909 if(b0field) then
5910 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
5911 else
5912 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
5913 end if
5914
5915 call laplacian_of_vector(bf,ixi^l,ixo^l,lapl_vec)
5916
5917 do idir=1,ndir
5918 ! Multiply by eta to store eta*Laplace B_idir
5919 tmp(ixo^s)=lapl_vec(ixo^s,idir)*eta(ixo^s)
5920
5921 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
5922 if (mhd_eta<zero)then
5923 do jdir=1,ndim; do kdir=idirmin,3
5924 if (lvc(idir,jdir,kdir)/=0)then
5925 if (lvc(idir,jdir,kdir)==1)then
5926 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
5927 else
5928 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
5929 end if
5930 end if
5931 end do; end do
5932 end if
5933
5934 ! Add sources related to eta*laplB-grad(eta) x J to B and e
5935 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
5936 if(total_energy) then
5937 w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
5938 end if
5939 end do ! idir
5940
5941 if(mhd_energy) then
5942 ! de/dt+=eta*J**2
5943 w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
5944 end if
5945
5946 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
5947
5948 end subroutine add_source_res1
5949
5950 !> Add resistive source to w within ixO in an explicit fashion
5951 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
5952 subroutine add_source_res_exp(qdt,ixI^L,ixO^L,wCT,w,x)
5954 use mod_usr_methods
5955 use mod_geometry
5956
5957 integer, intent(in) :: ixi^l, ixo^l
5958 double precision, intent(in) :: qdt
5959 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
5960 double precision, intent(inout) :: w(ixi^s,1:nw)
5961
5962 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
5963 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
5964 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
5965 integer :: ixa^l,idir,idirmin,idirmin1
5966
5967 ixa^l=ixo^l^ladd2;
5968
5969 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
5970 call mpistop("Error in add_source_res_exp: Non-conforming input limits")
5971
5972 ixa^l=ixo^l^ladd1;
5973 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
5974 ! Determine exact value of idirmin while doing the loop.
5975 call get_current(wct,ixi^l,ixa^l,idirmin,current)
5976
5977 tmpvec=zero
5978 if(mhd_eta>zero)then
5979 do idir=idirmin,3
5980 tmpvec(ixa^s,idir)=current(ixa^s,idir)*mhd_eta
5981 end do
5982 else
5983 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
5984 do idir=idirmin,3
5985 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
5986 end do
5987 end if
5988
5989 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
5990 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
5991 if(stagger_grid) then
5992 if(ndim==2.and.ndir==3) then
5993 ! if 2.5D
5994 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
5995 end if
5996 else
5997 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
5998 end if
5999
6000 if(mhd_energy) then
6001 if(mhd_eta>zero)then
6002 tmp(ixo^s)=qdt*mhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
6003 else
6004 tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
6005 end if
6006 if(total_energy) then
6007 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
6008 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6009 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6010 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6011 else
6012 ! add eta*J**2 source term in the internal energy equation
6013 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6014 end if
6015 end if
6016
6017 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res_exp')
6018 end subroutine add_source_res_exp
6019
6020
6021 !> Add ambipolar source to w within ixO in an explicit fashion
6022 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
6023 subroutine add_source_ambi_exp(qdt,ixI^L,ixO^L,wCT,w,x)
6025 use mod_usr_methods
6026 use mod_geometry
6027
6028 integer, intent(in) :: ixi^l, ixo^l
6029 double precision, intent(in) :: qdt
6030 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6031 double precision, intent(inout) :: w(ixi^s,1:nw)
6032
6033 double precision :: current(ixi^s,1:3),curlj(ixi^s,1:3)
6034 double precision :: tmpvec(ixi^s,1:3),tmp(ixi^s),btot2(ixi^s)
6035 integer :: ixa^l,idir,idirmin1
6036
6037 ixa^l=ixo^l^ladd2;
6038
6039 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6040 call mpistop("Error in add_source_ambi_exp: Non-conforming input limits")
6041
6042 ixa^l=ixo^l^ladd1;
6043 ! Calculate -J_perpB = (JxB)xB
6044 call mhd_get_jxbxb(wct,x,ixi^l,ixa^l,current)
6045
6046 tmpvec=current
6047 do idir=1,3
6048 !set electric field in tmpvec : E=nuA * jxbxb, where nuA=-etaA/rho^2
6049 !tmpvec(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
6050 call multiplyambicoef(ixi^l,ixa^l,tmpvec(ixi^s,idir),wct,x)
6051 end do
6052
6053 ! dB/dt= -curl(J_perpB*etaA), thus B_i=B_i-eps_ijk d_j Jeta_k
6054 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
6055 if(stagger_grid) then
6056 if(ndim==2.and.ndir==3) then
6057 ! if 2.5D
6058 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
6059 end if
6060 else
6061 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
6062 end if
6063
6064 if(mhd_energy) then
6065 ! compute ambipolar heating term: nuA* J_perpB^2/ B^2
6066 ! avoiding nulls here
6067 btot2(ixa^s)=mhd_mag_en_all(wct,ixi^l,ixa^l)
6068 where (btot2(ixa^s)>smalldouble )
6069 tmp(ixa^s) = sum(current(ixa^s,1:3)**2,dim=ndim+1) / btot2(ixa^s)
6070 elsewhere
6071 tmp(ixa^s) = zero
6072 endwhere
6073 ! multiply with nuA where nuA=-etaA/rho^2
6074 call multiplyambicoef(ixi^l,ixa^l,tmp,wct,x)
6075 ! compensate - sign and add timestep
6076 tmp(ixo^s)=-qdt*tmp(ixo^s)
6077 if(total_energy) then
6078 ! de/dt= +div(B x E_ambi) = eta J^2 - B dot curl(eta J)
6079 ! de1/dt= eta J^2 - B1 dot curl(eta J)
6080 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
6081 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
6082 else
6083 ! add eta*J**2 source term in the internal or hydrodynamic energy equation
6084 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
6085 end if
6086 end if
6087
6088 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_ambi_exp')
6089 end subroutine add_source_ambi_exp
6090
6091 !> Add Hyper-resistive source to w within ixO
6092 !> Uses 9 point stencil (4 neighbours) in each direction.
6093 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
6095 use mod_geometry
6096
6097 integer, intent(in) :: ixi^l, ixo^l
6098 double precision, intent(in) :: qdt
6099 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6100 double precision, intent(inout) :: w(ixi^s,1:nw)
6101 !.. local ..
6102 double precision :: current(ixi^s,7-2*ndir:3)
6103 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
6104 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
6105
6106 ixa^l=ixo^l^ladd3;
6107 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
6108 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
6109
6110 call get_current(wct,ixi^l,ixa^l,idirmin,current)
6111 tmpvec(ixa^s,1:ndir)=zero
6112 do jdir=idirmin,3
6113 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
6114 end do
6115
6116 ixa^l=ixo^l^ladd2;
6117 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6118
6119 ixa^l=ixo^l^ladd1;
6120 tmpvec(ixa^s,1:ndir)=zero
6121 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
6122 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mhd_eta_hyper
6123
6124 ixa^l=ixo^l;
6125 tmpvec2(ixa^s,1:ndir)=zero
6126 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
6127
6128 do idir=1,ndir
6129 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
6130 end do
6131
6132 if(total_energy) then
6133 ! de/dt= +div(B x Ehyper)
6134 ixa^l=ixo^l^ladd1;
6135 tmpvec2(ixa^s,1:ndir)=zero
6136 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
6137 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
6138 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
6139 end do; end do; end do
6140 tmp(ixo^s)=zero
6141 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
6142 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
6143 end if
6144
6145 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
6146
6147 end subroutine add_source_hyperres
6148
6149 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
6150 ! Add divB related sources to w within ixO
6151 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
6152 ! giving the EGLM-MHD scheme or GLM-MHD scheme
6154 use mod_geometry
6155
6156 integer, intent(in) :: ixi^l, ixo^l
6157 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6158 double precision, intent(inout) :: w(ixi^s,1:nw)
6159
6160 double precision:: divb(ixi^s), gradpsi(ixi^s), ba(ixo^s,1:ndir)
6161 integer :: idir
6162
6163
6164 ! dPsi/dt = - Ch^2/Cp^2 Psi
6165 if (mhd_glm_alpha < zero) then
6166 w(ixo^s,psi_) = abs(mhd_glm_alpha)*wct(ixo^s,psi_)
6167 else
6168 ! implicit update of Psi variable
6169 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
6170 if(slab_uniform) then
6171 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
6172 else
6173 w(ixo^s,psi_) = dexp(-qdt*cmax_global*mhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
6174 end if
6175 end if
6176
6177 if(mhd_glm_extended) then
6178 if(b0field) then
6179 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
6180 else
6181 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))
6182 end if
6183 ! gradient of Psi
6184 if(total_energy) then
6185 do idir=1,ndim
6186 select case(typegrad)
6187 case("central")
6188 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6189 case("limited")
6190 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
6191 end select
6192 ! e = e -qdt (b . grad(Psi))
6193 w(ixo^s,e_) = w(ixo^s,e_)-qdt*ba(ixo^s,idir)*gradpsi(ixo^s)
6194 end do
6195 end if
6196
6197 ! We calculate now div B
6198 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6199
6200 ! m = m - qdt b div b
6201 do idir=1,ndir
6202 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*ba(ixo^s,idir)*divb(ixo^s)
6203 end do
6204 end if
6205
6206 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
6207
6208 end subroutine add_source_glm
6209
6210 !> Add divB related sources to w within ixO corresponding to Powel
6211 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
6213
6214 integer, intent(in) :: ixi^l, ixo^l
6215 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6216 double precision, intent(inout) :: w(ixi^s,1:nw)
6217
6218 double precision :: divb(ixi^s), ba(1:ndir)
6219 integer :: idir, ix^d
6220
6221 ! calculate div B
6222 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6223
6224 if(b0field) then
6225 {do ix^db=ixomin^db,ixomax^db\}
6226 ! b = b - qdt v * div b
6227 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6228 ! m = m - qdt b div b
6229 ^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)\
6230 if (total_energy) then
6231 ! e = e - qdt (v . b) * div b
6232 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)
6233 end if
6234 {end do\}
6235 else
6236 {do ix^db=ixomin^db,ixomax^db\}
6237 ! b = b - qdt v * div b
6238 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6239 ! m = m - qdt b div b
6240 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)-qdt*wct(ix^d,b^c_)*divb(ix^d)\
6241 if (total_energy) then
6242 ! e = e - qdt (v . b) * div b
6243 w(ix^d,e_)=w(ix^d,e_)-qdt*(^c&wct(ix^d,m^c_)*wct(ix^d,b^c_)+)*divb(ix^d)
6244 end if
6245 {end do\}
6246 end if
6247
6248 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
6249
6250 end subroutine add_source_powel
6251
6252 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
6253 ! Add divB related sources to w within ixO
6254 ! corresponding to Janhunen, just the term in the induction equation.
6256
6257 integer, intent(in) :: ixi^l, ixo^l
6258 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6259 double precision, intent(inout) :: w(ixi^s,1:nw)
6260
6261 double precision :: divb(ixi^s)
6262 integer :: idir, ix^d
6263
6264 ! calculate div B
6265 call get_divb(wct,ixi^l,ixo^l,divb, mhd_divb_nth)
6266
6267 {do ix^db=ixomin^db,ixomax^db\}
6268 ! b = b - qdt v * div b
6269 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
6270 {end do\}
6271
6272 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
6273
6274 end subroutine add_source_janhunen
6275
6276 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
6277 ! Add Linde's divB related sources to wnew within ixO
6279 use mod_geometry
6280
6281 integer, intent(in) :: ixi^l, ixo^l
6282 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
6283 double precision, intent(inout) :: w(ixi^s,1:nw)
6284
6285 double precision :: divb(ixi^s),graddivb(ixi^s)
6286 integer :: idim, idir, ixp^l, i^d, iside
6287 logical, dimension(-1:1^D&) :: leveljump
6288
6289 ! Calculate div B
6290 ixp^l=ixo^l^ladd1;
6291 call get_divb(wct,ixi^l,ixp^l,divb, mhd_divb_nth)
6292
6293 ! for AMR stability, retreat one cell layer from the boarders of level jump
6294 {do i^db=-1,1\}
6295 if(i^d==0|.and.) cycle
6296 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
6297 leveljump(i^d)=.true.
6298 else
6299 leveljump(i^d)=.false.
6300 end if
6301 {end do\}
6302
6303 ixp^l=ixo^l;
6304 do idim=1,ndim
6305 select case(idim)
6306 {case(^d)
6307 do iside=1,2
6308 i^dd=kr(^dd,^d)*(2*iside-3);
6309 if (leveljump(i^dd)) then
6310 if (iside==1) then
6311 ixpmin^d=ixomin^d-i^d
6312 else
6313 ixpmax^d=ixomax^d-i^d
6314 end if
6315 end if
6316 end do
6317 \}
6318 end select
6319 end do
6320
6321 ! Add Linde's diffusive terms
6322 do idim=1,ndim
6323 ! Calculate grad_idim(divb)
6324 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
6325
6326 {do i^db=ixpmin^db,ixpmax^db\}
6327 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
6328 graddivb(i^d)=graddivb(i^d)*divbdiff/(^d&1.0d0/block%ds({i^d},^d)**2+)
6329
6330 w(i^d,mag(idim))=w(i^d,mag(idim))+graddivb(i^d)
6331
6332 if (typedivbdiff=='all' .and. total_energy) then
6333 ! e += B_idim*eta*grad_idim(divb)
6334 w(i^d,e_)=w(i^d,e_)+wct(i^d,mag(idim))*graddivb(i^d)
6335 end if
6336 {end do\}
6337 end do
6338
6339 if (fix_small_values) call mhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
6340
6341 end subroutine add_source_linde
6342
6343 !> get dimensionless div B = |divB| * volume / area / |B|
6344 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
6345
6347
6348 integer, intent(in) :: ixi^l, ixo^l
6349 double precision, intent(in) :: w(ixi^s,1:nw)
6350 double precision :: divb(ixi^s), dsurface(ixi^s)
6351
6352 double precision :: invb(ixo^s)
6353 integer :: ixa^l,idims
6354
6355 call get_divb(w,ixi^l,ixo^l,divb)
6356 invb(ixo^s)=sqrt(mhd_mag_en_all(w,ixi^l,ixo^l))
6357 where(invb(ixo^s)/=0.d0)
6358 invb(ixo^s)=1.d0/invb(ixo^s)
6359 end where
6360 if(slab_uniform) then
6361 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
6362 else
6363 ixamin^d=ixomin^d-1;
6364 ixamax^d=ixomax^d-1;
6365 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
6366 do idims=1,ndim
6367 ixa^l=ixo^l-kr(idims,^d);
6368 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
6369 end do
6370 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
6371 block%dvolume(ixo^s)/dsurface(ixo^s)
6372 end if
6373
6374 end subroutine get_normalized_divb
6375
6376 !> Calculate idirmin and the idirmin:3 components of the common current array
6377 !> make sure that dxlevel(^D) is set correctly.
6378 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
6380 use mod_geometry
6381
6382 integer, intent(in) :: ixo^l, ixi^l
6383 double precision, intent(in) :: w(ixi^s,1:nw)
6384 integer, intent(out) :: idirmin
6385
6386 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
6387 double precision :: current(ixi^s,7-2*ndir:3)
6388 integer :: idir, idirmin0
6389
6390 idirmin0 = 7-2*ndir
6391
6392 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
6393
6394 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
6395 block%J0(ixo^s,idirmin0:3)
6396 end subroutine get_current
6397
6398 !> If resistivity is not zero, check diffusion time limit for dt and similar other effects
6399 subroutine mhd_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
6401 use mod_usr_methods
6403 use mod_gravity, only: gravity_get_dt
6404 use mod_cak_force, only: cak_get_dt
6405 use mod_fld, only: fld_radforce_get_dt
6406
6407 integer, intent(in) :: ixi^l, ixo^l
6408 double precision, intent(inout) :: dtnew
6409 double precision, intent(in) :: dx^d
6410 double precision, intent(in) :: wprim(ixi^s,1:nw)
6411 double precision, intent(in) :: x(ixi^s,1:ndim)
6412
6413 double precision :: dxarr(ndim)
6414 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
6415 integer :: idirmin,idim
6416
6417 dtnew = bigdouble
6418
6419 ^d&dxarr(^d)=dx^d;
6420 if (mhd_eta>zero)then
6421 if(slab_uniform) then
6422 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mhd_eta
6423 else
6424 dtnew=dtdiffpar*minval(block%ds(ixo^s,1:ndim))**2/mhd_eta
6425 end if
6426 else if (mhd_eta<zero)then
6427 call get_current(wprim,ixi^l,ixo^l,idirmin,current)
6428 call usr_special_resistivity(wprim,ixi^l,ixo^l,idirmin,x,current,eta)
6429 dtnew=bigdouble
6430 do idim=1,ndim
6431 if(slab_uniform) then
6432 dtnew=min(dtnew,&
6433 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
6434 else
6435 dtnew=min(dtnew,&
6436 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
6437 end if
6438 end do
6439 end if
6440
6441 if(mhd_eta_hyper>zero) then
6442 if(slab_uniform) then
6443 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mhd_eta_hyper,dtnew)
6444 else
6445 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mhd_eta_hyper,dtnew)
6446 end if
6447 end if
6448
6449 if(mhd_viscosity) then
6450 call viscosity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6451 end if
6452
6453 if(mhd_gravity) then
6454 call gravity_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6455 end if
6456
6457 if(mhd_ambipolar_exp) then
6458 dtnew=min(dtdiffpar*get_ambipolar_dt(wprim,ixi^l,ixo^l,dx^d,x),dtnew)
6459 endif
6460
6461 if (mhd_cak_force) then
6462 call cak_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6463 end if
6464
6465 if(mhd_radiation_fld) then
6466 call fld_radforce_get_dt(wprim,ixi^l,ixo^l,dtnew,dx^d,x)
6467 endif
6468
6469 end subroutine mhd_get_dt
6470
6471 ! Add geometrical source terms to w
6472 ! Geometric sources to momentum and induction
6473 ! for the regular case, not semi-relativistic, nor any splitting active
6474 ! but possibly no energy equation at all
6475 ! NOTE: Hall terms in induction not handled yet
6476 subroutine mhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6478 use mod_geometry
6481
6482 integer, intent(in) :: ixi^l, ixo^l
6483 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6484 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6485
6486 double precision :: adiabs(ixi^s), gammas(ixi^s)
6487 double precision :: tmp,tmp1,invr,cot
6488 integer :: ix^d
6489 integer :: mr_,mphi_ ! Polar var. names
6490 integer :: br_,bphi_
6491
6492 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6493 br_=mag(1); bphi_=mag(1)-1+phi_
6494
6495 if(.not.mhd_energy) then
6496 if(associated(usr_set_adiab)) then
6497 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6498 else
6499 adiabs=mhd_adiab
6500 end if
6501 if(associated(usr_set_gamma)) then
6502 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6503 else
6504 gammas=mhd_gamma
6505 end if
6506 end if
6507
6508 select case (coordinate)
6509 case (cylindrical)
6510 {do ix^db=ixomin^db,ixomax^db\}
6511 ! include dt in invr, invr is always used with qdt
6512 if(local_timestep) then
6513 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6514 else
6515 invr=qdt/x(ix^d,1)
6516 end if
6517 if(mhd_energy) then
6518 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6519 else
6520 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6521 end if
6522 if(phi_>0) then
6523 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6524 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6525 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6526 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6527 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6528 if(.not.stagger_grid) then
6529 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6530 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6531 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6532 end if
6533 else
6534 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6535 end if
6536 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6537 {end do\}
6538 case (spherical)
6539 {do ix^db=ixomin^db,ixomax^db\}
6540 ! include dt in invr, invr is always used with qdt
6541 if(local_timestep) then
6542 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6543 else
6544 invr=qdt/x(ix^d,1)
6545 end if
6546 if(mhd_energy) then
6547 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6548 else
6549 tmp1=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)+half*(^c&wprim(ix^d,b^c_)**2+)
6550 end if
6551 ! m1
6552 {^ifonec
6553 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6554 }
6555 {^noonec
6556 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6557 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6558 }
6559 ! b1
6560 if(mhd_glm) then
6561 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6562 end if
6563 {^ifoned
6564 cot=0.d0
6565 }
6566 {^nooned
6567 cot=1.d0/tan(x(ix^d,2))
6568 }
6569 {^iftwoc
6570 ! m2
6571 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6572 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6573 ! b2
6574 if(.not.stagger_grid) then
6575 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6576 if(mhd_glm) then
6577 tmp=tmp+wprim(ix^d,psi_)*cot
6578 end if
6579 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6580 end if
6581 }
6582 {^ifthreec
6583 ! m2
6584 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6585 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
6586 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
6587 ! b2
6588 if(.not.stagger_grid) then
6589 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6590 if(mhd_glm) then
6591 tmp=tmp+wprim(ix^d,psi_)*cot
6592 end if
6593 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6594 end if
6595 ! m3
6596 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6597 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6598 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6599 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6600 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
6601 ! b3
6602 if(.not.stagger_grid) then
6603 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6604 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6605 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6606 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6607 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6608 end if
6609 }
6610 {end do\}
6611 end select
6612
6613 if (mhd_rotating_frame) then
6614 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6615 end if
6616
6617 end subroutine mhd_add_source_geom
6618
6619 ! Add geometrical source terms to w
6620 ! Geometric sources to momentum and induction
6621 ! for the semi-relativistic, hence no splitting active
6622 ! but possibly no energy equation at all
6623 ! NOTE: Hall terms in induction not handled yet
6624 subroutine mhd_add_source_geom_semirelati(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6626 use mod_geometry
6629
6630 integer, intent(in) :: ixi^l, ixo^l
6631 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6632 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6633
6634 double precision :: adiabs(ixi^s), gammas(ixi^s)
6635 double precision :: tmp,tmp1,tmp2,invr,cot,ef(ixo^s,1:ndir)
6636 integer :: ix^d
6637 integer :: mr_,mphi_ ! Polar var. names
6638 integer :: br_,bphi_
6639
6640 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6641 br_=mag(1); bphi_=mag(1)-1+phi_
6642
6643 if(.not.mhd_energy) then
6644 if(associated(usr_set_adiab)) then
6645 call usr_set_adiab(w,x,ixi^l,ixo^l,adiabs)
6646 else
6647 adiabs=mhd_adiab
6648 end if
6649 if(associated(usr_set_gamma)) then
6650 call usr_set_gamma(w,x,ixi^l,ixo^l,gammas)
6651 else
6652 gammas=mhd_gamma
6653 end if
6654 end if
6655
6656 select case (coordinate)
6657 case (cylindrical)
6658 {do ix^db=ixomin^db,ixomax^db\}
6659 ! include dt in invr, invr is always used with qdt
6660 if(local_timestep) then
6661 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6662 else
6663 invr=qdt/x(ix^d,1)
6664 end if
6665 if(mhd_energy) then
6666 tmp=wprim(ix^d,p_)
6667 else
6668 tmp=adiabs(ix^d)*wprim(ix^d,rho_)**gammas(ix^d)
6669 end if
6670 ! E=Bxv
6671 {^ifthreec
6672 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
6673 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
6674 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6675 }
6676 {^iftwoc
6677 ef(ix^d,1)=zero
6678 ! store e3 in e2 to count e3 when ^C is from 1 to 2
6679 ef(ix^d,2)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6680 }
6681 {^ifonec
6682 ef(ix^d,1)=zero
6683 }
6684 if(phi_>0) then
6685 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+&
6686 half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c) -&
6687 wprim(ix^d,bphi_)**2+wprim(ix^d,rho_)*wprim(ix^d,mphi_)**2)
6688 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6689 -wprim(ix^d,rho_)*wprim(ix^d,mphi_)*wprim(ix^d,mr_) &
6690 +wprim(ix^d,bphi_)*wprim(ix^d,br_)+ef(ix^d,phi_)*ef(ix^d,1)*inv_squared_c)
6691 if(.not.stagger_grid) then
6692 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6693 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6694 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6695 end if
6696 else
6697 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp+half*((^c&wprim(ix^d,b^c_)**2+)+&
6698 (^c&ef(ix^d,^c)**2+)*inv_squared_c))
6699 end if
6700 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6701 {end do\}
6702 case (spherical)
6703 {do ix^db=ixomin^db,ixomax^db\}
6704 ! include dt in invr, invr is always used with qdt
6705 if(local_timestep) then
6706 invr=block%dt(ix^d)*dtfactor/x(ix^d,1)
6707 else
6708 invr=qdt/x(ix^d,1)
6709 end if
6710 ! E=Bxv
6711 {^ifthreec
6712 ef(ix^d,1)=wprim(ix^d,b2_)*wprim(ix^d,m3_)-wprim(ix^d,b3_)*wprim(ix^d,m2_)
6713 ef(ix^d,2)=wprim(ix^d,b3_)*wprim(ix^d,m1_)-wprim(ix^d,b1_)*wprim(ix^d,m3_)
6714 ef(ix^d,3)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6715 }
6716 {^iftwoc
6717 ! store e3 in e1 to count e3 when ^C is from 1 to 2
6718 ef(ix^d,1)=wprim(ix^d,b1_)*wprim(ix^d,m2_)-wprim(ix^d,b2_)*wprim(ix^d,m1_)
6719 ef(ix^d,2)=zero
6720 }
6721 {^ifonec
6722 ef(ix^d,1)=zero
6723 }
6724 if(mhd_energy) then
6725 tmp1=wprim(ix^d,p_)+half*((^c&wprim(ix^d,b^c_)**2+)+(^c&ef(ix^d,^c)**2+)*inv_squared_c)
6726 else
6727 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)
6728 end if
6729 ! m1
6730 {^ifonec
6731 w(ix^d,m1_)=w(ix^d,m1_)+two*tmp1*invr
6732 }
6733 {^noonec
6734 w(ix^d,m1_)=w(ix^d,m1_)+invr*&
6735 (two*tmp1+(^ce&wprim(ix^d,rho_)*wprim(ix^d,m^ce_)**2-&
6736 wprim(ix^d,b^ce_)**2-ef(ix^d,^ce)**2*inv_squared_c+))
6737 }
6738 ! b1
6739 if(mhd_glm) then
6740 w(ix^d,b1_)=w(ix^d,b1_)+invr*2.0d0*wprim(ix^d,psi_)
6741 end if
6742 {^ifoned
6743 cot=0.d0
6744 }
6745 {^nooned
6746 cot=1.d0/tan(x(ix^d,2))
6747 }
6748 {^iftwoc
6749 ! m2
6750 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_)&
6751 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c)
6752 ! b2
6753 if(.not.stagger_grid) then
6754 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6755 if(mhd_glm) then
6756 tmp=tmp+wprim(ix^d,psi_)*cot
6757 end if
6758 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
6759 end if
6760 }
6761
6762 {^ifthreec
6763 ! m2
6764 w(ix^d,m2_)=w(ix^d,m2_)+invr*(tmp1*cot-wprim(ix^d,rho_)*wprim(ix^d,m1_)*wprim(ix^d,m2_) &
6765 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+ef(ix^d,1)*ef(ix^d,2)*inv_squared_c&
6766 +(wprim(ix^d,rho_)*wprim(ix^d,m3_)**2&
6767 -wprim(ix^d,b3_)**2-ef(ix^d,3)**2*inv_squared_c)*cot)
6768 ! b2
6769 if(.not.stagger_grid) then
6770 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6771 if(mhd_glm) then
6772 tmp=tmp+wprim(ix^d,psi_)*cot
6773 end if
6774 w(ix^d,b2_)=w(ix^d,b2_)+tmp*invr
6775 end if
6776 ! m3
6777 w(ix^d,m3_)=w(ix^d,m3_)+invr*&
6778 (-wprim(ix^d,m3_)*wprim(ix^d,m1_)*wprim(ix^d,rho_) &
6779 +wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6780 +ef(ix^d,3)*ef(ix^d,1)*inv_squared_c&
6781 +(-wprim(ix^d,m2_)*wprim(ix^d,m3_)*wprim(ix^d,rho_) &
6782 +wprim(ix^d,b2_)*wprim(ix^d,b3_)&
6783 +ef(ix^d,2)*ef(ix^d,3)*inv_squared_c)*cot)
6784 ! b3
6785 if(.not.stagger_grid) then
6786 w(ix^d,b3_)=w(ix^d,b3_)+invr*&
6787 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6788 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6789 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6790 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6791 end if
6792 }
6793 {end do\}
6794 end select
6795
6796 if (mhd_rotating_frame) then
6797 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6798 end if
6799
6800 end subroutine mhd_add_source_geom_semirelati
6801
6802 ! Add geometrical source terms to w
6803 ! Geometric sources to momentum and induction
6804 ! for those cases where any kind of splitting (B0field or has_equi_rho_and_p) is active
6805 ! This implies that there is an energy equation included for sure
6806 ! B0field impacts terms in induction equation and geometric sources for them
6807 ! both flags affect the terms in momentum equation, in three variants (TF, TT, FT)
6808 ! NOTE: Hall terms in induction not handled yet
6809 subroutine mhd_add_source_geom_split(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
6811 use mod_geometry
6813
6814 integer, intent(in) :: ixi^l, ixo^l
6815 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
6816 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
6817
6818 double precision :: tmp,tmp1,tmp2,invr,cot
6819 integer :: ix^d
6820 integer :: mr_,mphi_ ! Polar var. names
6821 integer :: br_,bphi_
6822
6823 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
6824 br_=mag(1); bphi_=mag(1)-1+phi_
6825
6826
6827 select case (coordinate)
6828 case (cylindrical)
6829 {do ix^db=ixomin^db,ixomax^db\}
6830 ! include dt in invr, invr is always used with qdt
6831 if(local_timestep) then
6832 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6833 else
6834 invr=qdt/x(ix^d,1)
6835 end if
6836 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6837 if(b0field) tmp=tmp+(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
6838 if(phi_>0) then
6839 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
6840 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
6841 if(b0field) then
6842 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))
6843 endif
6844 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
6845 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
6846 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
6847 if(b0field) then
6848 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))
6849 endif
6850 if(.not.stagger_grid) then
6851 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6852 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
6853 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
6854 if(b0field) then
6855 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
6856 (block%B0(ix^d,phi_,0)*wprim(ix^d,mr_) &
6857 -block%B0(ix^d,r_,0)*wprim(ix^d,mphi_))
6858 endif
6859 end if
6860 else
6861 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
6862 end if
6863 if(mhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
6864 {end do\}
6865 case (spherical)
6866 {do ix^db=ixomin^db,ixomax^db\}
6867 ! include dt in invr, invr is always used with qdt
6868 if(local_timestep) then
6869 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
6870 else
6871 invr=qdt/x(ix^d,1)
6872 end if
6873 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
6874 if(b0field) tmp2=(^c&block%B0(ix^d,^c,0)*wprim(ix^d,b^c_)+)
6875 ! m1
6876 {^ifonec
6877 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
6878 if(b0field) w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp2*invr
6879 }
6880 {^noonec
6881 if(b0field) then
6882 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6883 (two*(tmp1+tmp2)+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+)- &
6884 (^ce&two*block%B0(ix^d,^ce,0)*wprim(ix^d,b^ce_)+))
6885 else
6886 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
6887 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
6888 end if
6889 }
6890 ! b1
6891 if(mhd_glm) then
6892 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
6893 end if
6894 {^ifoned
6895 cot=0.d0
6896 }
6897 {^nooned
6898 cot=1.d0/tan(x(ix^d,2))
6899 }
6900 {^iftwoc
6901 ! m2
6902 if(b0field) then
6903 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6904 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
6905 +wprim(ix^d,b1_)*block%B0(ix^d,2,0))
6906 else
6907 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6908 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
6909 end if
6910 ! b2
6911 if(.not.stagger_grid) then
6912 if(b0field) then
6913 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
6914 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
6915 else
6916 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6917 end if
6918 if(mhd_glm) then
6919 tmp=tmp+wprim(ix^d,psi_)*cot
6920 end if
6921 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6922 end if
6923 }
6924 {^ifthreec
6925 ! m2
6926 if(b0field) then
6927 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*((tmp1+tmp2)*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6928 +wprim(ix^d,b1_)*wprim(ix^d,b2_)+block%B0(ix^d,1,0)*wprim(ix^d,b2_)&
6929 +wprim(ix^d,b1_)*block%B0(ix^d,2,0)&
6930 +(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)
6931 else
6932 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
6933 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
6934 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
6935 end if
6936 ! b2
6937 if(.not.stagger_grid) then
6938 if(b0field) then
6939 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)&
6940 +wprim(ix^d,m1_)*block%B0(ix^d,2,0)-wprim(ix^d,m2_)*block%B0(ix^d,1,0)
6941 else
6942 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
6943 end if
6944 if(mhd_glm) then
6945 tmp=tmp+wprim(ix^d,psi_)*cot
6946 end if
6947 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
6948 end if
6949 ! m3
6950 if(b0field) then
6951 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6952 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6953 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6954 +block%B0(ix^d,1,0)*wprim(ix^d,b3_) &
6955 +wprim(ix^d,b1_)*block%B0(ix^d,3,0) &
6956 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6957 -wprim(ix^d,b2_)*wprim(ix^d,b3_) &
6958 +block%B0(ix^d,2,0)*wprim(ix^d,b3_) &
6959 +wprim(ix^d,b2_)*block%B0(ix^d,3,0))*cot)
6960 else
6961 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
6962 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
6963 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
6964 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
6965 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
6966 end if
6967 ! b3
6968 if(.not.stagger_grid) then
6969 if(b0field) then
6970 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6971 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6972 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6973 +wprim(ix^d,m1_)*block%B0(ix^d,3,0) &
6974 -wprim(ix^d,m3_)*block%B0(ix^d,1,0) &
6975 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6976 -wprim(ix^d,m2_)*wprim(ix^d,b3_) &
6977 +wprim(ix^d,m3_)*block%B0(ix^d,2,0) &
6978 -wprim(ix^d,m2_)*block%B0(ix^d,3,0))*cot)
6979 else
6980 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
6981 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
6982 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
6983 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
6984 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
6985 end if
6986 end if
6987 }
6988 {end do\}
6989 end select
6990
6991 if (mhd_rotating_frame) then
6992 call rotating_frame_add_source(qdt,dtfactor,ixi^l,ixo^l,wprim,w,x)
6993 end if
6994
6995 end subroutine mhd_add_source_geom_split
6996
6997 !> Compute 2 times total magnetic energy
6998 function mhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
7000 integer, intent(in) :: ixi^l, ixo^l
7001 double precision, intent(in) :: w(ixi^s, nw)
7002 double precision :: mge(ixo^s)
7003
7004 if (b0field) then
7005 mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
7006 else
7007 mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
7008 end if
7009 end function mhd_mag_en_all
7010
7011 subroutine mhd_getv_hall(w,x,ixI^L,ixO^L,vHall,partial)
7013 use mod_geometry
7014
7015 integer, intent(in) :: ixi^l, ixo^l
7016 double precision, intent(in) :: w(ixi^s,nw)
7017 double precision, intent(in) :: x(ixi^s,1:ndim)
7018 double precision, intent(inout) :: vhall(ixi^s,1:ndir)
7019 logical, intent(in), optional :: partial
7020
7021 double precision :: current(ixi^s,7-2*ndir:3)
7022 double precision :: rho(ixi^s)
7023 integer :: idir, idirmin, ix^d
7024 logical :: use_partial
7025
7026 use_partial=.false.
7027 if(present(partial)) use_partial=partial
7028 call mhd_get_rho(w,x,ixi^l,ixo^l,rho)
7029 if(.not.use_partial)then
7030 ! Calculate current density and idirmin, including J0 when split
7031 call get_current(w,ixi^l,ixo^l,idirmin,current)
7032 else
7033 if(slab_uniform) then
7034 ! fourth order CD in cartesian
7035 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir,.true.)
7036 else
7037 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,7-2*ndir,ndir)
7038 endif
7039 endif
7040 do idir = idirmin, ndir
7041 {do ix^db=ixomin^db,ixomax^db\}
7042 vhall(ix^d,idir)=-mhd_etah*current(ix^d,idir)/rho(ix^d)
7043 {end do\}
7044 end do
7045
7046 end subroutine mhd_getv_hall
7047
7048 subroutine mhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
7050 use mod_usr_methods
7051 integer, intent(in) :: ixi^l, ixo^l, idir
7052 double precision, intent(in) :: qt
7053 double precision, intent(inout) :: wlc(ixi^s,1:nw), wrc(ixi^s,1:nw)
7054 double precision, intent(inout) :: wlp(ixi^s,1:nw), wrp(ixi^s,1:nw)
7055 type(state) :: s
7056
7057 double precision :: db(ixo^s), dpsi(ixo^s)
7058 integer :: ix^d
7059
7060 if(stagger_grid) then
7061 {do ix^db=ixomin^db,ixomax^db\}
7062 wlc(ix^d,mag(idir))=s%ws(ix^d,idir)
7063 wrc(ix^d,mag(idir))=s%ws(ix^d,idir)
7064 wlp(ix^d,mag(idir))=s%ws(ix^d,idir)
7065 wrp(ix^d,mag(idir))=s%ws(ix^d,idir)
7066 {end do\}
7067 else
7068 ! Solve the Riemann problem for the linear 2x2 system for normal
7069 ! B-field and GLM_Psi according to Dedner 2002:
7070 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
7071 ! Gives the Riemann solution on the interface
7072 ! for the normal B component and Psi in the GLM-MHD system.
7073 ! 23/04/2013 Oliver Porth
7074 {do ix^db=ixomin^db,ixomax^db\}
7075 db(ix^d)=wrp(ix^d,mag(idir))-wlp(ix^d,mag(idir))
7076 dpsi(ix^d)=wrp(ix^d,psi_)-wlp(ix^d,psi_)
7077 wlp(ix^d,mag(idir))=half*(wrp(ix^d,mag(idir))+wlp(ix^d,mag(idir))-dpsi(ix^d)/cmax_global)
7078 wlp(ix^d,psi_)=half*(wrp(ix^d,psi_)+wlp(ix^d,psi_)-db(ix^d)*cmax_global)
7079 wrp(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7080 wrp(ix^d,psi_)=wlp(ix^d,psi_)
7081 if(total_energy) then
7082 wrc(ix^d,e_)=wrc(ix^d,e_)-half*wrc(ix^d,mag(idir))**2
7083 wlc(ix^d,e_)=wlc(ix^d,e_)-half*wlc(ix^d,mag(idir))**2
7084 end if
7085 wrc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7086 wrc(ix^d,psi_)=wlp(ix^d,psi_)
7087 wlc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
7088 wlc(ix^d,psi_)=wlp(ix^d,psi_)
7089 ! modify total energy according to the change of magnetic field
7090 if(total_energy) then
7091 wrc(ix^d,e_)=wrc(ix^d,e_)+half*wrc(ix^d,mag(idir))**2
7092 wlc(ix^d,e_)=wlc(ix^d,e_)+half*wlc(ix^d,mag(idir))**2
7093 end if
7094 {end do\}
7095 end if
7096
7097 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
7098
7099 end subroutine mhd_modify_wlr
7100
7101 subroutine mhd_boundary_adjust(igrid,psb)
7103 integer, intent(in) :: igrid
7104 type(state), target :: psb(max_blocks)
7105
7106 integer :: ib, idims, iside, ixo^l, i^d
7107
7108 block=>ps(igrid)
7109 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7110 do idims=1,ndim
7111 ! to avoid using as yet unknown corner info in more than 1D, we
7112 ! fill only interior mesh ranges of the ghost cell ranges at first,
7113 ! and progressively enlarge the ranges to include corners later
7114 do iside=1,2
7115 i^d=kr(^d,idims)*(2*iside-3);
7116 if (neighbor_type(i^d,igrid)/=1) cycle
7117 ib=(idims-1)*2+iside
7118 if(.not.boundary_divbfix(ib)) cycle
7119 if(any(typeboundary(:,ib)==bc_special)) then
7120 ! MF nonlinear force-free B field extrapolation and data driven
7121 ! require normal B of the first ghost cell layer to be untouched by
7122 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
7123 select case (idims)
7124 {case (^d)
7125 if (iside==2) then
7126 ! maximal boundary
7127 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
7128 ixomax^dd=ixghi^dd;
7129 else
7130 ! minimal boundary
7131 ixomin^dd=ixglo^dd;
7132 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
7133 end if \}
7134 end select
7135 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
7136 end if
7137 end do
7138 end do
7139
7140 end subroutine mhd_boundary_adjust
7141
7142 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
7144
7145 integer, intent(in) :: ixg^l,ixo^l,ib
7146 double precision, intent(inout) :: w(ixg^s,1:nw)
7147 double precision, intent(in) :: x(ixg^s,1:ndim)
7148
7149 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
7150 integer :: ix^d,ixf^l
7151
7152 select case(ib)
7153 case(1)
7154 ! 2nd order CD for divB=0 to set normal B component better
7155 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7156 {^iftwod
7157 ixfmin1=ixomin1+1
7158 ixfmax1=ixomax1+1
7159 ixfmin2=ixomin2+1
7160 ixfmax2=ixomax2-1
7161 if(slab_uniform) then
7162 dx1x2=dxlevel(1)/dxlevel(2)
7163 do ix1=ixfmax1,ixfmin1,-1
7164 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
7165 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7166 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7167 enddo
7168 else
7169 do ix1=ixfmax1,ixfmin1,-1
7170 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
7171 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
7172 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7173 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7174 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7175 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7176 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7177 end do
7178 end if
7179 }
7180 {^ifthreed
7181 ixfmin1=ixomin1+1
7182 ixfmax1=ixomax1+1
7183 ixfmin2=ixomin2+1
7184 ixfmax2=ixomax2-1
7185 ixfmin3=ixomin3+1
7186 ixfmax3=ixomax3-1
7187 if(slab_uniform) then
7188 dx1x2=dxlevel(1)/dxlevel(2)
7189 dx1x3=dxlevel(1)/dxlevel(3)
7190 do ix1=ixfmax1,ixfmin1,-1
7191 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7192 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7193 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7194 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7195 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7196 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7197 end do
7198 else
7199 do ix1=ixfmax1,ixfmin1,-1
7200 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7201 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7202 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7203 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7204 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7205 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7206 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7207 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7208 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7209 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7210 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7211 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7212 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7213 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7214 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7215 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7216 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7217 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7218 end do
7219 end if
7220 }
7221 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7222 case(2)
7223 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7224 {^iftwod
7225 ixfmin1=ixomin1-1
7226 ixfmax1=ixomax1-1
7227 ixfmin2=ixomin2+1
7228 ixfmax2=ixomax2-1
7229 if(slab_uniform) then
7230 dx1x2=dxlevel(1)/dxlevel(2)
7231 do ix1=ixfmin1,ixfmax1
7232 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
7233 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
7234 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
7235 enddo
7236 else
7237 do ix1=ixfmin1,ixfmax1
7238 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
7239 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
7240 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
7241 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
7242 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
7243 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
7244 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
7245 end do
7246 end if
7247 }
7248 {^ifthreed
7249 ixfmin1=ixomin1-1
7250 ixfmax1=ixomax1-1
7251 ixfmin2=ixomin2+1
7252 ixfmax2=ixomax2-1
7253 ixfmin3=ixomin3+1
7254 ixfmax3=ixomax3-1
7255 if(slab_uniform) then
7256 dx1x2=dxlevel(1)/dxlevel(2)
7257 dx1x3=dxlevel(1)/dxlevel(3)
7258 do ix1=ixfmin1,ixfmax1
7259 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7260 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
7261 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
7262 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
7263 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
7264 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
7265 end do
7266 else
7267 do ix1=ixfmin1,ixfmax1
7268 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
7269 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
7270 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
7271 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
7272 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
7273 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
7274 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
7275 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
7276 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
7277 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
7278 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
7279 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
7280 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
7281 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
7282 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7283 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
7284 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
7285 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
7286 end do
7287 end if
7288 }
7289 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7290 case(3)
7291 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7292 {^iftwod
7293 ixfmin1=ixomin1+1
7294 ixfmax1=ixomax1-1
7295 ixfmin2=ixomin2+1
7296 ixfmax2=ixomax2+1
7297 if(slab_uniform) then
7298 dx2x1=dxlevel(2)/dxlevel(1)
7299 do ix2=ixfmax2,ixfmin2,-1
7300 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
7301 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7302 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7303 enddo
7304 else
7305 do ix2=ixfmax2,ixfmin2,-1
7306 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
7307 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
7308 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7309 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7310 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7311 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7312 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7313 end do
7314 end if
7315 }
7316 {^ifthreed
7317 ixfmin1=ixomin1+1
7318 ixfmax1=ixomax1-1
7319 ixfmin3=ixomin3+1
7320 ixfmax3=ixomax3-1
7321 ixfmin2=ixomin2+1
7322 ixfmax2=ixomax2+1
7323 if(slab_uniform) then
7324 dx2x1=dxlevel(2)/dxlevel(1)
7325 dx2x3=dxlevel(2)/dxlevel(3)
7326 do ix2=ixfmax2,ixfmin2,-1
7327 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7328 ix2+1,ixfmin3:ixfmax3,mag(2)) &
7329 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7330 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7331 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7332 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7333 end do
7334 else
7335 do ix2=ixfmax2,ixfmin2,-1
7336 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
7337 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
7338 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7339 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
7340 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7341 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7342 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7343 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7344 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7345 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7346 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7347 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7348 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7349 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7350 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7351 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7352 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
7353 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7354 end do
7355 end if
7356 }
7357 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7358 case(4)
7359 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7360 {^iftwod
7361 ixfmin1=ixomin1+1
7362 ixfmax1=ixomax1-1
7363 ixfmin2=ixomin2-1
7364 ixfmax2=ixomax2-1
7365 if(slab_uniform) then
7366 dx2x1=dxlevel(2)/dxlevel(1)
7367 do ix2=ixfmin2,ixfmax2
7368 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
7369 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
7370 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
7371 end do
7372 else
7373 do ix2=ixfmin2,ixfmax2
7374 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
7375 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
7376 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
7377 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
7378 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
7379 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
7380 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
7381 end do
7382 end if
7383 }
7384 {^ifthreed
7385 ixfmin1=ixomin1+1
7386 ixfmax1=ixomax1-1
7387 ixfmin3=ixomin3+1
7388 ixfmax3=ixomax3-1
7389 ixfmin2=ixomin2-1
7390 ixfmax2=ixomax2-1
7391 if(slab_uniform) then
7392 dx2x1=dxlevel(2)/dxlevel(1)
7393 dx2x3=dxlevel(2)/dxlevel(3)
7394 do ix2=ixfmin2,ixfmax2
7395 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
7396 ix2-1,ixfmin3:ixfmax3,mag(2)) &
7397 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
7398 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
7399 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
7400 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
7401 end do
7402 else
7403 do ix2=ixfmin2,ixfmax2
7404 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
7405 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
7406 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
7407 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
7408 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
7409 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7410 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
7411 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
7412 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
7413 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
7414 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
7415 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
7416 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
7417 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
7418 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
7419 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
7420 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
7421 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
7422 end do
7423 end if
7424 }
7425 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7426 {^ifthreed
7427 case(5)
7428 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7429 ixfmin1=ixomin1+1
7430 ixfmax1=ixomax1-1
7431 ixfmin2=ixomin2+1
7432 ixfmax2=ixomax2-1
7433 ixfmin3=ixomin3+1
7434 ixfmax3=ixomax3+1
7435 if(slab_uniform) then
7436 dx3x1=dxlevel(3)/dxlevel(1)
7437 dx3x2=dxlevel(3)/dxlevel(2)
7438 do ix3=ixfmax3,ixfmin3,-1
7439 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
7440 ixfmin2:ixfmax2,ix3+1,mag(3)) &
7441 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7442 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7443 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7444 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7445 end do
7446 else
7447 do ix3=ixfmax3,ixfmin3,-1
7448 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
7449 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
7450 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7451 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
7452 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7453 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7454 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7455 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7456 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7457 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7458 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7459 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7460 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7461 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7462 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7463 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7464 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
7465 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7466 end do
7467 end if
7468 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7469 case(6)
7470 if(total_energy) call mhd_to_primitive(ixg^l,ixo^l,w,x)
7471 ixfmin1=ixomin1+1
7472 ixfmax1=ixomax1-1
7473 ixfmin2=ixomin2+1
7474 ixfmax2=ixomax2-1
7475 ixfmin3=ixomin3-1
7476 ixfmax3=ixomax3-1
7477 if(slab_uniform) then
7478 dx3x1=dxlevel(3)/dxlevel(1)
7479 dx3x2=dxlevel(3)/dxlevel(2)
7480 do ix3=ixfmin3,ixfmax3
7481 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
7482 ixfmin2:ixfmax2,ix3-1,mag(3)) &
7483 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
7484 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
7485 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
7486 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
7487 end do
7488 else
7489 do ix3=ixfmin3,ixfmax3
7490 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
7491 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
7492 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
7493 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
7494 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
7495 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7496 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
7497 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
7498 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
7499 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
7500 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
7501 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
7502 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
7503 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
7504 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
7505 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
7506 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
7507 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
7508 end do
7509 end if
7510 if(total_energy) call mhd_to_conserved(ixg^l,ixo^l,w,x)
7511 }
7512 case default
7513 call mpistop("Special boundary is not defined for this region")
7514 end select
7515
7516 end subroutine fixdivb_boundary
7517
7518 {^nooned
7519 subroutine mhd_clean_divb_multigrid(qdt, qt, active)
7520 use mod_forest
7523 use mod_geometry
7524
7525 double precision, intent(in) :: qdt !< Current time step
7526 double precision, intent(in) :: qt !< Current time
7527 logical, intent(inout) :: active !< Output if the source is active
7528
7529 integer :: id
7530 integer, parameter :: max_its = 50
7531 double precision :: residual_it(max_its), max_divb
7532 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
7533 double precision :: res
7534 double precision, parameter :: max_residual = 1d-3
7535 double precision, parameter :: residual_reduction = 1d-10
7536 integer :: iigrid, igrid
7537 integer :: n, nc, lvl, ix^l, ixc^l, idim
7538 type(tree_node), pointer :: pnode
7539
7540 mg%operator_type = mg_laplacian
7541
7542 ! Set boundary conditions
7543 do n = 1, 2*ndim
7544 idim = (n+1)/2
7545 select case (typeboundary(mag(idim), n))
7546 case (bc_symm)
7547 ! d/dx B = 0, take phi = 0
7548 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7549 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7550 case (bc_asymm)
7551 ! B = 0, so grad(phi) = 0
7552 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
7553 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7554 case (bc_cont)
7555 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7556 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7557 case (bc_special)
7558 ! Assume Dirichlet boundary conditions, derivative zero
7559 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7560 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7561 case (bc_periodic)
7562 ! Nothing to do here
7563 case default
7564 write(*,*) "mhd_clean_divb_multigrid warning: unknown boundary type"
7565 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
7566 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
7567 end select
7568 end do
7569
7570 ix^l=ixm^ll^ladd1;
7571 max_divb = 0.0d0
7572
7573 ! Store divergence of B as right-hand side
7574 do iigrid = 1, igridstail
7575 igrid = igrids(iigrid);
7576 pnode => igrid_to_node(igrid, mype)%node
7577 id = pnode%id
7578 lvl = mg%boxes(id)%lvl
7579 nc = mg%box_size_lvl(lvl)
7580
7581 ! Geometry subroutines expect this to be set
7582 block => ps(igrid)
7583 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7584
7585 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
7587 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
7588 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
7589 end do
7590
7591 ! Solve laplacian(phi) = divB
7592 if(stagger_grid) then
7593 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
7594 mpi_max, icomm, ierrmpi)
7595
7596 if (mype == 0) print *, "Performing multigrid divB cleaning"
7597 if (mype == 0) print *, "iteration vs residual"
7598 ! Solve laplacian(phi) = divB
7599 do n = 1, max_its
7600 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
7601 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
7602 if (residual_it(n) < residual_reduction * max_divb) exit
7603 end do
7604 if (mype == 0 .and. n > max_its) then
7605 print *, "divb_multigrid warning: not fully converged"
7606 print *, "current amplitude of divb: ", residual_it(max_its)
7607 print *, "multigrid smallest grid: ", &
7608 mg%domain_size_lvl(:, mg%lowest_lvl)
7609 print *, "note: smallest grid ideally has <= 8 cells"
7610 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
7611 print *, "note: dx/dy/dz should be similar"
7612 end if
7613 else
7614 do n = 1, max_its
7615 call mg_fas_vcycle(mg, max_res=res)
7616 if (res < max_residual) exit
7617 end do
7618 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
7619 end if
7620
7621
7622 ! Correct the magnetic field
7623 do iigrid = 1, igridstail
7624 igrid = igrids(iigrid);
7625 pnode => igrid_to_node(igrid, mype)%node
7626 id = pnode%id
7627
7628 ! Geometry subroutines expect this to be set
7629 block => ps(igrid)
7630 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
7631
7632 ! Compute the gradient of phi
7633 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
7634
7635 if(stagger_grid) then
7636 do idim =1, ndim
7637 ixcmin^d=ixmlo^d-kr(idim,^d);
7638 ixcmax^d=ixmhi^d;
7639 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
7640 ! Apply the correction B* = B - gradient(phi)
7641 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
7642 end do
7643 ! store cell-center magnetic energy
7644 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
7645 ! change cell-center magnetic field
7646 call mhd_face_to_center(ixm^ll,ps(igrid))
7647 else
7648 do idim = 1, ndim
7649 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
7650 end do
7651 ! store cell-center magnetic energy
7652 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
7653 ! Apply the correction B* = B - gradient(phi)
7654 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
7655 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
7656 end if
7657
7658 if(total_energy) then
7659 ! Determine magnetic energy difference
7660 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
7661 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
7662 ! Keep thermal pressure the same
7663 ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
7664 end if
7665 end do
7666
7667 active = .true.
7668
7669 end subroutine mhd_clean_divb_multigrid
7670 }
7671
7672 !> get electric field through averaging neighors to update faces in CT
7673 subroutine mhd_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
7675 use mod_usr_methods
7676
7677 integer, intent(in) :: ixi^l, ixo^l
7678 double precision, intent(in) :: qt,qdt
7679 ! cell-center primitive variables
7680 double precision, intent(in) :: wp(ixi^s,1:nw)
7681 type(state) :: sct, s
7682 type(ct_velocity) :: vcts
7683 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
7684 double precision, intent(inout) :: fe(ixi^s,sdim:3)
7685
7686 double precision :: circ(ixi^s,1:ndim)
7687 ! non-ideal electric field on cell edges
7688 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
7689 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
7690 integer :: idim1,idim2,idir,iwdim1,iwdim2
7691
7692 associate(bfaces=>s%ws,x=>s%x)
7693
7694 ! Calculate contribution to FEM of each edge,
7695 ! that is, estimate value of line integral of
7696 ! electric field in the positive idir direction.
7697
7698 ! if there is resistivity, get eta J
7699 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
7700
7701 ! if there is ambipolar diffusion, get E_ambi
7702 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
7703
7704 do idim1=1,ndim
7705 iwdim1 = mag(idim1)
7706 i1kr^d=kr(idim1,^d);
7707 do idim2=1,ndim
7708 iwdim2 = mag(idim2)
7709 i2kr^d=kr(idim2,^d);
7710 do idir=sdim,3! Direction of line integral
7711 ! Allow only even permutations
7712 if (lvc(idim1,idim2,idir)==1) then
7713 ixcmax^d=ixomax^d;
7714 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7715 ! average cell-face electric field to cell edges
7716 {do ix^db=ixcmin^db,ixcmax^db\}
7717 fe(ix^d,idir)=quarter*&
7718 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
7719 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
7720 ! add resistive electric field at cell edges E=-vxB+eta J
7721 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
7722 ! add ambipolar electric field
7723 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
7724
7725 ! times time step and edge length
7726 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
7727 {end do\}
7728 end if
7729 end do
7730 end do
7731 end do
7732
7733 ! allow user to change inductive electric field, especially for boundary driven applications
7734 if(associated(usr_set_electric_field)) &
7735 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
7736
7737 circ(ixi^s,1:ndim)=zero
7738
7739 ! Calculate circulation on each face
7740 do idim1=1,ndim ! Coordinate perpendicular to face
7741 ixcmax^d=ixomax^d;
7742 ixcmin^d=ixomin^d-kr(idim1,^d);
7743 do idim2=1,ndim
7744 ixa^l=ixc^l-kr(idim2,^d);
7745 do idir=sdim,3 ! Direction of line integral
7746 ! Assemble indices
7747 if(lvc(idim1,idim2,idir)==1) then
7748 ! Add line integrals in direction idir
7749 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7750 +(fe(ixc^s,idir)&
7751 -fe(ixa^s,idir))
7752 else if(lvc(idim1,idim2,idir)==-1) then
7753 ! Add line integrals in direction idir
7754 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
7755 -(fe(ixc^s,idir)&
7756 -fe(ixa^s,idir))
7757 end if
7758 end do
7759 end do
7760 {do ix^db=ixcmin^db,ixcmax^db\}
7761 ! Divide by the area of the face to get dB/dt
7762 if(s%surfaceC(ix^d,idim1) > smalldouble) then
7763 ! Time update cell-face magnetic field component
7764 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
7765 end if
7766 {end do\}
7767 end do
7768
7769 end associate
7770
7771 end subroutine mhd_update_faces_average
7772
7773 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
7774 subroutine mhd_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
7776 use mod_usr_methods
7777 use mod_geometry
7778
7779 integer, intent(in) :: ixi^l, ixo^l
7780 double precision, intent(in) :: qt, qdt
7781 ! cell-center primitive variables
7782 double precision, intent(in) :: wp(ixi^s,1:nw)
7783 type(state) :: sct, s
7784 type(ct_velocity) :: vcts
7785 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
7786 double precision, intent(inout) :: fe(ixi^s,sdim:3)
7787
7788 double precision :: circ(ixi^s,1:ndim)
7789 ! electric field at cell centers
7790 double precision :: ecc(ixi^s,sdim:3)
7791 double precision :: ein(ixi^s,sdim:3)
7792 ! gradient of E at left and right side of a cell face
7793 double precision :: el(ixi^s),er(ixi^s)
7794 ! gradient of E at left and right side of a cell corner
7795 double precision :: elc,erc
7796 ! non-ideal electric field on cell edges
7797 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
7798 ! current on cell edges
7799 double precision :: jce(ixi^s,sdim:3)
7800 ! location at cell faces
7801 double precision :: xs(ixgs^t,1:ndim)
7802 double precision :: gradi(ixgs^t)
7803 integer :: ixc^l,ixa^l
7804 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
7805
7806 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
7807
7808 ! if there is resistivity, get eta J
7809 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
7810
7811 ! if there is ambipolar diffusion, get E_ambi
7812 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
7813
7814 if(b0field) then
7815 {do ix^db=iximin^db,iximax^db\}
7816 ! Calculate electric field at cell centers
7817 {^ifthreed
7818 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_)
7819 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_)
7820 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_)
7821 }
7822 {^iftwod
7823 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7824 }
7825 {^ifoned
7826 ecc(ix^d,3)=0.d0
7827 }
7828 {end do\}
7829 else
7830 {do ix^db=iximin^db,iximax^db\}
7831 ! Calculate electric field at cell centers
7832 {^ifthreed
7833 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
7834 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
7835 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7836 }
7837 {^iftwod
7838 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
7839 }
7840 {^ifoned
7841 ecc(ix^d,3)=0.d0
7842 }
7843 {end do\}
7844 end if
7845
7846 ! Calculate contribution to FEM of each edge,
7847 ! that is, estimate value of line integral of
7848 ! electric field in the positive idir direction.
7849 ! evaluate electric field along cell edges according to equation (41)
7850 do idim1=1,ndim
7851 iwdim1 = mag(idim1)
7852 i1kr^d=kr(idim1,^d);
7853 do idim2=1,ndim
7854 iwdim2 = mag(idim2)
7855 i2kr^d=kr(idim2,^d);
7856 do idir=sdim,3 ! Direction of line integral
7857 ! Allow only even permutations
7858 if (lvc(idim1,idim2,idir)==1) then
7859 ixcmax^d=ixomax^d;
7860 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7861 ! Assemble indices
7862 ! average cell-face electric field to cell edges
7863 {do ix^db=ixcmin^db,ixcmax^db\}
7864 fe(ix^d,idir)=quarter*&
7865 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
7866 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
7867 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)
7868 {end do\}
7869 ! add slope in idim2 direction from equation (50)
7870 ixamin^d=ixcmin^d;
7871 ixamax^d=ixcmax^d+i1kr^d;
7872 {do ix^db=ixamin^db,ixamax^db\}
7873 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
7874 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
7875 {end do\}
7876 {!dir$ ivdep
7877 do ix^db=ixcmin^db,ixcmax^db\}
7878 if(vnorm(ix^d,idim1)>0.d0) then
7879 elc=el(ix^d)
7880 else if(vnorm(ix^d,idim1)<0.d0) then
7881 elc=el({ix^d+i1kr^d})
7882 else
7883 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
7884 end if
7885 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
7886 erc=er(ix^d)
7887 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
7888 erc=er({ix^d+i1kr^d})
7889 else
7890 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
7891 end if
7892 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
7893 {end do\}
7894
7895 ! add slope in idim1 direction from equation (50)
7896 ixamin^d=ixcmin^d;
7897 ixamax^d=ixcmax^d+i2kr^d;
7898 {do ix^db=ixamin^db,ixamax^db\}
7899 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
7900 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
7901 {end do\}
7902 {!dir$ ivdep
7903 do ix^db=ixcmin^db,ixcmax^db\}
7904 if(vnorm(ix^d,idim2)>0.d0) then
7905 elc=el(ix^d)
7906 else if(vnorm(ix^d,idim2)<0.d0) then
7907 elc=el({ix^d+i2kr^d})
7908 else
7909 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
7910 end if
7911 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
7912 erc=er(ix^d)
7913 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
7914 erc=er({ix^d+i2kr^d})
7915 else
7916 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
7917 end if
7918 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
7919 ! difference between average and upwind interpolated E
7920 if(numerical_resistive_heating) ein(ix^d,idir)=fe(ix^d,idir)-ein(ix^d,idir)
7921 ! add resistive electric field at cell edges E=-vxB+eta J
7922 if(mhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
7923 ! add ambipolar electric field
7924 if(mhd_ambipolar_exp) fe(ix^d,idir)=fe(ix^d,idir)+e_ambi(ix^d,idir)
7925
7926 ! times time step and edge length
7927 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
7928 {end do\}
7929 end if
7930 end do
7931 end do
7932 end do
7933
7935 ! add upwind diffused magnetic energy back to energy
7936 ! calculate current density at cell edges
7937 jce=0.d0
7938 do idim1=1,ndim
7939 do idim2=1,ndim
7940 do idir=sdim,3
7941 if (lvc(idim1,idim2,idir)==0) cycle
7942 ixcmax^d=ixomax^d;
7943 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7944 ixamax^d=ixcmax^d-kr(idir,^d)+1;
7945 ixamin^d=ixcmin^d;
7946 ! current at transverse faces
7947 xs(ixa^s,:)=x(ixa^s,:)
7948 xs(ixa^s,idim2)=x(ixa^s,idim2)+half*s%dx(ixa^s,idim2)
7949 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi)
7950 if (lvc(idim1,idim2,idir)==1) then
7951 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
7952 else
7953 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
7954 end if
7955 end do
7956 end do
7957 end do
7958 do idir=sdim,3
7959 ixcmax^d=ixomax^d;
7960 ixcmin^d=ixomin^d+kr(idir,^d)-1;
7961 ! E dot J on cell edges
7962 ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
7963 ! average from cell edge to cell center
7964 {^ifthreed
7965 if(idir==1) then
7966 {do ix^db=ixomin^db,ixomax^db\}
7967 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1,ix2-1,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
7968 +ein(ix1,ix2-1,ix3-1,idir))
7969 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7970 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7971 {end do\}
7972 else if(idir==2) then
7973 {do ix^db=ixomin^db,ixomax^db\}
7974 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
7975 +ein(ix1-1,ix2,ix3-1,idir))
7976 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7977 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7978 {end do\}
7979 else
7980 {do ix^db=ixomin^db,ixomax^db\}
7981 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2-1,ix3,idir)&
7982 +ein(ix1-1,ix2-1,ix3,idir))
7983 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7984 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7985 {end do\}
7986 end if
7987 }
7988 {^iftwod
7989 !idir=3
7990 {do ix^db=ixomin^db,ixomax^db\}
7991 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,idir)+ein(ix1,ix2-1,idir)&
7992 +ein(ix1-1,ix2-1,idir))
7993 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
7994 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
7995 {end do\}
7996 }
7997 ! save additional numerical resistive heating to an extra variable
7998 !! if(nwextra>0) then
7999 !! block%w(ixO^S,nw)=block%w(ixO^S,nw)+jce(ixO^S,idir)
8000 !! end if
8001 end do
8002 end if
8003
8004 ! allow user to change inductive electric field, especially for boundary driven applications
8005 if(associated(usr_set_electric_field)) &
8006 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8007
8008 circ(ixi^s,1:ndim)=zero
8009
8010 ! Calculate circulation on each face
8011 do idim1=1,ndim ! Coordinate perpendicular to face
8012 ixcmax^d=ixomax^d;
8013 ixcmin^d=ixomin^d-kr(idim1,^d);
8014 do idim2=1,ndim
8015 ixa^l=ixc^l-kr(idim2,^d);
8016 do idir=sdim,3 ! Direction of line integral
8017 ! Assemble indices
8018 if(lvc(idim1,idim2,idir)==1) then
8019 ! Add line integrals in direction idir
8020 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8021 +(fe(ixc^s,idir)&
8022 -fe(ixa^s,idir))
8023 else if(lvc(idim1,idim2,idir)==-1) then
8024 ! Add line integrals in direction idir
8025 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8026 -(fe(ixc^s,idir)&
8027 -fe(ixa^s,idir))
8028 end if
8029 end do
8030 end do
8031 {do ix^db=ixcmin^db,ixcmax^db\}
8032 ! Divide by the area of the face to get dB/dt
8033 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8034 ! Time update cell-face magnetic field component
8035 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8036 end if
8037 {end do\}
8038 end do
8039
8040 end associate
8041
8042 end subroutine mhd_update_faces_contact
8043
8044 !> update faces
8045 subroutine mhd_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
8047 use mod_usr_methods
8049
8050 integer, intent(in) :: ixi^l, ixo^l
8051 double precision, intent(in) :: qt, qdt
8052 ! cell-center primitive variables
8053 double precision, intent(in) :: wp(ixi^s,1:nw)
8054 type(state) :: sct, s
8055 type(ct_velocity) :: vcts
8056 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
8057 double precision, intent(inout) :: fe(ixi^s,sdim:3)
8058
8059 double precision :: vtill(ixi^s,2)
8060 double precision :: vtilr(ixi^s,2)
8061 double precision :: bfacetot(ixi^s,ndim)
8062 double precision :: btill(ixi^s,ndim)
8063 double precision :: btilr(ixi^s,ndim)
8064 double precision :: cp(ixi^s,2)
8065 double precision :: cm(ixi^s,2)
8066 double precision :: circ(ixi^s,1:ndim)
8067 ! non-ideal electric field on cell edges
8068 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
8069 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
8070 integer :: idim1,idim2,idir,ix^d
8071
8072 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
8073 cbarmax=>vcts%cbarmax)
8074
8075 ! Calculate contribution to FEM of each edge,
8076 ! that is, estimate value of line integral of
8077 ! electric field in the positive idir direction.
8078
8079 ! Loop over components of electric field
8080
8081 ! idir: electric field component we need to calculate
8082 ! idim1: directions in which we already performed the reconstruction
8083 ! idim2: directions in which we perform the reconstruction
8084
8085 ! if there is resistivity, get eta J
8086 if(mhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
8087
8088 ! if there is ambipolar diffusion, get E_ambi
8089 if(mhd_ambipolar_exp) call get_ambipolar_electric_field(ixi^l,ixo^l,sct%w,x,e_ambi)
8090
8091 do idir=sdim,3
8092 ! Indices
8093 ! idir: electric field component
8094 ! idim1: one surface
8095 ! idim2: the other surface
8096 ! cyclic permutation: idim1,idim2,idir=1,2,3
8097 ! Velocity components on the surface
8098 ! follow cyclic premutations:
8099 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
8100
8101 ixcmax^d=ixomax^d;
8102 ixcmin^d=ixomin^d-1+kr(idir,^d);
8103
8104 ! Set indices and directions
8105 idim1=mod(idir,3)+1
8106 idim2=mod(idir+1,3)+1
8107
8108 jxc^l=ixc^l+kr(idim1,^d);
8109 ixcp^l=ixc^l+kr(idim2,^d);
8110
8111 ! Reconstruct transverse transport velocities
8112 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
8113 vtill(ixi^s,2),vtilr(ixi^s,2))
8114
8115 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
8116 vtill(ixi^s,1),vtilr(ixi^s,1))
8117
8118 ! Reconstruct magnetic fields
8119 ! Eventhough the arrays are larger, reconstruct works with
8120 ! the limits ixG.
8121 if(b0field) then
8122 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
8123 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
8124 else
8125 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
8126 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
8127 end if
8128 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
8129 btill(ixi^s,idim1),btilr(ixi^s,idim1))
8130
8131 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
8132 btill(ixi^s,idim2),btilr(ixi^s,idim2))
8133
8134 ! Take the maximum characteristic
8135
8136 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
8137 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
8138
8139 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
8140 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
8141
8142
8143 ! Calculate eletric field
8144 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
8145 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
8146 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
8147 /(cp(ixc^s,1)+cm(ixc^s,1)) &
8148 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
8149 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
8150 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
8151 /(cp(ixc^s,2)+cm(ixc^s,2))
8152
8153 ! add resistive electric field at cell edges E=-vxB+eta J
8154 if(mhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
8155 ! add ambipolar electric field
8156 if(mhd_ambipolar_exp) fe(ixc^s,idir)=fe(ixc^s,idir)+e_ambi(ixc^s,idir)
8157
8158 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
8159
8160 if (.not.slab) then
8161 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
8162 fe(ixc^s,idir)=zero
8163 end where
8164 end if
8165
8166 end do
8167
8168 ! allow user to change inductive electric field, especially for boundary driven applications
8169 if(associated(usr_set_electric_field)) &
8170 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
8171
8172 circ(ixi^s,1:ndim)=zero
8173
8174 ! Calculate circulation on each face: interal(fE dot dl)
8175 do idim1=1,ndim ! Coordinate perpendicular to face
8176 ixcmax^d=ixomax^d;
8177 ixcmin^d=ixomin^d-kr(idim1,^d);
8178 do idim2=1,ndim
8179 do idir=sdim,3 ! Direction of line integral
8180 ! Assemble indices
8181 if(lvc(idim1,idim2,idir)/=0) then
8182 hxc^l=ixc^l-kr(idim2,^d);
8183 ! Add line integrals in direction idir
8184 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
8185 +lvc(idim1,idim2,idir)&
8186 *(fe(ixc^s,idir)&
8187 -fe(hxc^s,idir))
8188 end if
8189 end do
8190 end do
8191 {do ix^db=ixcmin^db,ixcmax^db\}
8192 ! Divide by the area of the face to get dB/dt
8193 if(s%surfaceC(ix^d,idim1) > smalldouble) then
8194 ! Time update cell-face magnetic field component
8195 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
8196 end if
8197 {end do\}
8198 end do
8199
8200 end associate
8201 end subroutine mhd_update_faces_hll
8202
8203 !> calculate eta J at cell edges
8204 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
8206 use mod_usr_methods
8207 use mod_geometry
8208
8209 integer, intent(in) :: ixi^l, ixo^l
8210 ! cell-center primitive variables
8211 double precision, intent(in) :: wp(ixi^s,1:nw)
8212 type(state), intent(in) :: sct, s
8213 ! current on cell edges
8214 double precision :: jce(ixi^s,sdim:3)
8215
8216 ! current on cell centers
8217 double precision :: jcc(ixi^s,7-2*ndir:3)
8218 ! location at cell faces
8219 double precision :: xs(ixgs^t,1:ndim)
8220 ! resistivity
8221 double precision :: eta(ixi^s)
8222 double precision :: gradi(ixgs^t)
8223 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
8224
8225 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
8226 ! calculate current density at cell edges
8227 jce=0.d0
8228 do idim1=1,ndim
8229 do idim2=1,ndim
8230 do idir=sdim,3
8231 if (lvc(idim1,idim2,idir)==0) cycle
8232 ixcmax^d=ixomax^d;
8233 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8234 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
8235 ixbmin^d=ixcmin^d;
8236 ! current at transverse faces
8237 xs(ixb^s,:)=x(ixb^s,:)
8238 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
8239 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
8240 if (lvc(idim1,idim2,idir)==1) then
8241 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
8242 else
8243 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
8244 end if
8245 end do
8246 end do
8247 end do
8248 ! get resistivity
8249 if(mhd_eta>zero)then
8250 jce(ixi^s,:)=jce(ixi^s,:)*mhd_eta
8251 else
8252 ixa^l=ixo^l^ladd1;
8253 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
8254 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
8255 ! calculate eta on cell edges
8256 do idir=sdim,3
8257 ixcmax^d=ixomax^d;
8258 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8259 jcc(ixc^s,idir)=0.d0
8260 {do ix^db=0,1\}
8261 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8262 ixamin^d=ixcmin^d+ix^d;
8263 ixamax^d=ixcmax^d+ix^d;
8264 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
8265 {end do\}
8266 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
8267 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
8268 end do
8269 end if
8270
8271 end associate
8272 end subroutine get_resistive_electric_field
8273
8274 !> get ambipolar electric field on cell edges
8275 subroutine get_ambipolar_electric_field(ixI^L,ixO^L,w,x,fE)
8277
8278 integer, intent(in) :: ixi^l, ixo^l
8279 double precision, intent(in) :: w(ixi^s,1:nw)
8280 double precision, intent(in) :: x(ixi^s,1:ndim)
8281 double precision, intent(out) :: fe(ixi^s,sdim:3)
8282
8283 double precision :: jxbxb(ixi^s,1:3)
8284 integer :: idir,ixa^l,ixc^l,ix^d
8285
8286 ixa^l=ixo^l^ladd1;
8287 call mhd_get_jxbxb(w,x,ixi^l,ixa^l,jxbxb)
8288 ! calculate electric field on cell edges from cell centers
8289 do idir=sdim,3
8290 ! set ambipolar electric field in jxbxb: E=nuA * jxbxb, where nuA=-etaA/rho^2
8291 ! E_ambi(ixA^S,i) = -(mhd_eta_ambi/w(ixA^S, rho_)**2) * jxbxb(ixA^S,i)
8292 call multiplyambicoef(ixi^l,ixa^l,jxbxb(ixi^s,idir),w,x)
8293 ixcmax^d=ixomax^d;
8294 ixcmin^d=ixomin^d+kr(idir,^d)-1;
8295 fe(ixc^s,idir)=0.d0
8296 {do ix^db=0,1\}
8297 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
8298 ixamin^d=ixcmin^d+ix^d;
8299 ixamax^d=ixcmax^d+ix^d;
8300 fe(ixc^s,idir)=fe(ixc^s,idir)+jxbxb(ixa^s,idir)
8301 {end do\}
8302 fe(ixc^s,idir)=fe(ixc^s,idir)*0.25d0
8303 end do
8304
8305 end subroutine get_ambipolar_electric_field
8306
8307 !> calculate cell-center values from face-center values
8308 subroutine mhd_face_to_center(ixO^L,s)
8310 ! Non-staggered interpolation range
8311 integer, intent(in) :: ixo^l
8312 type(state) :: s
8313
8314 integer :: ix^d
8315
8316 ! calculate cell-center values from face-center values in 2nd order
8317 ! because the staggered arrays have an additional place to the left.
8318 ! Interpolate to cell barycentre using arithmetic average
8319 ! This might be done better later, to make the method less diffusive.
8320 {!dir$ ivdep
8321 do ix^db=ixomin^db,ixomax^db\}
8322 {^ifthreed
8323 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8324 +s%ws(ix1-1,ix2,ix3,1)*s%surfaceC(ix1-1,ix2,ix3,1))
8325 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8326 +s%ws(ix1,ix2-1,ix3,2)*s%surfaceC(ix1,ix2-1,ix3,2))
8327 s%w(ix^d,b3_)=half/s%surface(ix^d,3)*(s%ws(ix^d,3)*s%surfaceC(ix^d,3)&
8328 +s%ws(ix1,ix2,ix3-1,3)*s%surfaceC(ix1,ix2,ix3-1,3))
8329 }
8330 {^iftwod
8331 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
8332 +s%ws(ix1-1,ix2,1)*s%surfaceC(ix1-1,ix2,1))
8333 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
8334 +s%ws(ix1,ix2-1,2)*s%surfaceC(ix1,ix2-1,2))
8335 }
8336 {end do\}
8337
8338 ! calculate cell-center values from face-center values in 4th order
8339 !do idim=1,ndim
8340 ! gxO^L=ixO^L-2*kr(idim,^D);
8341 ! hxO^L=ixO^L-kr(idim,^D);
8342 ! jxO^L=ixO^L+kr(idim,^D);
8343
8344 ! ! Interpolate to cell barycentre using fourth order central formula
8345 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
8346 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8347 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8348 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8349 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
8350 !end do
8351
8352 ! calculate cell-center values from face-center values in 6th order
8353 !do idim=1,ndim
8354 ! fxO^L=ixO^L-3*kr(idim,^D);
8355 ! gxO^L=ixO^L-2*kr(idim,^D);
8356 ! hxO^L=ixO^L-kr(idim,^D);
8357 ! jxO^L=ixO^L+kr(idim,^D);
8358 ! kxO^L=ixO^L+2*kr(idim,^D);
8359
8360 ! ! Interpolate to cell barycentre using sixth order central formula
8361 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
8362 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
8363 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
8364 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
8365 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
8366 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
8367 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
8368 !end do
8369
8370 end subroutine mhd_face_to_center
8371
8372 !> calculate magnetic field from vector potential
8373 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
8376
8377 integer, intent(in) :: ixis^l, ixi^l, ixo^l
8378 double precision, intent(inout) :: ws(ixis^s,1:nws)
8379 double precision, intent(in) :: x(ixi^s,1:ndim)
8380
8381 double precision :: adummy(ixis^s,1:3)
8382
8383 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
8384
8385 end subroutine b_from_vector_potential
8386
8387 subroutine rfactor_from_temperature_ionization(w,x,ixI^L,ixO^L,Rfactor)
8390 integer, intent(in) :: ixi^l, ixo^l
8391 double precision, intent(in) :: w(ixi^s,1:nw)
8392 double precision, intent(in) :: x(ixi^s,1:ndim)
8393 double precision, intent(out):: rfactor(ixi^s)
8394
8395 double precision :: iz_h(ixo^s),iz_he(ixo^s)
8396
8397 call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,te_),iz_h,iz_he)
8398 ! assume the first and second ionization of Helium have the same degree
8399 rfactor(ixo^s)=(1.d0+iz_h(ixo^s)+0.1d0*(1.d0+iz_he(ixo^s)*(1.d0+iz_he(ixo^s))))/(2.d0+3.d0*he_abundance)
8400
8401 end subroutine rfactor_from_temperature_ionization
8402
8403 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
8405 integer, intent(in) :: ixi^l, ixo^l
8406 double precision, intent(in) :: w(ixi^s,1:nw)
8407 double precision, intent(in) :: x(ixi^s,1:ndim)
8408 double precision, intent(out):: rfactor(ixi^s)
8409
8410 rfactor(ixo^s)=rr
8411
8412 end subroutine rfactor_from_constant_ionization
8413end module mod_mhd_phys
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
subroutine cak_init(phys_gamma)
Initialize the module.
subroutine cak_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Check time step for total radiation contribution.
subroutine cak_add_source(qdt, ixil, ixol, wct, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter bigdouble
A very large real number.
subroutine reconstruct(ixil, ixcl, idir, q, ql, qr)
Reconstruct scalar q within ixO^L to 1/2 dx in direction idir Return both left and right reconstructe...
subroutine b_from_vector_potentiala(ixisl, ixil, ixol, ws, x, a)
calculate magnetic field from vector potential A at cell edges
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition mod_convert.t:59
Module for flux conservation near refinement boundaries.
subroutine, public store_flux(igrid, fc, idimlim, nwfluxin)
subroutine, public store_edge(igrid, ixil, fe, idimlim)
Module for flux limited diffusion (FLD)-approximation in Radiation-(Magneto)hydrodynamics simulations...
Definition mod_fld.t:13
logical fld_no_mg
Definition mod_fld.t:29
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure)
Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
Definition mod_fld.t:477
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:23
double precision, public fld_diff_tol
Tolerance for radiative Energy diffusion.
Definition mod_fld.t:25
double precision, public fld_gamma
A copy of (m)hd_gamma.
Definition mod_fld.t:42
character(len=40) fld_fluxlimiter
flux limiter choice
Definition mod_fld.t:34
character(len=40) fld_opal_table
Definition mod_fld.t:32
double precision, public fld_kappa0
Opacity value when using constant opacity.
Definition mod_fld.t:20
character(len=40) fld_opacity_law
switches for opacity
Definition mod_fld.t:31
character(len=40) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
Definition mod_fld.t:40
subroutine, public add_fld_rad_force(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
Definition mod_fld.t:189
logical fld_radforce_split
source split for energy interact and radforce:
Definition mod_fld.t:18
subroutine, public fld_init(r_gamma)
Initialising FLD-module Read opacities Initialise Multigrid and adimensionalise kappa.
Definition mod_fld.t:81
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x)
get dt limit for radiation force and FLD explicit source additions NOTE: w is primitive on entry
Definition mod_fld.t:345
integer nth_for_diff_mg
diffusion coefficient stencil control
Definition mod_fld.t:38
Module with basic grid data structures.
Definition mod_forest.t:2
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition mod_forest.t:32
subroutine, public get_divb(w, ixil, ixol, divb, nth_in)
Calculate div B within ixO.
integer, dimension(:), allocatable, public mag
Indices of the magnetic field.
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
integer coordinate
Definition mod_geometry.t:7
subroutine laplacian_of_vector(qvec, ixil, ixol, lapl_qvec)
integer, parameter cylindrical
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
subroutine gradientf(q, x, ixil, ixol, idir, gradq, nth_in, pm_in)
subroutine gradientl(q, ixil, ixol, idir, gradq)
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
double precision arad_norm
Normalised radiation constant.
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
double precision unit_charge
Physical scaling factor for charge.
integer ixghi
Upper index of grid block arrays.
pure subroutine cross_product(ixil, ixol, a, b, axb)
Cross product of two vectors.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
double precision unit_time
Physical scaling factor for time.
double precision unit_density
Physical scaling factor for density.
double precision unit_opacity
Physical scaling factor for Opacity.
integer, parameter unitpar
file handle for IO
double precision unit_mass
Physical scaling factor for mass.
logical use_imex_scheme
whether IMEX in use or not
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
double precision unit_numberdensity
Physical scaling factor for number density.
character(len=std_len) convert_type
Which format to use when converting.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
logical stagger_grid
True for using stagger grid.
double precision const_rad_a
Physical factors useful for radiation fld.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
double precision bdip
amplitude of background dipolar, quadrupolar, octupolar, user's field
integer b0i
background magnetic field location indicator
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
logical local_timestep
each cell has its own timestep or not
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
integer nwauxio
Number of auxiliary variables that are only included in output.
double precision unit_velocity
Physical scaling factor for velocity.
double precision c_norm
Normalised speed of light.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision unit_radflux
Physical scaling factor for radiation flux.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter sdim
starting dimension for electric field
logical phys_trac
Use TRAC for MHD or 1D HD.
logical need_global_cmax
need global maximal wave speed
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical use_multigrid
Use multigrid (only available in 2D and 3D)
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer max_blocks
The maximum number of grid blocks in a processor.
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
integer, parameter unitconvert
double precision unit_erad
Physical scaling factor for radiation energy density.
integer number_equi_vars
number of equilibrium set variables, besides the mag field
integer, parameter ixglo
Lower index of grid block arrays (always 1)
Module for including gravity in (magneto)hydrodynamics simulations.
Definition mod_gravity.t:2
subroutine gravity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Definition mod_gravity.t:81
subroutine gravity_init()
Initialize the module.
Definition mod_gravity.t:26
subroutine gravity_add_source(qdt, ixil, ixol, wct, wctprim, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
Definition mod_gravity.t:43
module ionization degree - get ionization degree for given temperature
subroutine ionization_degree_from_temperature(ixil, ixol, te, iz_h, iz_he)
module mod_magnetofriction.t Purpose: use magnetofrictional method to relax 3D magnetic field to forc...
subroutine magnetofriction_init()
Initialize the module.
Magneto-hydrodynamics module.
Definition mod_mhd_phys.t:2
subroutine, public mhd_get_trad(w, x, ixil, ixol, trad)
Calculates radiation temperature.
integer, public, protected c_
logical, public, protected mhd_gravity
Whether gravity is added.
logical, public, protected mhd_internal_e
Whether internal energy is solved instead of total energy.
logical, public, protected mhd_glm_extended
Whether extended GLM-MHD is used with additional sources.
character(len=std_len), public, protected type_ct
Method type of constrained transport.
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
subroutine, public mhd_clean_divb_multigrid(qdt, qt, active)
logical, public, protected mhd_hyperbolic_thermal_conduction
Whether thermal conduction is used.
logical, public, protected mhd_radiative_cooling
Whether radiative cooling is added.
subroutine, public mhd_e_to_ei(ixil, ixol, w, x)
Transform total energy to internal energy.
double precision, public mhd_adiab
The adiabatic constant.
logical, public, protected mhd_partial_ionization
Whether plasma is partially ionized.
double precision, public divbdiff
Coefficient of diffusive divB cleaning.
double precision, public mhd_eta_hyper
The MHD hyper-resistivity.
subroutine, public mhd_get_temperature_from_prim(w, x, ixil, ixol, res)
Calculate temperature=p/rho when in e_ the pressure p_ (primitive) is stored.
double precision, public, protected rr
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
double precision, public mhd_gamma
The adiabatic index.
integer, public, protected mhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
subroutine, public get_normalized_divb(w, ixil, ixol, divb)
get dimensionless div B = |divB| * volume / area / |B|
logical, public numerical_resistive_heating
Whether numerical resistive heating is included when solving partial energy equation.
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
logical, public, protected mhd_rotating_frame
Whether rotating frame is activated.
logical, public, protected mhd_semirelativistic
Whether semirelativistic MHD equations (Gombosi 2002 JCP) are solved.
integer, public, protected mhd_divb_nth
Whether divB is computed with a fourth order approximation.
integer, public, protected q_
Index of the heat flux q.
integer, public, protected mhd_n_tracer
Number of tracer species.
integer, public, protected te_
Indices of temperature.
integer, public, protected m
integer, public equi_rho0_
equi vars indices in the stateequi_vars array
integer, public, protected mhd_trac_type
Which TRAC method is used.
logical, public, protected mhd_cak_force
Whether CAK radiation line force is activated.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
logical, public, protected mhd_hall
Whether Hall-MHD is used.
type(te_fluid), allocatable, public te_fl_mhd
type of fluid for thermal emission synthesis
logical, public, protected mhd_ambipolar
Whether Ambipolar term is used.
double precision, public hypertc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
logical, public has_equi_rho_and_p
whether split off equilibrium density and pressure
double precision, public mhd_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
double precision function, dimension(ixo^s), public mhd_mag_en_all(w, ixil, ixol)
Compute 2 times total magnetic energy.
logical, public, protected mhd_radiation_fld
Whether radiation-gas interaction is handled using flux limited diffusion.
subroutine, public multiplyambicoef(ixil, ixol, res, w, x)
multiply res by the ambipolar coefficient The ambipolar coefficient is calculated as -mhd_eta_ambi/rh...
subroutine, public b_from_vector_potential(ixisl, ixil, ixol, ws, x)
calculate magnetic field from vector potential
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
logical, public, protected mhd_viscosity
Whether viscosity is added.
procedure(sub_get_pthermal), pointer, public mhd_get_rfactor
subroutine, public mhd_get_pradiation_from_prim(w, x, ixil, ixol, prad)
Calculate radiation pressure within ixO^L.
double precision, public, protected mhd_reduced_c
Reduced speed of light for semirelativistic MHD: 2% of light speed.
logical, public, protected mhd_energy
Whether an energy equation is used.
logical, public, protected mhd_ambipolar_exp
Whether Ambipolar term is implemented explicitly.
logical, public, protected mhd_htc_sat
Whether saturation is considered for hyperbolic TC.
logical, public, protected mhd_glm
Whether GLM-MHD is used to control div B.
logical, public clean_initial_divb
clean initial divB
procedure(sub_convert), pointer, public mhd_to_conserved
double precision, public mhd_eta
The MHD resistivity.
logical, public divbwave
Add divB wave in Roe solver.
logical, public, protected mhd_magnetofriction
Whether magnetofriction is added.
double precision, public, protected mhd_trac_mask
Height of the mask used in the TRAC method.
procedure(mask_subroutine), pointer, public usr_mask_ambipolar
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
subroutine, public mhd_get_temperature_from_etot(w, x, ixil, ixol, res)
Calculate temperature=p/rho from total energy.
logical, public, protected mhd_thermal_conduction
Whether thermal conduction is used.
procedure(sub_get_pthermal), pointer, public mhd_get_temperature
integer, public equi_pe0_
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 p_
Index of the gas pressure (-1 if not present) should equal e_.
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
procedure(sub_convert), pointer, public mhd_to_primitive
logical, public, protected mhd_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
logical, public, protected mhd_particles
Whether particles module is added.
integer, public, protected b
subroutine, public mhd_face_to_center(ixol, s)
calculate cell-center values from face-center values
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
subroutine, public get_current(w, ixil, ixol, idirmin, current)
Calculate idirmin and the idirmin:3 components of the common current array make sure that dxlevel(^D)...
double precision, public mhd_etah
Hall resistivity.
subroutine, public mhd_get_v(w, x, ixil, ixol, v)
Calculate v vector.
double precision, public mhd_eta_ambi
The MHD ambipolar coefficient.
logical, public, protected mhd_hydrodynamic_e
Whether hydrodynamic energy is solved instead of total energy.
integer, public, protected r_e
Index of the radiation energy.
subroutine, public mhd_phys_init()
logical, public, protected mhd_trac
Whether TRAC method is used.
logical, public, protected eq_state_units
subroutine, public mhd_get_csrad2(w, x, ixil, ixol, csound)
Calculate modified squared sound speed for FLD NOTE: only for diagnostic purposes,...
subroutine, public mhd_get_pthermal_plus_pradiation(w, x, ixil, ixol, pth_plus_prad)
Calculates the sum of the gas pressure and the max Prad tensor element.
type(rc_fluid), allocatable, public rc_fl
type of fluid for radiative cooling
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
integer, public, protected rho_
Index of the density (in the w array)
logical, public, protected b0field_forcefree
B0 field is force-free.
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
integer, public, protected tweight_
logical, public, protected mhd_ambipolar_sts
Whether Ambipolar term is implemented using supertimestepping.
procedure(sub_get_pthermal), pointer, public mhd_get_pthermal
subroutine, public mhd_ei_to_e(ixil, ixol, w, x)
Transform internal energy to total energy.
integer, public, protected e_
Index of the energy density (-1 if not present)
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
subroutine, public mhd_get_rho(w, x, ixil, ixol, rho)
integer, public, protected psi_
Indices of the GLM psi.
logical, public mhd_equi_thermal
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
Module containing all the particle routines.
subroutine particles_init()
Initialize particle data and parameters.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
Module for including rotating frame in (magneto)hydrodynamics simulations The rotation vector is assu...
subroutine rotating_frame_add_source(qdt, dtfactor, ixil, ixol, wct, w, x)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine rotating_frame_init()
Initialize the module.
Module for handling problematic values in simulations, such as negative pressures.
subroutine, public small_values_average(ixil, ixol, w, x, w_flag, windex)
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
subroutine, public small_values_error(wprim, x, ixil, ixol, w_flag, subname)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method which can be used for multiple source terms in the governing equatio...
subroutine, public add_sts_method(sts_getdt, sts_set_sources, startvar, nflux, startwbc, nwbc, evolve_b)
subroutine which added programatically a term to be calculated using STS Params: sts_getdt function c...
subroutine, public set_conversion_methods_to_head(sts_before_first_cycle, sts_after_last_cycle)
Set the hooks called before the first cycle and after the last cycle in the STS update This method sh...
subroutine, public set_error_handling_to_head(sts_error_handling)
Set the hook of error handling in the STS update. This method is called before updating the BC....
subroutine, public sts_init()
Initialize sts module.
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
double precision function, public get_tc_dt_mhd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation) Note: also used in 1D MHD (or for neutrals i...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_hd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_adiab), pointer usr_set_adiab
procedure(set_adiab), pointer usr_set_gamma
procedure(phys_gravity), pointer usr_gravity
procedure(set_equi_vars), pointer usr_set_equi_vars
procedure(set_electric_field), pointer usr_set_electric_field
The module add viscous source terms and check time step.
subroutine, public viscosity_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
procedure(sub_add_source), pointer, public viscosity_add_source
subroutine, public viscosity_init(phys_wider_stencil)
Initialize the module.
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11