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