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