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