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