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