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