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