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