MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_rmhd_phys.t
Go to the documentation of this file.
1!> Radiation-magneto-hydrodynamics module
3
4#include "amrvac.h"
5
6 use mod_global_parameters, only: std_len, const_c
10 use mod_comm_lib, only: mpistop
12
13 implicit none
14 private
15
16 !> The adiabatic index
17 double precision, public :: rmhd_gamma = 5.d0/3.0d0
18 !> The adiabatic constant
19 double precision, public :: rmhd_adiab = 1.0d0
20 !> The MHD resistivity
21 double precision, public :: rmhd_eta = 0.0d0
22 !> The MHD hyper-resistivity
23 double precision, public :: rmhd_eta_hyper = 0.0d0
24 !> Hall resistivity
25 double precision, public :: rmhd_etah = 0.0d0
26 !> The small_est allowed energy
27 double precision, protected :: small_e
28 !> The smallest allowed radiation energy
29 double precision, public, protected :: small_r_e = 0.d0
30 !> Height of the mask used in the TRAC method
31 double precision, public, protected :: rmhd_trac_mask = 0.d0
32 !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
33 !> taking values within [0, 1]
34 double precision, public :: rmhd_glm_alpha = 0.5d0
35 !> The thermal conductivity kappa in hyperbolic thermal conduction
36 double precision, public :: hypertc_kappa
37 !> Coefficient of diffusive divB cleaning
38 double precision :: divbdiff = 0.8d0
39 !> Helium abundance over Hydrogen
40 double precision, public, protected :: he_abundance=0.1d0
41 !> Ionization fraction of H
42 !> H_ion_fr = H+/(H+ + H)
43 double precision, public, protected :: h_ion_fr=1d0
44 !> Ionization fraction of He
45 !> He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
46 double precision, public, protected :: he_ion_fr=1d0
47 !> Ratio of number He2+ / number He+ + He2+
48 !> He_ion_fr2 = He2+/(He2+ + He+)
49 double precision, public, protected :: he_ion_fr2=1d0
50 ! used for eq of state when it is not defined by units,
51 ! the units do not contain terms related to ionization fraction
52 ! and it is p = RR * rho * T
53 double precision, public, protected :: rr=1d0
54 !> gamma minus one and its inverse
55 double precision :: gamma_1, inv_gamma_1
56 !> inverse of squared speed of light c0 and reduced speed of light c
57 double precision :: inv_squared_c0, inv_squared_c
58 !> equi vars indices in the state%equi_vars array
59 integer, public :: equi_rho0_ = -1
60 integer, public :: equi_pe0_ = -1
61 !> Number of tracer species
62 integer, public, protected :: rmhd_n_tracer = 0
63 !> Index of the density (in the w array)
64 integer, public, protected :: rho_
65 !> Indices of the momentum density
66 integer, allocatable, public, protected :: mom(:)
67 !> Indices of the momentum density for the form of better vectorization
68 integer, public, protected :: ^c&m^C_
69 !> Index of the energy density (-1 if not present)
70 integer, public, protected :: e_
71 !> Index of the radiation energy
72 integer, public, protected :: r_e
73 !> Indices of the magnetic field for the form of better vectorization
74 integer, public, protected :: ^c&b^C_
75 !> Index of the gas pressure (-1 if not present) should equal e_
76 integer, public, protected :: p_
77 !> Index of the heat flux q
78 integer, public, protected :: q_
79 !> Indices of the GLM psi
80 integer, public, protected :: psi_
81 !> Indices of temperature
82 integer, public, protected :: te_
83 !> Index of the cutoff temperature for the TRAC method
84 integer, public, protected :: tcoff_
85 integer, public, protected :: tweight_
86 !> Indices of the tracers
87 integer, allocatable, public, protected :: tracer(:)
88 !> The number of waves
89 integer :: nwwave=8
90 !> Method type in a integer for good performance
91 integer :: type_divb
92 !> To skip * layer of ghost cells during divB=0 fix for boundary
93 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
94 ! DivB cleaning methods
95 integer, parameter :: divb_none = 0
96 integer, parameter :: divb_multigrid = -1
97 integer, parameter :: divb_glm = 1
98 integer, parameter :: divb_powel = 2
99 integer, parameter :: divb_janhunen = 3
100 integer, parameter :: divb_linde = 4
101 integer, parameter :: divb_lindejanhunen = 5
102 integer, parameter :: divb_lindepowel = 6
103 integer, parameter :: divb_lindeglm = 7
104 integer, parameter :: divb_ct = 8
105 !> Whether an energy equation is used
106 logical, public, protected :: rmhd_energy = .true.
107 !> Whether thermal conduction is used
108 logical, public, protected :: rmhd_thermal_conduction = .false.
109 !> Whether thermal conduction is used
110 logical, public, protected :: rmhd_hyperbolic_thermal_conduction = .false.
111 !> Whether viscosity is added
112 logical, public, protected :: rmhd_viscosity = .false.
113 !> Whether gravity is added
114 logical, public, protected :: rmhd_gravity = .false.
115 !> Whether particles module is added
116 logical, public, protected :: rmhd_particles = .false.
117 !> Whether GLM-MHD is used to control div B
118 logical, public, protected :: rmhd_glm = .false.
119 !> Whether extended GLM-MHD is used with additional sources
120 logical, public, protected :: rmhd_glm_extended = .true.
121 !> Whether TRAC method is used
122 logical, public, protected :: rmhd_trac = .false.
123 !> Which TRAC method is used
124 integer, public, protected :: rmhd_trac_type=1
125 !> Distance between two adjacent traced magnetic field lines (in finest cell size)
126 integer, public, protected :: rmhd_trac_finegrid=4
127 !> Whether divB cleaning sources are added splitting from fluid solver
128 logical, public, protected :: source_split_divb = .false.
129 !> Whether plasma is partially ionized
130 logical, public, protected :: rmhd_partial_ionization = .false.
131 !> Whether CAK radiation line force is activated
132 logical, public, protected :: rmhd_cak_force = .false.
133 !> whether split off equilibrium density
134 logical, public :: has_equi_rho0 = .false.
135 !> whether split off equilibrium thermal pressure
136 logical, public :: has_equi_pe0 = .false.
137 logical, public :: rmhd_equi_thermal = .false.
138 !> whether dump full variables (when splitting is used) in a separate dat file
139 logical, public, protected :: rmhd_dump_full_vars = .false.
140 !> Whether divB is computed with a fourth order approximation
141 integer, public, protected :: rmhd_divb_nth = 1
142 !> Use a compact way to add resistivity
143 logical :: compactres = .false.
144 !> Add divB wave in Roe solver
145 logical, public :: divbwave = .true.
146 !> clean initial divB
147 logical, public :: clean_initial_divb = .false.
148 !> Formalism to treat radiation
149 character(len=8), public :: rmhd_radiation_formalism = 'fld'
150 !> In the case of no rmhd_energy, how to compute pressure
151 character(len=8), public :: rmhd_pressure = 'Trad'
152 !> Treat radiation fld_Rad_force
153 logical, public, protected :: rmhd_radiation_force = .true.
154 !> Treat radiation-gas energy interaction
155 logical, public, protected :: rmhd_energy_interact = .true.
156 !> Treat radiation energy diffusion
157 logical, public, protected :: rmhd_radiation_diffusion = .true.
158 !> Treat radiation advection
159 logical, public, protected :: rmhd_radiation_advection = .true.
160 !> Do a running mean over the radiation pressure when determining dt
161 logical, protected :: radio_acoustic_filter = .false.
162 integer, protected :: size_ra_filter = 1
163 !> kb/(m_p mu)* 1/a_rad**4,
164 double precision, public :: kbmpmua4
165 !> Use the speed of light to calculate the timestep, usefull for debugging
166 logical :: dt_c = .false.
167 ! remove the below flag and assume default value = .false.
168 ! when eq state properly implemented everywhere
169 ! and not anymore through units
170 logical, public, protected :: eq_state_units = .true.
171 !> To control divB=0 fix for boundary
172 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
173 !> B0 field is force-free
174 logical, public, protected :: b0field_forcefree=.true.
175 !> Whether an total energy equation is used
176 logical :: total_energy = .true.
177 !> Whether an internal or hydrodynamic energy equation is used
178 logical, public :: partial_energy = .false.
179 !> Whether gravity work is included in energy equation
180 logical :: gravity_energy
181 !> Method type to clean divergence of B
182 character(len=std_len), public, protected :: typedivbfix = 'linde'
183 !> Method type of constrained transport
184 character(len=std_len), public, protected :: type_ct = 'uct_contact'
185 !> Update all equations due to divB cleaning
186 character(len=std_len) :: typedivbdiff = 'all'
187 !> type of fluid for thermal conduction
188 type(tc_fluid), public, allocatable :: tc_fl
189 !> type of fluid for thermal emission synthesis
190 type(te_fluid), public, allocatable :: te_fl_rmhd
191
192 procedure(sub_convert), pointer :: rmhd_to_primitive => null()
193 procedure(sub_convert), pointer :: rmhd_to_conserved => null()
194 procedure(sub_small_values), pointer :: rmhd_handle_small_values => null()
195 procedure(sub_get_pthermal), pointer :: rmhd_get_pthermal => null()
196 procedure(sub_get_pthermal), pointer :: rmhd_get_rfactor => null()
197 procedure(sub_get_pthermal), pointer :: rmhd_get_temperature=> null()
198 ! Public methods
199 public :: rmhd_phys_init
200 public :: rmhd_get_pthermal
201 public :: rmhd_get_temperature
202 public :: rmhd_get_v
203 public :: rmhd_get_rho
204 public :: rmhd_to_conserved
205 public :: rmhd_to_primitive
206 public :: rmhd_e_to_ei
207 public :: rmhd_ei_to_e
208 public :: rmhd_face_to_center
209 public :: get_divb
210 public :: get_current
211 public :: get_normalized_divb
213 public :: rmhd_mag_en_all
214 {^nooned
216 }
217 public :: rmhd_get_pradiation
219 public :: rmhd_get_tgas
220 public :: rmhd_get_trad
221 public :: rmhd_set_mg_bounds
222
223contains
224
225 !> Read this module"s parameters from a file
226 subroutine rmhd_read_params(files)
228 use mod_particles, only: particles_eta, particles_etah
229 character(len=*), intent(in) :: files(:)
230 integer :: n
231
232 namelist /rmhd_list/ rmhd_energy, rmhd_n_tracer, rmhd_gamma, rmhd_adiab,&
236 typedivbdiff, type_ct, compactres, divbwave, he_abundance,&
239 particles_eta, particles_etah,has_equi_rho0, has_equi_pe0,rmhd_equi_thermal,&
245 rmhd_radiation_advection, radio_acoustic_filter, size_ra_filter, dt_c
246
247 do n = 1, size(files)
248 open(unitpar, file=trim(files(n)), status="old")
249 read(unitpar, rmhd_list, end=111)
250111 close(unitpar)
251 end do
252
253 end subroutine rmhd_read_params
254
255 !> Write this module's parameters to a snapsoht
256 subroutine rmhd_write_info(fh)
258 integer, intent(in) :: fh
259 integer :: er
260 integer, parameter :: n_par = 1
261 double precision :: values(n_par)
262 integer, dimension(MPI_STATUS_SIZE) :: st
263 character(len=name_len) :: names(n_par)
264
265 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
266
267 names(1) = "gamma"
268 values(1) = rmhd_gamma
269 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
270 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
271 end subroutine rmhd_write_info
272
273 subroutine rmhd_phys_init()
277 use mod_gravity, only: gravity_init
278 use mod_particles, only: particles_init, particles_eta, particles_etah
279 use mod_fld
280 use mod_afld
283 use mod_cak_force, only: cak_init
286 {^nooned
288 }
289
290 integer :: itr, idir
291
292 call rmhd_read_params(par_files)
293
294 if(.not.eq_state_units) then
297 if(mype==0) write(*,*) 'WARNING: set rmhd_partial_ionization=F when eq_state_units=F'
298 end if
299 end if
300
303 if(mype==0) write(*,*) 'WARNING: turn off parabolic TC when using hyperbolic TC'
304 end if
305
306 physics_type = "rmhd"
307 phys_energy=rmhd_energy
310 phys_partial_ionization=rmhd_partial_ionization
311
312 phys_gamma = rmhd_gamma
314
315 if(rmhd_energy) then
316 partial_energy=.false.
317 total_energy=.true.
318 else
319 total_energy=.false.
320 end if
321 phys_total_energy=total_energy
322 if(rmhd_energy) then
323 gravity_energy=.true.
324 else
325 gravity_energy=.false.
326 end if
327
328 {^ifoned
329 if(rmhd_trac .and. rmhd_trac_type .gt. 2) then
331 if(mype==0) write(*,*) 'WARNING: reset rmhd_trac_type=1 for 1D simulation'
332 end if
333 }
334 if(rmhd_trac .and. rmhd_trac_type .le. 4) then
335 rmhd_trac_mask=bigdouble
336 if(mype==0) write(*,*) 'WARNING: set rmhd_trac_mask==bigdouble for global TRAC method'
337 end if
339
340 ! set default gamma for polytropic/isothermal process
342 if(ndim==1) typedivbfix='none'
343 select case (typedivbfix)
344 case ('none')
345 type_divb = divb_none
346 {^nooned
347 case ('multigrid')
348 type_divb = divb_multigrid
349 use_multigrid = .true.
350 mg%operator_type = mg_laplacian
351 phys_global_source_after => rmhd_clean_divb_multigrid
352 }
353 case ('glm')
354 rmhd_glm = .true.
355 need_global_cmax = .true.
356 type_divb = divb_glm
357 case ('powel', 'powell')
358 type_divb = divb_powel
359 case ('janhunen')
360 type_divb = divb_janhunen
361 case ('linde')
362 type_divb = divb_linde
363 case ('lindejanhunen')
364 type_divb = divb_lindejanhunen
365 case ('lindepowel')
366 type_divb = divb_lindepowel
367 case ('lindeglm')
368 rmhd_glm = .true.
369 need_global_cmax = .true.
370 type_divb = divb_lindeglm
371 case ('ct')
372 type_divb = divb_ct
373 stagger_grid = .true.
374 case default
375 call mpistop('Unknown divB fix')
376 end select
377
378 allocate(start_indices(number_species),stop_indices(number_species))
379 ! set the index of the first flux variable for species 1
380 start_indices(1)=1
381 ! Determine flux variables
382 rho_ = var_set_rho()
383
384 allocate(mom(ndir))
385 mom(:) = var_set_momentum(ndir)
386 m^c_=mom(^c);
387
388 ! Set index of energy variable
389 if (rmhd_energy) then
390 nwwave = 8
391 e_ = var_set_energy() ! energy density
392 p_ = e_ ! gas pressure
393 else
394 nwwave = 7
395 e_ = -1
396 p_ = -1
397 end if
398
399 allocate(mag(ndir))
400 mag(:) = var_set_bfield(ndir)
401 b^c_=mag(^c);
402
403 if (rmhd_glm) then
404 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
405 else
406 psi_ = -1
407 end if
408
409 !> set radiation energy
410 r_e = var_set_radiation_energy()
411
413 ! hyperbolic thermal conduction flux q
414 q_ = var_set_q()
415 need_global_cmax=.true.
416 else
417 q_=-1
418 end if
419
420 allocate(tracer(rmhd_n_tracer))
421 ! Set starting index of tracers
422 do itr = 1, rmhd_n_tracer
423 tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
424 end do
425
426 ! set temperature as an auxiliary variable to get ionization degree
428 te_ = var_set_auxvar('Te','Te')
429 else
430 te_ = -1
431 end if
432
433 ! set number of variables which need update ghostcells
434 nwgc=nwflux+nwaux
435
436 ! set the index of the last flux variable for species 1
437 stop_indices(1)=nwflux
438
439 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
440 tweight_ = -1
441 if(rmhd_trac) then
442 tcoff_ = var_set_wextra()
443 iw_tcoff=tcoff_
444 if(rmhd_trac_type .ge. 3) then
445 tweight_ = var_set_wextra()
446 endif
447 else
448 tcoff_ = -1
449 end if
450
451 ! set indices of equi vars and update number_equi_vars
453 if(has_equi_rho0) then
456 iw_equi_rho = equi_rho0_
457 endif
458 if(has_equi_pe0) then
461 iw_equi_p = equi_pe0_
462 endif
463 ! determine number of stagger variables
464 nws=ndim
465
466 nvector = 2 ! No. vector vars
467 allocate(iw_vector(nvector))
468 iw_vector(1) = mom(1) - 1 ! TODO: why like this?
469 iw_vector(2) = mag(1) - 1 ! TODO: why like this?
470
471 ! Check whether custom flux types have been defined
472 if (.not. allocated(flux_type)) then
473 allocate(flux_type(ndir, nwflux))
474 flux_type = flux_default
475 else if (any(shape(flux_type) /= [ndir, nwflux])) then
476 call mpistop("phys_check error: flux_type has wrong shape")
477 end if
478
479 if(nwflux>mag(ndir)) then
480 ! for flux of tracers, using hll flux
481 flux_type(:,mag(ndir)+1:nwflux)=flux_hll
482 end if
483
484 if(ndim>1) then
485 if(rmhd_glm) then
486 flux_type(:,psi_)=flux_special
487 do idir=1,ndir
488 flux_type(idir,mag(idir))=flux_special
489 end do
490 else
491 do idir=1,ndir
492 flux_type(idir,mag(idir))=flux_tvdlf
493 end do
494 end if
495 end if
496
497 phys_get_rho => rmhd_get_rho
498 phys_get_dt => rmhd_get_dt
499 phys_get_cmax => rmhd_get_cmax_origin
500 phys_get_tcutoff => rmhd_get_tcutoff
501 phys_get_h_speed => rmhd_get_h_speed
502 if(has_equi_rho0) then
503 phys_get_cbounds => rmhd_get_cbounds_split_rho
504 else
505 phys_get_cbounds => rmhd_get_cbounds
506 end if
507 if(has_equi_rho0) then
508 phys_to_primitive => rmhd_to_primitive_split_rho
509 rmhd_to_primitive => rmhd_to_primitive_split_rho
510 phys_to_conserved => rmhd_to_conserved_split_rho
511 rmhd_to_conserved => rmhd_to_conserved_split_rho
512 else
513 phys_to_primitive => rmhd_to_primitive_origin
514 rmhd_to_primitive => rmhd_to_primitive_origin
515 phys_to_conserved => rmhd_to_conserved_origin
516 rmhd_to_conserved => rmhd_to_conserved_origin
517 end if
518 if(b0field.or.has_equi_rho0.or.has_equi_pe0) then
519 phys_get_flux => rmhd_get_flux_split
520 else
521 phys_get_flux => rmhd_get_flux
522 end if
523 phys_get_v => rmhd_get_v
524 if(b0field.or.has_equi_rho0) then
525 phys_add_source_geom => rmhd_add_source_geom_split
526 else
527 phys_add_source_geom => rmhd_add_source_geom
528 end if
529 phys_add_source => rmhd_add_source
530 phys_check_params => rmhd_check_params
531 phys_write_info => rmhd_write_info
532
533 phys_handle_small_values => rmhd_handle_small_values_origin
534 rmhd_handle_small_values => rmhd_handle_small_values_origin
535 phys_check_w => rmhd_check_w_origin
536
537 phys_set_mg_bounds => rmhd_set_mg_bounds
538 phys_get_tgas => rmhd_get_tgas
539
540 phys_get_pthermal => rmhd_get_pthermal_origin
541 rmhd_get_pthermal => rmhd_get_pthermal_origin
542
543 if(number_equi_vars>0) then
544 phys_set_equi_vars => set_equi_vars_grid
545 endif
546
547 if(type_divb==divb_glm) then
548 phys_modify_wlr => rmhd_modify_wlr
549 end if
550
551 ! choose Rfactor in ideal gas law
553 rmhd_get_rfactor=>rfactor_from_temperature_ionization
554 phys_update_temperature => rmhd_update_temperature
555 else if(associated(usr_rfactor)) then
556 rmhd_get_rfactor=>usr_rfactor
557 else
558 rmhd_get_rfactor=>rfactor_from_constant_ionization
559 end if
560
562 rmhd_get_temperature => rmhd_get_temperature_from_te
563 else
564 if(has_equi_pe0 .and. has_equi_rho0) then
565 rmhd_get_temperature => rmhd_get_temperature_from_etot_with_equi
566 else
567 rmhd_get_temperature => rmhd_get_temperature_from_etot
568 end if
569 end if
570
571 ! if using ct stagger grid, boundary divb=0 is not done here
572 if(stagger_grid) then
573 select case(type_ct)
574 case('average')
575 transverse_ghost_cells = 1
576 phys_get_ct_velocity => rmhd_get_ct_velocity_average
577 phys_update_faces => rmhd_update_faces_average
578 case('uct_contact')
579 transverse_ghost_cells = 1
580 phys_get_ct_velocity => rmhd_get_ct_velocity_contact
581 phys_update_faces => rmhd_update_faces_contact
582 case('uct_hll')
583 transverse_ghost_cells = 2
584 phys_get_ct_velocity => rmhd_get_ct_velocity_hll
585 phys_update_faces => rmhd_update_faces_hll
586 case default
587 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
588 end select
589 phys_face_to_center => rmhd_face_to_center
590 phys_modify_wlr => rmhd_modify_wlr
591 else if(ndim>1) then
592 phys_boundary_adjust => rmhd_boundary_adjust
593 end if
594
595 {^nooned
596 ! clean initial divb
597 if(clean_initial_divb) phys_clean_divb => rmhd_clean_divb_multigrid
598 }
599
600 ! derive units from basic units
601 call rmhd_physical_units()
602
603 !> Initiate radiation-closure module
604 select case(rmhd_radiation_formalism)
605 case('fld')
607 case('afld')
609 case default
610 call mpistop('Radiation formalism unknown')
611 end select
612
614 if(si_unit)then
615 ! parallel conduction Spitzer
617 else
618 ! in cgs
620 endif
621 end if
622 if(.not. rmhd_energy .and. rmhd_thermal_conduction) then
623 call mpistop("thermal conduction needs rmhd_energy=T")
624 end if
626 call mpistop("hyperbolic thermal conduction needs rmhd_energy=T")
627 end if
628
629 ! initialize thermal conduction module
631 call sts_init()
633
634 allocate(tc_fl)
635 call tc_get_mhd_params(tc_fl,tc_params_read_rmhd)
636 call add_sts_method(rmhd_get_tc_dt_rmhd,rmhd_sts_set_source_tc_rmhd,e_,1,e_,1,.false.)
637 if(has_equi_pe0 .and. has_equi_rho0) then
638 tc_fl%get_temperature_from_conserved => rmhd_get_temperature_from_etot_with_equi
639 else
640 tc_fl%get_temperature_from_conserved => rmhd_get_temperature_from_etot
641 end if
642 if(has_equi_pe0 .and. has_equi_rho0) then
643 tc_fl%get_temperature_from_eint => rmhd_get_temperature_from_eint_with_equi
644 if(rmhd_equi_thermal) then
645 tc_fl%subtract_equi = .true.
646 tc_fl%get_temperature_equi => rmhd_get_temperature_equi
647 tc_fl%get_rho_equi => rmhd_get_rho_equi
648 else
649 tc_fl%subtract_equi = .false.
650 end if
651 else
652 tc_fl%get_temperature_from_eint => rmhd_get_temperature_from_eint
653 end if
655 call set_error_handling_to_head(rmhd_tc_handle_small_e)
656 tc_fl%get_rho => rmhd_get_rho
657 tc_fl%e_ = e_
658 tc_fl%Tcoff_ = tcoff_
659 end if
660
661 allocate(te_fl_rmhd)
662 te_fl_rmhd%get_rho=> rmhd_get_rho
663 te_fl_rmhd%get_pthermal=> rmhd_get_pthermal
664 te_fl_rmhd%get_var_Rfactor => rmhd_get_rfactor
665{^ifthreed
666 phys_te_images => rmhd_te_images
667}
668 ! Initialize viscosity module
669 if (rmhd_viscosity) call viscosity_init(phys_wider_stencil)
670
671 ! Initialize gravity module
672 if(rmhd_gravity) then
673 call gravity_init()
674 end if
675
676 ! Initialize particles module
677 if(rmhd_particles) then
678 call particles_init()
679 if (particles_eta < zero) particles_eta = rmhd_eta
680 if (particles_etah < zero) particles_eta = rmhd_etah
681 if(mype==0) then
682 write(*,*) '*****Using particles: with rmhd_eta, rmhd_etah :', rmhd_eta, rmhd_etah
683 write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
684 end if
685 end if
686
687 ! initialize ionization degree table
689
690 ! Initialize CAK radiation force module
692 end subroutine rmhd_phys_init
693
694{^ifthreed
695 subroutine rmhd_te_images
698
699 select case(convert_type)
700 case('EIvtiCCmpi','EIvtuCCmpi')
702 case('ESvtiCCmpi','ESvtuCCmpi')
704 case('SIvtiCCmpi','SIvtuCCmpi')
706 case('WIvtiCCmpi','WIvtuCCmpi')
708 case default
709 call mpistop("Error in synthesize emission: Unknown convert_type")
710 end select
711 end subroutine rmhd_te_images
712}
713
714!!start th cond
715 ! wrappers for STS functions in thermal_conductivity module
716 ! which take as argument the tc_fluid (defined in the physics module)
717 subroutine rmhd_sts_set_source_tc_rmhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
721 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
722 double precision, intent(in) :: x(ixi^s,1:ndim)
723 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
724 double precision, intent(in) :: my_dt
725 logical, intent(in) :: fix_conserve_at_step
726 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl)
727 end subroutine rmhd_sts_set_source_tc_rmhd
728
729 function rmhd_get_tc_dt_rmhd(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
730 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
731 !where tc_k_para_i=tc_k_para*B_i**2/B**2
732 !and T=p/rho
735 integer, intent(in) :: ixi^l, ixo^l
736 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
737 double precision, intent(in) :: w(ixi^s,1:nw)
738 double precision :: dtnew
739
740 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl)
741 end function rmhd_get_tc_dt_rmhd
742
743 subroutine rmhd_tc_handle_small_e(w, x, ixI^L, ixO^L, step)
745 integer, intent(in) :: ixi^l,ixo^l
746 double precision, intent(inout) :: w(ixi^s,1:nw)
747 double precision, intent(in) :: x(ixi^s,1:ndim)
748 integer, intent(in) :: step
749 character(len=140) :: error_msg
750
751 write(error_msg,"(a,i3)") "Thermal conduction step ", step
752 call rmhd_handle_small_ei(w,x,ixi^l,ixo^l,e_,error_msg)
753 end subroutine rmhd_tc_handle_small_e
754
755 ! fill in tc_fluid fields from namelist
756 subroutine tc_params_read_rmhd(fl)
758 type(tc_fluid), intent(inout) :: fl
759 double precision :: tc_k_para=0d0
760 double precision :: tc_k_perp=0d0
761 integer :: n
762 ! list parameters
763 logical :: tc_perpendicular=.false.
764 logical :: tc_saturate=.false.
765 character(len=std_len) :: tc_slope_limiter="MC"
766
767 namelist /tc_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp
768
769 do n = 1, size(par_files)
770 open(unitpar, file=trim(par_files(n)), status="old")
771 read(unitpar, tc_list, end=111)
772111 close(unitpar)
773 end do
774
775 fl%tc_perpendicular = tc_perpendicular
776 fl%tc_saturate = tc_saturate
777 fl%tc_k_para = tc_k_para
778 fl%tc_k_perp = tc_k_perp
779 select case(tc_slope_limiter)
780 case ('no','none')
781 fl%tc_slope_limiter = 0
782 case ('MC')
783 ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
784 fl%tc_slope_limiter = 1
785 case('minmod')
786 ! minmod limiter
787 fl%tc_slope_limiter = 2
788 case ('superbee')
789 ! Roes superbee limiter (eq.3.51i)
790 fl%tc_slope_limiter = 3
791 case ('koren')
792 ! Barry Koren Right variant
793 fl%tc_slope_limiter = 4
794 case default
795 call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
796 end select
797 end subroutine tc_params_read_rmhd
798!!end th cond
799
800 !> sets the equilibrium variables
801 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
804 integer, intent(in) :: igrid, ixi^l, ixo^l
805 double precision, intent(in) :: x(ixi^s,1:ndim)
806 double precision :: delx(ixi^s,1:ndim)
807 double precision :: xc(ixi^s,1:ndim),xshift^d
808 integer :: idims, ixc^l, hxo^l, ix, idims2
809
810 if(slab_uniform)then
811 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
812 else
813 ! for all non-cartesian and stretched cartesian coordinates
814 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
815 endif
816
817 do idims=1,ndim
818 hxo^l=ixo^l-kr(idims,^d);
819 if(stagger_grid) then
820 ! ct needs all transverse cells
821 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
822 else
823 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
824 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
825 end if
826 ! always xshift=0 or 1/2
827 xshift^d=half*(one-kr(^d,idims));
828 do idims2=1,ndim
829 select case(idims2)
830 {case(^d)
831 do ix = ixc^lim^d
832 ! xshift=half: this is the cell center coordinate
833 ! xshift=0: this is the cell edge i+1/2 coordinate
834 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
835 end do\}
836 end select
837 end do
838 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
839 end do
840 end subroutine set_equi_vars_grid_faces
841
842 !> sets the equilibrium variables
843 subroutine set_equi_vars_grid(igrid)
846 integer, intent(in) :: igrid
847
848 !values at the center
849 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
850
851 !values at the interfaces
852 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
853 end subroutine set_equi_vars_grid
854
855 ! w, wnew conserved, add splitted variables back to wnew
856 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
858 integer, intent(in) :: ixi^l,ixo^l, nwc
859 double precision, intent(in) :: w(ixi^s, 1:nw)
860 double precision, intent(in) :: x(ixi^s,1:ndim)
861 double precision :: wnew(ixo^s, 1:nwc)
862
863 if(has_equi_rho0) then
864 wnew(ixo^s,rho_)=w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,0)
865 else
866 wnew(ixo^s,rho_)=w(ixo^s,rho_)
867 endif
868 wnew(ixo^s,mom(:))=w(ixo^s,mom(:))
869
870 if (b0field) then
871 ! add background magnetic field B0 to B
872 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
873 else
874 wnew(ixo^s,mag(1:ndir))=w(ixo^s,mag(1:ndir))
875 end if
876
877 if(rmhd_energy) then
878 wnew(ixo^s,e_)=w(ixo^s,e_)
879 if(has_equi_pe0) then
880 wnew(ixo^s,e_)=wnew(ixo^s,e_)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
881 end if
882 if(b0field .and. total_energy) then
883 wnew(ixo^s,e_)=wnew(ixo^s,e_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
884 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
885 end if
886 end if
887 end function convert_vars_splitting
888
889 subroutine rmhd_check_params
893
894 ! after user parameter setting
895 gamma_1=rmhd_gamma-1.d0
896 if (.not. rmhd_energy) then
897 if (rmhd_gamma <= 0.0d0) call mpistop ("Error: rmhd_gamma <= 0")
898 if (rmhd_adiab < 0.0d0) call mpistop ("Error: rmhd_adiab < 0")
900 else
901 if (rmhd_gamma <= 0.0d0 .or. rmhd_gamma == 1.0d0) &
902 call mpistop ("Error: rmhd_gamma <= 0 or rmhd_gamma == 1")
903 inv_gamma_1=1.d0/gamma_1
904 small_e = small_pressure * inv_gamma_1
905 end if
906
908
909 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
910 call mpistop("usr_set_equi_vars has to be implemented in the user file")
911 endif
912 if(convert .or. autoconvert) then
913 if(convert_type .eq. 'dat_generic_mpi') then
914 if(rmhd_dump_full_vars) then
915 if(mype .eq. 0) print*, " add conversion method: split -> full "
916 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
917 endif
918 endif
919 endif
920
922 end subroutine rmhd_check_params
923
924 !> Set the boundaries for the diffusion of E
929 integer :: ib
930
931 ! Set boundary conditions for the multigrid solver
932 do ib = 1, 2*ndim
933 select case (typeboundary(r_e, ib))
934 case (bc_symm)
935 ! d/dx u = 0
936 mg%bc(ib, mg_iphi)%bc_type = mg_bc_neumann
937 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
938 case (bc_asymm)
939 ! u = 0
940 mg%bc(ib, mg_iphi)%bc_type = mg_bc_dirichlet
941 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
942 case (bc_cont)
943 ! d/dx u = 0
944 ! mg%bc(iB, mg_iphi)%bc_type = mg_bc_continuous
945 mg%bc(ib, mg_iphi)%bc_type = mg_bc_neumann
946 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
947 case (bc_periodic)
948 ! Nothing to do here
949 case (bc_noinflow)
950 call usr_special_mg_bc(ib)
951 case (bc_special)
952 call usr_special_mg_bc(ib)
953 case default
954 call mpistop("divE_multigrid warning: unknown b.c. ")
955 end select
956 end do
957 end subroutine rmhd_set_mg_bounds
958
959 subroutine rmhd_physical_units()
961 double precision :: mp,kb,miu0,c_lightspeed
962 double precision :: a,b
963
964 ! Derive scaling units
965 if(si_unit) then
966 mp=mp_si
967 kb=kb_si
968 miu0=miu0_si
969 c_lightspeed=c_si
970 else
971 mp=mp_cgs
972 kb=kb_cgs
973 miu0=4.d0*dpi ! G^2 cm^2 dyne^-1
974 c_lightspeed=const_c
975 end if
976 if(eq_state_units) then
977 a=1d0+4d0*he_abundance
980 else
981 b=2d0+3d0*he_abundance
982 end if
983 rr=1d0
984 else
985 a=1d0
986 b=1d0
987 rr=(1d0+h_ion_fr+he_abundance*(he_ion_fr*(he_ion_fr2+1d0)+1d0))/(1d0+4d0*he_abundance)
988 end if
989 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
990 if(unit_density/=1.d0) then
992 else if(unit_numberdensity/=1.d0) then
994 end if
995 if(unit_temperature/=1.d0) then
999 if(unit_length/=1.d0) then
1001 else if(unit_time/=1.d0) then
1003 end if
1004 else if(unit_magneticfield/=1.d0) then
1008 if(unit_length/=1.d0) then
1010 else if(unit_time/=1.d0) then
1012 end if
1013 else if(unit_pressure/=1.d0) then
1017 if(unit_length/=1.d0) then
1019 else if(unit_time/=1.d0) then
1021 end if
1022 else if(unit_velocity/=1.d0) then
1026 if(unit_length/=1.d0) then
1028 else if(unit_time/=1.d0) then
1030 end if
1031 else if(unit_time/=1.d0) then
1036 end if
1037 else if(unit_temperature/=1.d0) then
1038 ! units of temperature and velocity are dependent
1039 if(unit_magneticfield/=1.d0) then
1044 if(unit_length/=1.d0) then
1046 else if(unit_time/=1.d0) then
1048 end if
1049 else if(unit_pressure/=1.d0) then
1054 if(unit_length/=1.d0) then
1056 else if(unit_time/=1.d0) then
1058 end if
1059 end if
1060 else if(unit_magneticfield/=1.d0) then
1061 ! units of magnetic field and pressure are dependent
1062 if(unit_velocity/=1.d0) then
1067 if(unit_length/=1.d0) then
1069 else if(unit_time/=1.d0) then
1071 end if
1072 else if(unit_time/=0.d0) then
1078 end if
1079 else if(unit_pressure/=1.d0) then
1080 if(unit_velocity/=1.d0) then
1085 if(unit_length/=1.d0) then
1087 else if(unit_time/=1.d0) then
1089 end if
1090 else if(unit_time/=0.d0) then
1096 end if
1097 end if
1098 ! Additional units needed for the particles
1099 c_norm=c_lightspeed/unit_velocity
1101 if (.not. si_unit) unit_charge = unit_charge*const_c
1103
1104 !> Units for radiative flux and opacity
1107 end subroutine rmhd_physical_units
1108
1109 subroutine rmhd_check_w_origin(primitive,ixI^L,ixO^L,w,flag)
1111 logical, intent(in) :: primitive
1112 integer, intent(in) :: ixi^l, ixo^l
1113 double precision, intent(in) :: w(ixi^s,nw)
1114 logical, intent(inout) :: flag(ixi^s,1:nw)
1115 double precision :: tmp
1116 integer :: ix^d
1117
1118 flag=.false.
1119 {do ix^db=ixomin^db,ixomax^db\}
1120 if(has_equi_rho0) then
1121 tmp=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1122 else
1123 tmp=w(ix^d,rho_)
1124 end if
1125 if(tmp<small_density) flag(ix^d,rho_) = .true.
1126 if(primitive) then
1127 if(has_equi_pe0) then
1128 if(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,0)<small_pressure) flag(ix^d,e_) = .true.
1129 else
1130 if(w(ix^d,p_)<small_pressure) flag(ix^d,e_) = .true.
1131 end if
1132 else
1133 tmp=w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/tmp+(^c&w(ix^d,b^c_)**2+))
1134 if(has_equi_pe0) then
1135 if(tmp+block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1<small_e) flag(ix^d,e_) = .true.
1136 else
1137 if(tmp<small_e) flag(ix^d,e_) = .true.
1138 end if
1139 end if
1140 if(w(ix^d,r_e)<small_r_e) flag(ix^d,r_e) = .true.
1141 {end do\}
1142 end subroutine rmhd_check_w_origin
1143
1144 !> Transform primitive variables into conservative ones
1145 subroutine rmhd_to_conserved_origin(ixI^L,ixO^L,w,x)
1147 integer, intent(in) :: ixi^l, ixo^l
1148 double precision, intent(inout) :: w(ixi^s, nw)
1149 double precision, intent(in) :: x(ixi^s, 1:ndim)
1150 integer :: ix^d
1151
1152 {do ix^db=ixomin^db,ixomax^db\}
1153 ! Calculate total energy from pressure, kinetic and magnetic energy
1154 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1155 +half*((^c&w(ix^d,m^c_)**2+)*w(ix^d,rho_)&
1156 +(^c&w(ix^d,b^c_)**2+))
1157 ! Convert velocity to momentum
1158 ^c&w(ix^d,m^c_)=w(ix^d,rho_)*w(ix^d,m^c_)\
1159 {end do\}
1160 end subroutine rmhd_to_conserved_origin
1161
1162 !> Transform primitive variables into conservative ones
1163 subroutine rmhd_to_conserved_split_rho(ixI^L,ixO^L,w,x)
1165 integer, intent(in) :: ixi^l, ixo^l
1166 double precision, intent(inout) :: w(ixi^s, nw)
1167 double precision, intent(in) :: x(ixi^s, 1:ndim)
1168 double precision :: rho
1169 integer :: ix^d
1170
1171 {do ix^db=ixomin^db,ixomax^db\}
1172 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i)
1173 ! Calculate total energy from pressure, kinetic and magnetic energy
1174 w(ix^d,e_)=w(ix^d,p_)*inv_gamma_1&
1175 +half*((^c&w(ix^d,m^c_)**2+)*rho&
1176 +(^c&w(ix^d,b^c_)**2+))
1177 ! Convert velocity to momentum
1178 ^c&w(ix^d,m^c_)=rho*w(ix^d,m^c_)\
1179 {end do\}
1180 end subroutine rmhd_to_conserved_split_rho
1181
1182 !> Transform conservative variables into primitive ones
1183 subroutine rmhd_to_primitive_origin(ixI^L,ixO^L,w,x)
1185 integer, intent(in) :: ixi^l, ixo^l
1186 double precision, intent(inout) :: w(ixi^s, nw)
1187 double precision, intent(in) :: x(ixi^s, 1:ndim)
1188 double precision :: inv_rho
1189 integer :: ix^d
1190
1191 if (fix_small_values) then
1192 ! fix small values preventing NaN numbers in the following converting
1193 call rmhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'rmhd_to_primitive_origin')
1194 end if
1195
1196 {do ix^db=ixomin^db,ixomax^db\}
1197 inv_rho = 1.d0/w(ix^d,rho_)
1198 ! Convert momentum to velocity
1199 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1200 ! Calculate pressure = (gamma-1) * (e-ek-eb)
1201 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
1202 -half*(w(ix^d,rho_)*(^c&w(ix^d,m^c_)**2+)&
1203 +(^c&w(ix^d,b^c_)**2+)))
1204 {end do\}
1205 end subroutine rmhd_to_primitive_origin
1206
1207 !> Transform conservative variables into primitive ones
1208 subroutine rmhd_to_primitive_split_rho(ixI^L,ixO^L,w,x)
1210 integer, intent(in) :: ixi^l, ixo^l
1211 double precision, intent(inout) :: w(ixi^s, nw)
1212 double precision, intent(in) :: x(ixi^s, 1:ndim)
1213 double precision :: inv_rho
1214 integer :: ix^d
1215
1216 if (fix_small_values) then
1217 ! fix small values preventing NaN numbers in the following converting
1218 call rmhd_handle_small_values(.false., w, x, ixi^l, ixo^l, 'rmhd_to_primitive_split_rho')
1219 end if
1220
1221 {do ix^db=ixomin^db,ixomax^db\}
1222 inv_rho=1.d0/(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1223 ! Convert momentum to velocity
1224 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)*inv_rho\
1225 ! Calculate pressure = (gamma-1) * (e-ek-eb)
1226 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
1227 -half*((w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))*&
1228 (^c&w(ix^d,m^c_)**2+)+(^c&w(ix^d,b^c_)**2+)))
1229 {end do\}
1230 end subroutine rmhd_to_primitive_split_rho
1231
1232 !> Transform internal energy to total energy
1233 subroutine rmhd_ei_to_e(ixI^L,ixO^L,w,x)
1235 integer, intent(in) :: ixi^l, ixo^l
1236 double precision, intent(inout) :: w(ixi^s, nw)
1237 double precision, intent(in) :: x(ixi^s, 1:ndim)
1238
1239 integer :: ix^d
1240
1241 if(has_equi_rho0) then
1242 {do ix^db=ixomin^db,ixomax^db\}
1243 ! Calculate e = ei + ek + eb
1244 w(ix^d,e_)=w(ix^d,e_)&
1245 +half*((^c&w(ix^d,m^c_)**2+)/&
1246 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
1247 +(^c&w(ix^d,b^c_)**2+))
1248 {end do\}
1249 else
1250 {do ix^db=ixomin^db,ixomax^db\}
1251 ! Calculate e = ei + ek + eb
1252 w(ix^d,e_)=w(ix^d,e_)&
1253 +half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
1254 +(^c&w(ix^d,b^c_)**2+))
1255 {end do\}
1256 end if
1257 end subroutine rmhd_ei_to_e
1258
1259 !> Transform total energy to internal energy
1260 subroutine rmhd_e_to_ei(ixI^L,ixO^L,w,x)
1262 integer, intent(in) :: ixi^l, ixo^l
1263 double precision, intent(inout) :: w(ixi^s, nw)
1264 double precision, intent(in) :: x(ixi^s, 1:ndim)
1265
1266 integer :: ix^d
1267
1268 if(has_equi_rho0) then
1269 {do ix^db=ixomin^db,ixomax^db\}
1270 ! Calculate ei = e - ek - eb
1271 w(ix^d,e_)=w(ix^d,e_)&
1272 -half*((^c&w(ix^d,m^c_)**2+)/&
1273 (w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0))&
1274 +(^c&w(ix^d,b^c_)**2+))
1275 {end do\}
1276 else
1277 {do ix^db=ixomin^db,ixomax^db\}
1278 ! Calculate ei = e - ek - eb
1279 w(ix^d,e_)=w(ix^d,e_)&
1280 -half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
1281 +(^c&w(ix^d,b^c_)**2+))
1282 {end do\}
1283 end if
1284
1285 if(fix_small_values) then
1286 call rmhd_handle_small_ei(w,x,ixi^l,ixi^l,e_,'rmhd_e_to_ei')
1287 end if
1288 end subroutine rmhd_e_to_ei
1289
1290 subroutine rmhd_handle_small_values_origin(primitive, w, x, ixI^L, ixO^L, subname)
1293 logical, intent(in) :: primitive
1294 integer, intent(in) :: ixi^l,ixo^l
1295 double precision, intent(inout) :: w(ixi^s,1:nw)
1296 double precision, intent(in) :: x(ixi^s,1:ndim)
1297 character(len=*), intent(in) :: subname
1298 double precision :: rho
1299 integer :: idir, ix^d
1300 logical :: flag(ixi^s,1:nw)
1301
1302 call phys_check_w(primitive, ixi^l, ixi^l, w, flag)
1303 if(any(flag)) then
1304 select case (small_values_method)
1305 case ("replace")
1306 {do ix^db=ixomin^db,ixomax^db\}
1307 if(has_equi_rho0) then
1308 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1309 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density-block%equi_vars(ix^d,equi_rho0_,0)
1310 else
1311 rho=w(ix^d,rho_)
1312 if(flag(ix^d,rho_)) w(ix^d,rho_)=small_density
1313 end if
1314 {
1315 if(small_values_fix_iw(m^c_)) then
1316 if(flag({ix^d},rho_)) w({ix^d},m^c_)=0.0d0
1317 end if
1318 \}
1319 if(primitive) then
1320 if(has_equi_pe0) then
1321 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure-block%equi_vars(ix^d,equi_pe0_,0)
1322 else
1323 if(flag(ix^d,e_)) w(ix^d,p_)=small_pressure
1324 end if
1325 else
1326 if(has_equi_pe0) then
1327 if(flag(ix^d,e_)) &
1328 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))&
1329 -block%equi_vars(ix^d,equi_pe0_,0)*inv_gamma_1
1330 else
1331 if(flag(ix^d,e_)) &
1332 w(ix^d,e_)=small_e+half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
1333 end if
1334 end if
1335 if(flag(ix^d,r_e)) w(ix^d,r_e)=small_r_e
1336 {end do\}
1337 case ("average")
1338 ! do averaging of density
1339 call small_values_average(ixi^l, ixo^l, w, x, flag, rho_)
1340 if(primitive)then
1341 call small_values_average(ixi^l, ixo^l, w, x, flag, p_)
1342 else
1343 ! do averaging of internal energy
1344 {do ix^db=iximin^db,iximax^db\}
1345 if(has_equi_rho0) then
1346 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1347 else
1348 rho=w(ix^d,rho_)
1349 end if
1350 w(ix^d,e_)=w(ix^d,e_)&
1351 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
1352 {end do\}
1353 call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
1354 ! convert back
1355 {do ix^db=iximin^db,iximax^db\}
1356 if(has_equi_rho0) then
1357 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1358 else
1359 rho=w(ix^d,rho_)
1360 end if
1361 w(ix^d,e_)=w(ix^d,e_)&
1362 +half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+))
1363 {end do\}
1364 end if
1365 call small_values_average(ixi^l, ixo^l, w, x, flag, r_e)
1366 case default
1367 if(.not.primitive) then
1368 !convert w to primitive
1369 ! do averaging of internal energy
1370 {do ix^db=iximin^db,iximax^db\}
1371 if(has_equi_rho0) then
1372 rho=w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,0)
1373 else
1374 rho=w(ix^d,rho_)
1375 end if
1376 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)/rho\
1377 w(ix^d,p_)=gamma_1*(w(ix^d,e_)&
1378 -half*((^c&w(ix^d,m^c_)**2+)/rho+(^c&w(ix^d,b^c_)**2+)))
1379 {end do\}
1380 end if
1381 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
1382 end select
1383 end if
1384 end subroutine rmhd_handle_small_values_origin
1385
1386 !> Calculate v vector
1387 subroutine rmhd_get_v(w,x,ixI^L,ixO^L,v)
1389 integer, intent(in) :: ixi^l, ixo^l
1390 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
1391 double precision, intent(out) :: v(ixi^s,ndir)
1392 double precision :: rho(ixi^s)
1393 integer :: idir
1394
1395 call rmhd_get_rho(w,x,ixi^l,ixo^l,rho)
1396 rho(ixo^s)=1.d0/rho(ixo^s)
1397 ! Convert momentum to velocity
1398 do idir = 1, ndir
1399 v(ixo^s, idir) = w(ixo^s, mom(idir))*rho(ixo^s)
1400 end do
1401 end subroutine rmhd_get_v
1402
1403 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
1404 subroutine rmhd_get_cmax_origin(w,x,ixI^L,ixO^L,idim,cmax)
1406 integer, intent(in) :: ixi^l, ixo^l, idim
1407 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
1408 double precision, intent(inout) :: cmax(ixi^s)
1409 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
1410 integer :: ix^d
1411
1412 if(b0field) then
1413 {do ix^db=ixomin^db,ixomax^db \}
1414 if(has_equi_rho0) then
1415 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1416 else
1417 rho=w(ix^d,rho_)
1418 end if
1419 inv_rho=1.d0/rho
1420 ! sound speed**2
1421 cmax(ix^d)=rmhd_gamma*w(ix^d,p_)*inv_rho
1422 ! store |B|^2 in v
1423 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
1424 cfast2=b2*inv_rho+cmax(ix^d)
1425 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*(w(ix^d,mag(idim))+block%B0(ix^d,idim,b0i))**2*inv_rho
1426 if(avmincs2<zero) avmincs2=zero
1427 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
1428 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
1429 {end do\}
1430 else
1431 {do ix^db=ixomin^db,ixomax^db \}
1432 if(has_equi_rho0) then
1433 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1434 else
1435 rho=w(ix^d,rho_)
1436 end if
1437 inv_rho=1.d0/rho
1438 ! sound speed**2
1439 cmax(ix^d)=rmhd_gamma*w(ix^d,p_)*inv_rho
1440 ! store |B|^2 in v
1441 b2=(^c&w(ix^d,b^c_)**2+)
1442 cfast2=b2*inv_rho+cmax(ix^d)
1443 avmincs2=cfast2**2-4.0d0*cmax(ix^d)*w(ix^d,mag(idim))**2*inv_rho
1444 if(avmincs2<zero) avmincs2=zero
1445 cmax(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
1446 cmax(ix^d)=abs(w(ix^d,mom(idim)))+cmax(ix^d)
1447 {end do\}
1448 end if
1449 end subroutine rmhd_get_cmax_origin
1450
1451 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
1452 subroutine rmhd_get_tcutoff(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
1454 use mod_geometry
1455 integer, intent(in) :: ixi^l,ixo^l
1456 double precision, intent(in) :: x(ixi^s,1:ndim)
1457 double precision, intent(out) :: tco_local,tmax_local
1458 ! in primitive form
1459 double precision, intent(inout) :: w(ixi^s,1:nw)
1460 double precision, parameter :: trac_delta=0.25d0
1461 double precision :: tmp1(ixi^s),te(ixi^s),lts(ixi^s)
1462 double precision, dimension(ixI^S,1:ndir) :: bunitvec
1463 double precision, dimension(ixI^S,1:ndim) :: gradt
1464 double precision :: bdir(ndim)
1465 double precision :: ltrc,ltrp,altr(ixi^s)
1466 integer :: idims,jxo^l,hxo^l,ixa^d,ixb^d,ix^d
1467 integer :: jxp^l,hxp^l,ixp^l,ixq^l
1468 logical :: lrlt(ixi^s)
1469
1471 call rmhd_get_temperature_from_te(w,x,ixi^l,ixi^l,te)
1472 else
1473 call rmhd_get_rfactor(w,x,ixi^l,ixi^l,te)
1474 te(ixi^s)=w(ixi^s,p_)/(te(ixi^s)*w(ixi^s,rho_))
1475 end if
1476 tco_local=zero
1477 tmax_local=maxval(te(ixo^s))
1478
1479 {^ifoned
1480 select case(rmhd_trac_type)
1481 case(0)
1482 !> test case, fixed cutoff temperature
1483 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
1484 case(1)
1485 hxo^l=ixo^l-1;
1486 jxo^l=ixo^l+1;
1487 lts(ixo^s)=0.5d0*abs(te(jxo^s)-te(hxo^s))/te(ixo^s)
1488 lrlt=.false.
1489 where(lts(ixo^s) > trac_delta)
1490 lrlt(ixo^s)=.true.
1491 end where
1492 if(any(lrlt(ixo^s))) then
1493 tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
1494 end if
1495 case(2)
1496 !> iijima et al. 2021, LTRAC method
1497 ltrc=1.5d0
1498 ltrp=4.d0
1499 ixp^l=ixo^l^ladd1;
1500 hxo^l=ixo^l-1;
1501 jxo^l=ixo^l+1;
1502 hxp^l=ixp^l-1;
1503 jxp^l=ixp^l+1;
1504 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
1505 lts(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
1506 lts(ixo^s)=0.25d0*(lts(jxo^s)+two*lts(ixo^s)+lts(hxo^s))
1507 block%wextra(ixo^s,tcoff_)=te(ixo^s)*lts(ixo^s)**0.4d0
1508 case default
1509 call mpistop("rmhd_trac_type not allowed for 1D simulation")
1510 end select
1511 }
1512 {^nooned
1513 select case(rmhd_trac_type)
1514 case(0)
1515 !> test case, fixed cutoff temperature
1516 block%wextra(ixi^s,tcoff_)=2.5d5/unit_temperature
1517 case(1,4,6)
1518 ! temperature gradient at cell centers
1519 do idims=1,ndim
1520 call gradient(te,ixi^l,ixo^l,idims,tmp1)
1521 gradt(ixo^s,idims)=tmp1(ixo^s)
1522 end do
1523 ! B vector
1524 if(b0field) then
1525 bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))+block%B0(ixo^s,:,0)
1526 else
1527 bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))
1528 end if
1529 if(rmhd_trac_type .gt. 1) then
1530 ! B direction at cell center
1531 bdir=zero
1532 {do ixa^d=0,1\}
1533 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
1534 bdir(1:ndim)=bdir(1:ndim)+bunitvec(ixb^d,1:ndim)
1535 {end do\}
1536 if(sum(bdir(:)**2) .gt. zero) then
1537 bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
1538 end if
1539 block%special_values(3:ndim+2)=bdir(1:ndim)
1540 end if
1541 tmp1(ixo^s)=dsqrt(sum(bunitvec(ixo^s,:)**2,dim=ndim+1))
1542 where(tmp1(ixo^s)/=0.d0)
1543 tmp1(ixo^s)=1.d0/tmp1(ixo^s)
1544 elsewhere
1545 tmp1(ixo^s)=bigdouble
1546 end where
1547 ! b unit vector: magnetic field direction vector
1548 do idims=1,ndim
1549 bunitvec(ixo^s,idims)=bunitvec(ixo^s,idims)*tmp1(ixo^s)
1550 end do
1551 ! temperature length scale inversed
1552 lts(ixo^s)=abs(sum(gradt(ixo^s,1:ndim)*bunitvec(ixo^s,1:ndim),dim=ndim+1))/te(ixo^s)
1553 ! fraction of cells size to temperature length scale
1554 if(slab_uniform) then
1555 lts(ixo^s)=minval(dxlevel)*lts(ixo^s)
1556 else
1557 lts(ixo^s)=minval(block%ds(ixo^s,:),dim=ndim+1)*lts(ixo^s)
1558 end if
1559 lrlt=.false.
1560 where(lts(ixo^s) > trac_delta)
1561 lrlt(ixo^s)=.true.
1562 end where
1563 if(any(lrlt(ixo^s))) then
1564 block%special_values(1)=maxval(te(ixo^s), mask=lrlt(ixo^s))
1565 else
1566 block%special_values(1)=zero
1567 end if
1568 block%special_values(2)=tmax_local
1569 case(2)
1570 !> iijima et al. 2021, LTRAC method
1571 ltrc=1.5d0
1572 ltrp=4.d0
1573 ixp^l=ixo^l^ladd2;
1574 ! temperature gradient at cell centers
1575 do idims=1,ndim
1576 ixq^l=ixp^l;
1577 hxp^l=ixp^l;
1578 jxp^l=ixp^l;
1579 select case(idims)
1580 {case(^d)
1581 ixqmin^d=ixqmin^d+1
1582 ixqmax^d=ixqmax^d-1
1583 hxpmax^d=ixpmin^d
1584 jxpmin^d=ixpmax^d
1585 \}
1586 end select
1587 call gradient(te,ixi^l,ixq^l,idims,gradt(ixi^s,idims))
1588 call gradientf(te,x,ixi^l,hxp^l,idims,gradt(ixi^s,idims),nghostcells,.true.)
1589 call gradientf(te,x,ixi^l,jxp^l,idims,gradt(ixi^s,idims),nghostcells,.false.)
1590 end do
1591 ! B vector
1592 {do ix^db=ixpmin^db,ixpmax^db\}
1593 if(b0field) then
1594 ^c&bunitvec(ix^d,^c)=w(ix^d,iw_mag(^c))+block%B0(ix^d,^c,0)\
1595 else
1596 ^c&bunitvec(ix^d,^c)=w(ix^d,iw_mag(^c))\
1597 end if
1598 tmp1(ix^d)=1.d0/(dsqrt(^c&bunitvec(ix^d,^c)**2+)+smalldouble)
1599 ! b unit vector: magnetic field direction vector
1600 ^d&bunitvec({ix^d},^d)=bunitvec({ix^d},^d)*tmp1({ix^d})\
1601 ! temperature length scale inversed
1602 lts(ix^d)=abs(^d&gradt({ix^d},^d)*bunitvec({ix^d},^d)+)/te(ix^d)
1603 ! fraction of cells size to temperature length scale
1604 if(slab_uniform) then
1605 lts(ix^d)=min(^d&dxlevel(^d))*lts(ix^d)
1606 else
1607 lts(ix^d)=min(^d&block%ds({ix^d},^d))*lts(ix^d)
1608 end if
1609 lts(ix^d)=max(one,(exp(lts(ix^d))/ltrc)**ltrp)
1610 {end do\}
1611 ! need one ghost layer for thermal conductivity
1612 ixp^l=ixo^l^ladd1;
1613 do idims=1,ndim
1614 hxo^l=ixp^l-kr(idims,^d);
1615 jxo^l=ixp^l+kr(idims,^d);
1616 if(idims==1) then
1617 altr(ixp^s)=0.25d0*(lts(hxo^s)+two*lts(ixp^s)+lts(jxo^s))*bunitvec(ixp^s,idims)**2
1618 else
1619 altr(ixp^s)=altr(ixp^s)+0.25d0*(lts(hxo^s)+two*lts(ixp^s)+lts(jxo^s))*bunitvec(ixp^s,idims)**2
1620 end if
1621 end do
1622 block%wextra(ixp^s,tcoff_)=te(ixp^s)*altr(ixp^s)**0.4d0
1623 case(3,5)
1624 !> do nothing here
1625 case default
1626 call mpistop("unknown rmhd_trac_type")
1627 end select
1628 }
1629 end subroutine rmhd_get_tcutoff
1630
1631 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
1632 subroutine rmhd_get_h_speed(wprim,x,ixI^L,ixO^L,idim,Hspeed)
1634
1635 integer, intent(in) :: ixi^l, ixo^l, idim
1636 double precision, intent(in) :: wprim(ixi^s, nw)
1637 double precision, intent(in) :: x(ixi^s,1:ndim)
1638 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
1639
1640 double precision :: csound(ixi^s,ndim)
1641 double precision, allocatable :: tmp(:^d&)
1642 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
1643
1644 hspeed=0.d0
1645 ixa^l=ixo^l^ladd1;
1646 allocate(tmp(ixa^s))
1647 do id=1,ndim
1648 call rmhd_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
1649 csound(ixa^s,id)=tmp(ixa^s)
1650 end do
1651 ixcmax^d=ixomax^d;
1652 ixcmin^d=ixomin^d+kr(idim,^d)-1;
1653 jxcmax^d=ixcmax^d+kr(idim,^d);
1654 jxcmin^d=ixcmin^d+kr(idim,^d);
1655 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))
1656
1657 do id=1,ndim
1658 if(id==idim) cycle
1659 ixamax^d=ixcmax^d+kr(id,^d);
1660 ixamin^d=ixcmin^d+kr(id,^d);
1661 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)))
1662 ixamax^d=ixcmax^d-kr(id,^d);
1663 ixamin^d=ixcmin^d-kr(id,^d);
1664 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)))
1665 end do
1666
1667 do id=1,ndim
1668 if(id==idim) cycle
1669 ixamax^d=jxcmax^d+kr(id,^d);
1670 ixamin^d=jxcmin^d+kr(id,^d);
1671 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)))
1672 ixamax^d=jxcmax^d-kr(id,^d);
1673 ixamin^d=jxcmin^d-kr(id,^d);
1674 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)))
1675 end do
1676 deallocate(tmp)
1677
1678 end subroutine rmhd_get_h_speed
1679
1680 !> Estimating bounds for the minimum and maximum signal velocities without split
1681 subroutine rmhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
1683 integer, intent(in) :: ixi^l, ixo^l, idim
1684 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
1685 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1686 double precision, intent(in) :: x(ixi^s,1:ndim)
1687 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
1688 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
1689 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
1690
1691 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
1692 double precision :: umean, dmean, tmp1, tmp2, tmp3
1693 integer :: ix^d
1694
1695 select case (boundspeed)
1696 case (1)
1697 ! This implements formula (10.52) from "Riemann Solvers and Numerical
1698 ! Methods for Fluid Dynamics" by Toro.
1699 call rmhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
1700 call rmhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
1701 if(present(cmin)) then
1702 {do ix^db=ixomin^db,ixomax^db\}
1703 tmp1=sqrt(wlp(ix^d,rho_))
1704 tmp2=sqrt(wrp(ix^d,rho_))
1705 tmp3=1.d0/(tmp1+tmp2)
1706 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
1707 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
1708 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
1709 cmin(ix^d,1)=umean-dmean
1710 cmax(ix^d,1)=umean+dmean
1711 {end do\}
1712 if(h_correction) then
1713 {do ix^db=ixomin^db,ixomax^db\}
1714 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1715 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1716 {end do\}
1717 end if
1718 else
1719 {do ix^db=ixomin^db,ixomax^db\}
1720 tmp1=sqrt(wlp(ix^d,rho_))
1721 tmp2=sqrt(wrp(ix^d,rho_))
1722 tmp3=1.d0/(tmp1+tmp2)
1723 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
1724 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
1725 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
1726 cmax(ix^d,1)=abs(umean)+dmean
1727 {end do\}
1728 end if
1729 case (2)
1730 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
1731 call rmhd_get_csound_prim(wmean,x,ixi^l,ixo^l,idim,csoundr)
1732 if(present(cmin)) then
1733 {do ix^db=ixomin^db,ixomax^db\}
1734 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
1735 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
1736 {end do\}
1737 if(h_correction) then
1738 {do ix^db=ixomin^db,ixomax^db\}
1739 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1740 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1741 {end do\}
1742 end if
1743 else
1744 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
1745 end if
1746 case (3)
1747 ! Miyoshi 2005 JCP 208, 315 equation (67)
1748 call rmhd_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
1749 call rmhd_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
1750 if(present(cmin)) then
1751 {do ix^db=ixomin^db,ixomax^db\}
1752 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
1753 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
1754 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
1755 {end do\}
1756 if(h_correction) then
1757 {do ix^db=ixomin^db,ixomax^db\}
1758 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1759 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1760 {end do\}
1761 end if
1762 else
1763 {do ix^db=ixomin^db,ixomax^db\}
1764 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
1765 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
1766 {end do\}
1767 end if
1768 end select
1769 end subroutine rmhd_get_cbounds
1770
1771 !> Estimating bounds for the minimum and maximum signal velocities with rho split
1772 subroutine rmhd_get_cbounds_split_rho(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
1774 integer, intent(in) :: ixi^l, ixo^l, idim
1775 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
1776 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1777 double precision, intent(in) :: x(ixi^s,1:ndim)
1778 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
1779 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
1780 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
1781 double precision :: wmean(ixi^s,nw), csoundl(ixo^s), csoundr(ixo^s)
1782 double precision :: umean, dmean, tmp1, tmp2, tmp3
1783 integer :: ix^d
1784
1785 select case (boundspeed)
1786 case (1)
1787 ! This implements formula (10.52) from "Riemann Solvers and Numerical
1788 ! Methods for Fluid Dynamics" by Toro.
1789 call rmhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
1790 call rmhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
1791 if(present(cmin)) then
1792 {do ix^db=ixomin^db,ixomax^db\}
1793 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1794 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1795 tmp3=1.d0/(tmp1+tmp2)
1796 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
1797 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
1798 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
1799 cmin(ix^d,1)=umean-dmean
1800 cmax(ix^d,1)=umean+dmean
1801 {end do\}
1802 if(h_correction) then
1803 {do ix^db=ixomin^db,ixomax^db\}
1804 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1805 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1806 {end do\}
1807 end if
1808 else
1809 {do ix^db=ixomin^db,ixomax^db\}
1810 tmp1=sqrt(wlp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1811 tmp2=sqrt(wrp(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
1812 tmp3=1.d0/(tmp1+tmp2)
1813 umean=(wlp(ix^d,mom(idim))*tmp1+wrp(ix^d,mom(idim))*tmp2)*tmp3
1814 dmean=sqrt((tmp1*csoundl(ix^d)**2+tmp2*csoundr(ix^d)**2)*tmp3+&
1815 half*tmp1*tmp2*tmp3**2*(wrp(ix^d,mom(idim))-wlp(ix^d,mom(idim)))**2)
1816 cmax(ix^d,1)=abs(umean)+dmean
1817 {end do\}
1818 end if
1819 case (2)
1820 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
1821 call rmhd_get_csound_prim_split(wmean,x,ixi^l,ixo^l,idim,csoundr)
1822 if(present(cmin)) then
1823 {do ix^db=ixomin^db,ixomax^db\}
1824 cmax(ix^d,1)=max(wmean(ix^d,mom(idim))+csoundr(ix^d),zero)
1825 cmin(ix^d,1)=min(wmean(ix^d,mom(idim))-csoundr(ix^d),zero)
1826 {end do\}
1827 if(h_correction) then
1828 {do ix^db=ixomin^db,ixomax^db\}
1829 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1830 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1831 {end do\}
1832 end if
1833 else
1834 cmax(ixo^s,1)=abs(wmean(ixo^s,mom(idim)))+csoundr(ixo^s)
1835 end if
1836 case (3)
1837 ! Miyoshi 2005 JCP 208, 315 equation (67)
1838 call rmhd_get_csound_prim_split(wlp,x,ixi^l,ixo^l,idim,csoundl)
1839 call rmhd_get_csound_prim_split(wrp,x,ixi^l,ixo^l,idim,csoundr)
1840 if(present(cmin)) then
1841 {do ix^db=ixomin^db,ixomax^db\}
1842 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
1843 cmin(ix^d,1)=min(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))-csoundl(ix^d)
1844 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
1845 {end do\}
1846 if(h_correction) then
1847 {do ix^db=ixomin^db,ixomax^db\}
1848 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
1849 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
1850 {end do\}
1851 end if
1852 else
1853 {do ix^db=ixomin^db,ixomax^db\}
1854 csoundl(ix^d)=max(csoundl(ix^d),csoundr(ix^d))
1855 cmax(ix^d,1)=max(wlp(ix^d,mom(idim)),wrp(ix^d,mom(idim)))+csoundl(ix^d)
1856 {end do\}
1857 end if
1858 end select
1859 end subroutine rmhd_get_cbounds_split_rho
1860
1861 !> prepare velocities for ct methods
1862 subroutine rmhd_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
1864
1865 integer, intent(in) :: ixi^l, ixo^l, idim
1866 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1867 double precision, intent(in) :: cmax(ixi^s)
1868 double precision, intent(in), optional :: cmin(ixi^s)
1869 type(ct_velocity), intent(inout):: vcts
1870
1871 end subroutine rmhd_get_ct_velocity_average
1872
1873 subroutine rmhd_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
1875
1876 integer, intent(in) :: ixi^l, ixo^l, idim
1877 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1878 double precision, intent(in) :: cmax(ixi^s)
1879 double precision, intent(in), optional :: cmin(ixi^s)
1880 type(ct_velocity), intent(inout):: vcts
1881
1882 ! calculate velocities related to different UCT schemes
1883 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
1884 ! get average normal velocity at cell faces
1885 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
1886
1887 end subroutine rmhd_get_ct_velocity_contact
1888
1889 subroutine rmhd_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
1891
1892 integer, intent(in) :: ixi^l, ixo^l, idim
1893 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
1894 double precision, intent(in) :: cmax(ixi^s)
1895 double precision, intent(in), optional :: cmin(ixi^s)
1896 type(ct_velocity), intent(inout):: vcts
1897
1898 integer :: idime,idimn
1899
1900 if(.not.allocated(vcts%vbarC)) then
1901 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
1902 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
1903 end if
1904 ! Store magnitude of characteristics
1905 if(present(cmin)) then
1906 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
1907 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
1908 else
1909 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
1910 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
1911 end if
1912
1913 idimn=mod(idim,ndir)+1 ! 'Next' direction
1914 idime=mod(idim+1,ndir)+1 ! Electric field direction
1915 ! Store velocities
1916 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
1917 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
1918 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
1919 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
1920 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
1921
1922 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
1923 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
1924 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
1925 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
1926 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
1927
1928 end subroutine rmhd_get_ct_velocity_hll
1929
1930 !> Calculate fast magnetosonic wave speed
1931 subroutine rmhd_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
1933 integer, intent(in) :: ixi^l, ixo^l, idim
1934 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
1935 double precision, intent(out):: csound(ixo^s)
1936 double precision :: inv_rho, cfast2, avmincs2, b2, kmax
1937 double precision :: prad_tensor(ixo^s, 1:ndim, 1:ndim)
1938 double precision :: prad_max(ixo^s)
1939 integer :: ix^d
1940
1941 call rmhd_get_pradiation(w, x, ixi^l, ixo^l, prad_tensor, nghostcells-1)
1942 !> filter cmax
1943 if(radio_acoustic_filter) then
1944 call rmhd_radio_acoustic_filter(x, ixi^l, ixo^l, prad_max)
1945 endif
1946 ! store |B|^2 in v
1947 if(b0field) then
1948 {do ix^db=ixomin^db,ixomax^db \}
1949 inv_rho=1.d0/w(ix^d,rho_)
1950 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
1951 if(rmhd_energy) then
1952 csound(ix^d)=max(rmhd_gamma,4.d0/3.d0)*(w(ix^d,p_)+prad_max(ix^d))*inv_rho
1953 else
1954 csound(ix^d)=rmhd_gamma*rmhd_adiab*w(ix^d,rho_)**gamma_1
1955 end if
1956 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
1957 cfast2=b2*inv_rho+csound(ix^d)
1958 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
1959 block%B0(ix^d,idim,b0i))**2*inv_rho
1960 if(avmincs2<zero) avmincs2=zero
1961 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
1962 {end do\}
1963 else
1964 {do ix^db=ixomin^db,ixomax^db \}
1965 inv_rho=1.d0/w(ix^d,rho_)
1966 prad_max(ix^d)=maxval(prad_tensor(ix^d,:,:))
1967 if(rmhd_energy) then
1968 csound(ix^d)=max(rmhd_gamma,4.d0/3.d0)*(w(ix^d,p_)+prad_max(ix^d))*inv_rho
1969 else
1970 csound(ix^d)=rmhd_gamma*rmhd_adiab*w(ix^d,rho_)**gamma_1
1971 end if
1972 b2=(^c&w(ix^d,b^c_)**2+)
1973 cfast2=b2*inv_rho+csound(ix^d)
1974 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
1975 if(avmincs2<zero) avmincs2=zero
1976 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
1977 {end do\}
1978 end if
1979 end subroutine rmhd_get_csound_prim
1980
1981 !> Calculate fast magnetosonic wave speed
1982 subroutine rmhd_get_csound_prim_split(w,x,ixI^L,ixO^L,idim,csound)
1984 integer, intent(in) :: ixi^l, ixo^l, idim
1985 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
1986 double precision, intent(out):: csound(ixo^s)
1987 double precision :: rho, inv_rho, cfast2, avmincs2, b2, kmax
1988 double precision :: prad_tensor(ixo^s, 1:ndim, 1:ndim)
1989 double precision :: prad_max(ixo^s)
1990 integer :: ix^d
1991
1992 call rmhd_get_pradiation(w, x, ixi^l, ixo^l, prad_tensor, nghostcells-1)
1993 !> filter cmax
1994 if (radio_acoustic_filter) then
1995 call rmhd_radio_acoustic_filter(x, ixi^l, ixo^l, prad_max)
1996 endif
1997
1998 ! store |B|^2 in v
1999 if(b0field) then
2000 {do ix^db=ixomin^db,ixomax^db \}
2001 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2002 inv_rho=1.d0/rho
2003 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
2004 if(has_equi_pe0) then
2005 csound(ix^d)=max(rmhd_gamma,4.d0/3.d0)*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i)+prad_max(ix^d))*inv_rho
2006 end if
2007 b2=(^c&(w(ix^d,b^c_)+block%B0(ix^d,^c,b0i))**2+)
2008 cfast2=b2*inv_rho+csound(ix^d)
2009 avmincs2=cfast2**2-4.0d0*csound(ix^d)*(w(ix^d,mag(idim))+&
2010 block%B0(ix^d,idim,b0i))**2*inv_rho
2011 if(avmincs2<zero) avmincs2=zero
2012 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2013 {end do\}
2014 else
2015 {do ix^db=ixomin^db,ixomax^db \}
2016 rho=(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2017 inv_rho=1.d0/rho
2018 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
2019 if(has_equi_pe0) then
2020 csound(ix^d)=max(rmhd_gamma,4.d0/3.d0)*(w(ix^d,p_)+block%equi_vars(ix^d,equi_pe0_,b0i)+prad_max(ix^d))*inv_rho
2021 end if
2022 b2=(^c&w(ix^d,b^c_)**2+)
2023 cfast2=b2*inv_rho+csound(ix^d)
2024 avmincs2=cfast2**2-4.0d0*csound(ix^d)*w(ix^d,mag(idim))**2*inv_rho
2025 if(avmincs2<zero) avmincs2=zero
2026 csound(ix^d)=sqrt(half*(cfast2+sqrt(avmincs2)))
2027 {end do\}
2028 end if
2029 end subroutine rmhd_get_csound_prim_split
2030
2031 !> Calculate thermal pressure=(gamma-1)*(e-0.5*m**2/rho-b**2/2) within ixO^L
2032 subroutine rmhd_get_pthermal_origin(w,x,ixI^L,ixO^L,pth)
2035
2036 integer, intent(in) :: ixi^l, ixo^l
2037 double precision, intent(in) :: w(ixi^s,nw)
2038 double precision, intent(in) :: x(ixi^s,1:ndim)
2039 double precision, intent(out):: pth(ixi^s)
2040
2041 integer :: iw, ix^d
2042
2043 {do ix^db=ixomin^db,ixomax^db\}
2044 if(has_equi_rho0) then
2045 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))&
2046 +(^c&w(ix^d,b^c_)**2+)))+block%equi_vars(ix^d,equi_pe0_,0)
2047 else
2048 pth(ix^d)=gamma_1*(w(ix^d,e_)-half*((^c&w(ix^d,m^c_)**2+)/w(ix^d,rho_)&
2049 +(^c&w(ix^d,b^c_)**2+)))
2050 end if
2051 if(fix_small_values.and.pth(ix^d)<small_pressure) pth(ix^d)=small_pressure
2052 {end do\}
2053
2054 if(check_small_values.and..not.fix_small_values) then
2055 {do ix^db=ixomin^db,ixomax^db\}
2056 if(pth(ix^d)<small_pressure) then
2057 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
2058 " encountered when call rmhd_get_pthermal"
2059 write(*,*) "Iteration: ", it, " Time: ", global_time
2060 write(*,*) "Location: ", x(ix^d,:)
2061 write(*,*) "Cell number: ", ix^d
2062 do iw=1,nw
2063 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
2064 end do
2065 ! use erroneous arithmetic operation to crash the run
2066 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
2067 write(*,*) "Saving status at the previous time step"
2068 crash=.true.
2069 end if
2070 {end do\}
2071 end if
2072 end subroutine rmhd_get_pthermal_origin
2073
2074 !> copy temperature from stored Te variable
2075 subroutine rmhd_get_temperature_from_te(w, x, ixI^L, ixO^L, res)
2077 integer, intent(in) :: ixi^l, ixo^l
2078 double precision, intent(in) :: w(ixi^s, 1:nw)
2079 double precision, intent(in) :: x(ixi^s, 1:ndim)
2080 double precision, intent(out):: res(ixi^s)
2081 res(ixo^s) = w(ixo^s, te_)
2082 end subroutine rmhd_get_temperature_from_te
2083
2084 !> Calculate temperature=p/rho when in e_ the internal energy is stored
2085 subroutine rmhd_get_temperature_from_eint(w, x, ixI^L, ixO^L, res)
2087 integer, intent(in) :: ixi^l, ixo^l
2088 double precision, intent(in) :: w(ixi^s, 1:nw)
2089 double precision, intent(in) :: x(ixi^s, 1:ndim)
2090 double precision, intent(out):: res(ixi^s)
2091 double precision :: r(ixi^s)
2092
2093 call rmhd_get_rfactor(w,x,ixi^l,ixo^l,r)
2094 res(ixo^s) = gamma_1 * w(ixo^s, e_)/(w(ixo^s,rho_)*r(ixo^s))
2095 end subroutine rmhd_get_temperature_from_eint
2096
2097 !> Calculate temperature=p/rho when in e_ the total energy is stored
2098 subroutine rmhd_get_temperature_from_etot(w, x, ixI^L, ixO^L, res)
2100 integer, intent(in) :: ixi^l, ixo^l
2101 double precision, intent(in) :: w(ixi^s, 1:nw)
2102 double precision, intent(in) :: x(ixi^s, 1:ndim)
2103 double precision, intent(out):: res(ixi^s)
2104 double precision :: r(ixi^s)
2105
2106 call rmhd_get_rfactor(w,x,ixi^l,ixo^l,r)
2107 call rmhd_get_pthermal(w,x,ixi^l,ixo^l,res)
2108 res(ixo^s)=res(ixo^s)/(r(ixo^s)*w(ixo^s,rho_))
2109 end subroutine rmhd_get_temperature_from_etot
2110
2111 subroutine rmhd_get_temperature_from_etot_with_equi(w, x, ixI^L, ixO^L, res)
2113 integer, intent(in) :: ixi^l, ixo^l
2114 double precision, intent(in) :: w(ixi^s, 1:nw)
2115 double precision, intent(in) :: x(ixi^s, 1:ndim)
2116 double precision, intent(out):: res(ixi^s)
2117 double precision :: r(ixi^s)
2118
2119 call rmhd_get_rfactor(w,x,ixi^l,ixo^l,r)
2120 call rmhd_get_pthermal(w,x,ixi^l,ixo^l,res)
2121 res(ixo^s)=res(ixo^s)/(r(ixo^s)*(w(ixo^s,rho_)+block%equi_vars(ixo^s,equi_rho0_,b0i)))
2122 end subroutine rmhd_get_temperature_from_etot_with_equi
2123
2124 subroutine rmhd_get_temperature_from_eint_with_equi(w, x, ixI^L, ixO^L, res)
2126 integer, intent(in) :: ixi^l, ixo^l
2127 double precision, intent(in) :: w(ixi^s, 1:nw)
2128 double precision, intent(in) :: x(ixi^s, 1:ndim)
2129 double precision, intent(out):: res(ixi^s)
2130 double precision :: r(ixi^s)
2131
2132 call rmhd_get_rfactor(w,x,ixi^l,ixo^l,r)
2133 res(ixo^s) = (gamma_1 * w(ixo^s, e_) + block%equi_vars(ixo^s,equi_pe0_,b0i)) /&
2134 ((w(ixo^s,rho_) +block%equi_vars(ixo^s,equi_rho0_,b0i))*r(ixo^s))
2135 end subroutine rmhd_get_temperature_from_eint_with_equi
2136
2137 subroutine rmhd_get_temperature_equi(w,x, ixI^L, ixO^L, res)
2139 integer, intent(in) :: ixi^l, ixo^l
2140 double precision, intent(in) :: w(ixi^s, 1:nw)
2141 double precision, intent(in) :: x(ixi^s, 1:ndim)
2142 double precision, intent(out):: res(ixi^s)
2143 double precision :: r(ixi^s)
2144
2145 call rmhd_get_rfactor(w,x,ixi^l,ixo^l,r)
2146 res(ixo^s)= block%equi_vars(ixo^s,equi_pe0_,b0i)/(block%equi_vars(ixo^s,equi_rho0_,b0i)*r(ixo^s))
2147 end subroutine rmhd_get_temperature_equi
2148
2149 subroutine rmhd_get_rho_equi(w, x, ixI^L, ixO^L, res)
2151 integer, intent(in) :: ixi^l, ixo^l
2152 double precision, intent(in) :: w(ixi^s, 1:nw)
2153 double precision, intent(in) :: x(ixi^s, 1:ndim)
2154 double precision, intent(out):: res(ixi^s)
2155 res(ixo^s) = block%equi_vars(ixo^s,equi_rho0_,b0i)
2156 end subroutine rmhd_get_rho_equi
2157
2158 subroutine rmhd_get_pe_equi(w,x, ixI^L, ixO^L, res)
2160 integer, intent(in) :: ixi^l, ixo^l
2161 double precision, intent(in) :: w(ixi^s, 1:nw)
2162 double precision, intent(in) :: x(ixi^s, 1:ndim)
2163 double precision, intent(out):: res(ixi^s)
2164 res(ixo^s) = block%equi_vars(ixo^s,equi_pe0_,b0i)
2165 end subroutine rmhd_get_pe_equi
2166
2167 !> Calculate total pressure within ixO^L including magnetic pressure
2168 subroutine rmhd_get_p_total(w,x,ixI^L,ixO^L,p)
2170 integer, intent(in) :: ixi^l, ixo^l
2171 double precision, intent(in) :: w(ixi^s,nw)
2172 double precision, intent(in) :: x(ixi^s,1:ndim)
2173 double precision, intent(out) :: p(ixi^s)
2174
2175 call rmhd_get_pthermal(w,x,ixi^l,ixo^l,p)
2176 p(ixo^s) = p(ixo^s) + 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
2177 end subroutine rmhd_get_p_total
2178
2179 !> Calculate radiation pressure within ixO^L
2180 subroutine rmhd_get_pradiation(w, x, ixI^L, ixO^L, prad, nth)
2182 use mod_fld
2183 use mod_afld
2184 integer, intent(in) :: ixi^l, ixo^l, nth
2185 double precision, intent(in) :: w(ixi^s, 1:nw)
2186 double precision, intent(in) :: x(ixi^s, 1:ndim)
2187 double precision, intent(out):: prad(ixo^s, 1:ndim, 1:ndim)
2188
2189 select case (rmhd_radiation_formalism)
2190 case('fld')
2191 call fld_get_radpress(w, x, ixi^l, ixo^l, prad, nth)
2192 case('afld')
2193 call afld_get_radpress(w, x, ixi^l, ixo^l, prad, nth)
2194 case default
2195 call mpistop('Radiation formalism unknown')
2196 end select
2197 end subroutine rmhd_get_pradiation
2198
2199 !> Calculates the sum of the gas pressure and the max Prad tensor element
2200 subroutine rmhd_get_pthermal_plus_pradiation(w, x, ixI^L, ixO^L, pth_plus_prad)
2202 integer, intent(in) :: ixi^l, ixo^l
2203 double precision, intent(in) :: w(ixi^s, 1:nw)
2204 double precision, intent(in) :: x(ixi^s, 1:ndim)
2205 double precision :: pth(ixi^s)
2206 double precision :: prad_tensor(ixo^s, 1:ndim, 1:ndim)
2207 double precision :: prad_max(ixo^s)
2208 double precision, intent(out) :: pth_plus_prad(ixi^s)
2209 integer :: ix^d
2210
2211 call rmhd_get_pthermal(w, x, ixi^l, ixo^l, pth)
2212 call rmhd_get_pradiation(w, x, ixi^l, ixo^l, prad_tensor, nghostcells)
2213 {do ix^d = ixomin^d,ixomax^d\}
2214 prad_max(ix^d) = maxval(prad_tensor(ix^d,:,:))
2215 {enddo\}
2216 !> filter cmax
2217 if (radio_acoustic_filter) then
2218 call rmhd_radio_acoustic_filter(x, ixi^l, ixo^l, prad_max)
2219 endif
2220 pth_plus_prad(ixo^s) = pth(ixo^s) + prad_max(ixo^s)
2222
2223 !> Filter peaks in cmax due to radiation energy density, used for debugging
2224 subroutine rmhd_radio_acoustic_filter(x, ixI^L, ixO^L, prad_max)
2226 integer, intent(in) :: ixi^l, ixo^l
2227 double precision, intent(in) :: x(ixi^s, 1:ndim)
2228 double precision, intent(inout) :: prad_max(ixo^s)
2229 double precision :: tmp_prad(ixi^s)
2230 integer :: ix^d, filter, idim
2231
2232 if (size_ra_filter .lt. 1) call mpistop("ra filter of size < 1 makes no sense")
2233 if (size_ra_filter .gt. nghostcells) call mpistop("ra filter of size < nghostcells makes no sense")
2234
2235 tmp_prad(ixi^s) = zero
2236 tmp_prad(ixo^s) = prad_max(ixo^s)
2237 do filter = 1,size_ra_filter
2238 do idim = 1,ndim
2239 ! {do ix^D = ixOmin^D+filter,ixOmax^D-filter\}
2240 {do ix^d = ixomin^d,ixomax^d\}
2241 prad_max(ix^d) = min(tmp_prad(ix^d),tmp_prad(ix^d+filter*kr(idim,^d)))
2242 prad_max(ix^d) = min(tmp_prad(ix^d),tmp_prad(ix^d-filter*kr(idim,^d)))
2243 {enddo\}
2244 enddo
2245 enddo
2246 end subroutine rmhd_radio_acoustic_filter
2247
2248 !> Calculates gas temperature
2249 subroutine rmhd_get_tgas(w, x, ixI^L, ixO^L, tgas)
2251 integer, intent(in) :: ixi^l, ixo^l
2252 double precision, intent(in) :: w(ixi^s, 1:nw)
2253 double precision, intent(in) :: x(ixi^s, 1:ndim)
2254 double precision :: pth(ixi^s)
2255 double precision, intent(out):: tgas(ixi^s)
2256
2257 call rmhd_get_pthermal(w, x, ixi^l, ixo^l, pth)
2258 tgas(ixi^s) = pth(ixi^s)/w(ixi^s,rho_)
2259 end subroutine rmhd_get_tgas
2260
2261 !> Calculates radiation temperature
2262 subroutine rmhd_get_trad(w, x, ixI^L, ixO^L, trad)
2264 use mod_constants
2265
2266 integer, intent(in) :: ixi^l, ixo^l
2267 double precision, intent(in) :: w(ixi^s, 1:nw)
2268 double precision, intent(in) :: x(ixi^s, 1:ndim)
2269 double precision, intent(out):: trad(ixi^s)
2270
2271 trad(ixi^s) = (w(ixi^s,r_e)*unit_pressure&
2272 /const_rad_a)**(1.d0/4.d0)/unit_temperature
2273 end subroutine rmhd_get_trad
2274
2275 !> Calculate fluxes within ixO^L without any splitting
2276 subroutine rmhd_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
2278 use mod_geometry
2279
2280 integer, intent(in) :: ixi^l, ixo^l, idim
2281 ! conservative w
2282 double precision, intent(in) :: wc(ixi^s,nw)
2283 ! primitive w
2284 double precision, intent(in) :: w(ixi^s,nw)
2285 double precision, intent(in) :: x(ixi^s,1:ndim)
2286 double precision,intent(out) :: f(ixi^s,nwflux)
2287 double precision :: vhall(ixi^s,1:ndir)
2288 double precision :: ptotal
2289 integer :: iw, ix^d
2290
2291 {do ix^db=ixomin^db,ixomax^db\}
2292 ! Get flux of density
2293 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
2294 ! f_i[m_k]=v_i*m_k-b_k*b_i
2295 ^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_)\
2296 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
2297 ! normal one includes total pressure
2298 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
2299 ! Get flux of total energy
2300 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
2301 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
2302 -w(ix^d,mag(idim))*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
2303 ! f_i[b_k]=v_i*b_k-v_k*b_i
2304 ^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_)\
2305 {end do\}
2306 if(rmhd_glm) then
2307 {do ix^db=ixomin^db,ixomax^db\}
2308 f(ix^d,mag(idim))=w(ix^d,psi_)
2309 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
2310 f(ix^d,psi_)=cmax_global**2*w(ix^d,mag(idim))
2311 {end do\}
2312 end if
2314 {do ix^db=ixomin^db,ixomax^db\}
2315 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
2316 {end do\}
2317 else
2318 f(ixo^s,r_e)=zero
2319 endif
2320 ! Get flux of tracer
2321 do iw=1,rmhd_n_tracer
2322 {do ix^db=ixomin^db,ixomax^db\}
2323 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
2324 {end do\}
2325 end do
2327 {do ix^db=ixomin^db,ixomax^db\}
2328 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*w(ix^d,mag(idim))/(dsqrt(^c&w({ix^d},b^c_)**2+)+smalldouble)
2329 f(ix^d,q_)=zero
2330 {end do\}
2331 end if
2332 end subroutine rmhd_get_flux
2333
2334 !> Calculate fluxes within ixO^L with possible splitting
2335 subroutine rmhd_get_flux_split(wC,w,x,ixI^L,ixO^L,idim,f)
2337 use mod_geometry
2338 integer, intent(in) :: ixi^l, ixo^l, idim
2339 ! conservative w
2340 double precision, intent(in) :: wc(ixi^s,nw)
2341 ! primitive w
2342 double precision, intent(in) :: w(ixi^s,nw)
2343 double precision, intent(in) :: x(ixi^s,1:ndim)
2344 double precision,intent(out) :: f(ixi^s,nwflux)
2345 double precision :: vhall(ixi^s,1:ndir)
2346 double precision :: ptotal, btotal(ixo^s,1:ndir)
2347 integer :: iw, ix^d
2348
2349 {do ix^db=ixomin^db,ixomax^db\}
2350 ! Get flux of density
2351 if(has_equi_rho0) then
2352 f(ix^d,rho_)=w(ix^d,mom(idim))*(w(ix^d,rho_)+block%equi_vars(ix^d,equi_rho0_,b0i))
2353 else
2354 f(ix^d,rho_)=w(ix^d,mom(idim))*w(ix^d,rho_)
2355 endif
2356 if(rmhd_energy) then
2357 ptotal=w(ix^d,p_)+half*(^c&w(ix^d,b^c_)**2+)
2358 else
2359 ptotal=rmhd_adiab*w(ix^d,rho_)**rmhd_gamma+half*(^c&w(ix^d,b^c_)**2+)
2360 if(has_equi_pe0) then
2361 ptotal=ptotal-block%equi_vars(ix^d,equi_pe0_,b0i)
2362 end if
2363 end if
2364 if(b0field) then
2365 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)+block%B0(ix^d,^c,idim)\
2366 ptotal=ptotal+(^c&w(ix^d,b^c_)*block%B0(ix^d,^c,idim)+)
2367 ! Get flux of momentum and magnetic field
2368 ! f_i[m_k]=v_i*m_k-b_k*b_i
2369 ^c&f(ix^d,m^c_)=wc(ix^d,mom(idim))*w(ix^d,m^c_)-&
2370 btotal(ix^d,idim)*w(ix^d,b^c_)-w(ix^d,mag(idim))*block%B0(ix^d,^c,idim)\
2371 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
2372 else
2373 ^c&btotal(ix^d,^c)=w(ix^d,b^c_)\
2374 ! Get flux of momentum and magnetic field
2375 ! f_i[m_k]=v_i*m_k-b_k*b_i
2376 ^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_)\
2377 f(ix^d,mom(idim))=f(ix^d,mom(idim))+ptotal
2378 end if
2379 ! f_i[b_k]=v_i*b_k-v_k*b_i
2380 ^c&f(ix^d,b^c_)=w(ix^d,mom(idim))*btotal(ix^d,^c)-btotal(ix^d,idim)*w(ix^d,m^c_)\
2381 ! Get flux of energy
2382 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
2383 if(rmhd_energy) then
2384 f(ix^d,e_)=w(ix^d,mom(idim))*(wc(ix^d,e_)+ptotal)&
2385 -btotal(ix^d,idim)*(^c&w(ix^d,b^c_)*w(ix^d,m^c_)+)
2386 end if
2387 {end do\}
2388 if(rmhd_glm) then
2389 {do ix^db=ixomin^db,ixomax^db\}
2390 f(ix^d,mag(idim))=w(ix^d,psi_)
2391 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
2392 f(ix^d,psi_) = cmax_global**2*w(ix^d,mag(idim))
2393 {end do\}
2394 end if
2396 {do ix^db=ixomin^db,ixomax^db\}
2397 f(ix^d,r_e)=w(ix^d,mom(idim))*wc(ix^d,r_e)
2398 {end do\}
2399 else
2400 f(ixo^s,r_e)=zero
2401 endif
2402 ! Get flux of tracer
2403 do iw=1,rmhd_n_tracer
2404 {do ix^db=ixomin^db,ixomax^db\}
2405 f(ix^d,tracer(iw))=w(ix^d,mom(idim))*w(ix^d,tracer(iw))
2406 {end do\}
2407 end do
2409 {do ix^db=ixomin^db,ixomax^db\}
2410 f(ix^d,e_)=f(ix^d,e_)+w(ix^d,q_)*btotal(ix^d,idim)/(dsqrt(^c&btotal(ix^d,^c)**2+)+smalldouble)
2411 f(ix^d,q_)=zero
2412 {end do\}
2413 end if
2414 end subroutine rmhd_get_flux_split
2415
2416 !> use cell-center flux to get cell-face flux
2417 !> and get the source term as the divergence of the flux
2418 subroutine get_flux_on_cell_face(ixI^L,ixO^L,ff,src)
2420
2421 integer, intent(in) :: ixi^l, ixo^l
2422 double precision, dimension(:^D&,:), intent(inout) :: ff
2423 double precision, intent(out) :: src(ixi^s)
2424
2425 double precision :: ffc(ixi^s,1:ndim)
2426 double precision :: dxinv(ndim)
2427 integer :: idims, ix^d, ixa^l, ixb^l, ixc^l
2428
2429 ixa^l=ixo^l^ladd1;
2430 dxinv=1.d0/dxlevel
2431 ! cell corner flux in ffc
2432 ffc=0.d0
2433 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
2434 {do ix^db=0,1\}
2435 ixbmin^d=ixcmin^d+ix^d;
2436 ixbmax^d=ixcmax^d+ix^d;
2437 ffc(ixc^s,1:ndim)=ffc(ixc^s,1:ndim)+ff(ixb^s,1:ndim)
2438 {end do\}
2439 ffc(ixc^s,1:ndim)=0.5d0**ndim*ffc(ixc^s,1:ndim)
2440 ! flux at cell face
2441 ff(ixi^s,1:ndim)=0.d0
2442 do idims=1,ndim
2443 ixb^l=ixo^l-kr(idims,^d);
2444 ixcmax^d=ixomax^d; ixcmin^d=ixbmin^d;
2445 {do ix^db=0,1 \}
2446 if({ ix^d==0 .and. ^d==idims | .or.}) then
2447 ixbmin^d=ixcmin^d-ix^d;
2448 ixbmax^d=ixcmax^d-ix^d;
2449 ff(ixc^s,idims)=ff(ixc^s,idims)+ffc(ixb^s,idims)
2450 end if
2451 {end do\}
2452 ff(ixc^s,idims)=ff(ixc^s,idims)*0.5d0**(ndim-1)
2453 end do
2454 src=0.d0
2455 if(slab_uniform) then
2456 do idims=1,ndim
2457 ff(ixa^s,idims)=dxinv(idims)*ff(ixa^s,idims)
2458 ixb^l=ixo^l-kr(idims,^d);
2459 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
2460 end do
2461 else
2462 do idims=1,ndim
2463 ff(ixa^s,idims)=ff(ixa^s,idims)*block%surfaceC(ixa^s,idims)
2464 ixb^l=ixo^l-kr(idims,^d);
2465 src(ixo^s)=src(ixo^s)+ff(ixo^s,idims)-ff(ixb^s,idims)
2466 end do
2467 src(ixo^s)=src(ixo^s)/block%dvolume(ixo^s)
2468 end if
2469 end subroutine get_flux_on_cell_face
2470
2471 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
2472 subroutine rmhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
2476 use mod_cak_force, only: cak_add_source
2477
2478 integer, intent(in) :: ixi^l, ixo^l
2479 double precision, intent(in) :: qdt,dtfactor
2480 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw), x(ixi^s,1:ndim)
2481 double precision, intent(inout) :: w(ixi^s,1:nw)
2482 logical, intent(in) :: qsourcesplit
2483 logical, intent(inout) :: active
2484
2485 ! TODO local_timestep support is only added for splitting
2486 ! but not for other nonideal terms such gravity, RC, viscosity,..
2487 ! it will also only work for divbfix 'linde', which does not require
2488 ! modification as it does not use dt in the update
2489 if (.not. qsourcesplit) then
2490 if(has_equi_pe0) then
2491 active = .true.
2492 call add_pe0_divv(qdt,dtfactor,ixi^l,ixo^l,wctprim,w,x)
2493 end if
2495 call add_hypertc_source(qdt,ixi^l,ixo^l,wct,w,x,wctprim)
2496 end if
2497 ! Source for B0 splitting
2498 if (b0field) then
2499 active = .true.
2500 call add_source_b0split(qdt,dtfactor,ixi^l,ixo^l,wctprim,w,x)
2501 end if
2502 ! Sources for resistivity in eqs. for e, B1, B2 and B3
2503 if (abs(rmhd_eta)>smalldouble)then
2504 active = .true.
2505 call add_source_res2(qdt,ixi^l,ixo^l,wct,w,x)
2506 end if
2507 if (rmhd_eta_hyper>0.d0)then
2508 active = .true.
2509 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
2510 end if
2511 end if
2512 {^nooned
2513 if(source_split_divb .eqv. qsourcesplit) then
2514 ! Sources related to div B
2515 select case (type_divb)
2516 case (divb_ct)
2517 continue ! Do nothing
2518 case (divb_linde)
2519 active = .true.
2520 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
2521 case (divb_glm)
2522 active = .true.
2523 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
2524 case (divb_powel)
2525 active = .true.
2526 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
2527 case (divb_janhunen)
2528 active = .true.
2529 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
2530 case (divb_lindejanhunen)
2531 active = .true.
2532 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
2533 call add_source_janhunen(qdt,ixi^l,ixo^l,wctprim,w,x)
2534 case (divb_lindepowel)
2535 active = .true.
2536 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
2537 call add_source_powel(qdt,ixi^l,ixo^l,wctprim,w,x)
2538 case (divb_lindeglm)
2539 active = .true.
2540 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
2541 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
2542 case (divb_multigrid)
2543 continue ! Do nothing
2544 case (divb_none)
2545 ! Do nothing
2546 case default
2547 call mpistop('Unknown divB fix')
2548 end select
2549 end if
2550 }
2551 if(rmhd_viscosity) then
2552 call viscosity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
2553 w,x,rmhd_energy,qsourcesplit,active)
2554 end if
2555 if(rmhd_gravity) then
2556 call gravity_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
2557 w,x,gravity_energy,qsourcesplit,active)
2558 end if
2559 if (rmhd_cak_force) then
2560 call cak_add_source(qdt,ixi^l,ixo^l,wct,w,x,rmhd_energy,qsourcesplit,active)
2561 end if
2562 !> This is where the radiation force and heating/cooling are added
2563 call rmhd_add_radiation_source(qdt,ixi^l,ixo^l,wct,wctprim,w,x,qsourcesplit,active)
2564 ! update temperature from new pressure, density, and old ionization degree
2566 if(.not.qsourcesplit) then
2567 active = .true.
2568 call rmhd_update_temperature(ixi^l,ixo^l,wct,w,x)
2569 end if
2570 end if
2571 end subroutine rmhd_add_source
2572
2573 subroutine rmhd_add_radiation_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
2574 use mod_constants
2576 use mod_usr_methods
2577 use mod_fld
2578 use mod_afld
2579 integer, intent(in) :: ixi^l, ixo^l
2580 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
2581 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
2582 double precision, intent(inout) :: w(ixi^s,1:nw)
2583 logical, intent(in) :: qsourcesplit
2584 logical, intent(inout) :: active
2585 double precision :: cmax(ixi^s)
2586
2587 select case(rmhd_radiation_formalism)
2588 case('fld')
2589 call fld_get_diffcoef_central(w, wct, wctprim, x, ixi^l, ixo^l,.true.)
2590 !> radiation force
2591 if(rmhd_radiation_force) call add_fld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,rmhd_energy,qsourcesplit,active)
2592 call rmhd_handle_small_values(.true., w, x, ixi^l, ixo^l, 'fld_e_interact')
2593 case('afld')
2594 call afld_get_diffcoef_central(w, wct, wctprim, x, ixi^l, ixo^l,.true.)
2595 !> radiation force
2596 if(rmhd_radiation_force) call add_afld_rad_force(qdt,ixi^l,ixo^l,wct,wctprim,w,x,rmhd_energy,qsourcesplit,active)
2597 call rmhd_handle_small_values(.true., w, x, ixi^l, ixo^l, 'fld_e_interact')
2598 !> photon tiring, heating and cooling
2599 if(rmhd_energy) then
2600 if (rmhd_energy_interact) call get_afld_energy_interact(qdt,ixi^l,ixo^l,wct,w,x,rmhd_energy,qsourcesplit,active)
2601 endif
2602 case default
2603 call mpistop('Radiation formalism unknown')
2604 end select
2605 end subroutine rmhd_add_radiation_source
2606
2607 subroutine add_pe0_divv(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
2609 use mod_geometry
2610 integer, intent(in) :: ixi^l, ixo^l
2611 double precision, intent(in) :: qdt,dtfactor
2612 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
2613 double precision, intent(inout) :: w(ixi^s,1:nw)
2614 double precision :: divv(ixi^s)
2615
2616 if(slab_uniform) then
2617 if(nghostcells .gt. 2) then
2618 call divvector(wct(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,3)
2619 else
2620 call divvector(wct(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv,2)
2621 end if
2622 else
2623 call divvector(wct(ixi^s,mom(1:ndir)),ixi^l,ixo^l,divv)
2624 end if
2625 if(local_timestep) then
2626 w(ixo^s,e_)=w(ixo^s,e_)-dtfactor*block%dt(ixo^s)*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
2627 else
2628 w(ixo^s,e_)=w(ixo^s,e_)-qdt*block%equi_vars(ixo^s,equi_pe0_,0)*divv(ixo^s)
2629 end if
2630 end subroutine add_pe0_divv
2631
2632 subroutine get_tau(ixI^L,ixO^L,w,Te,tau,sigT5)
2634 integer, intent(in) :: ixi^l, ixo^l
2635 double precision, dimension(ixI^S,1:nw), intent(in) :: w
2636 double precision, dimension(ixI^S), intent(in) :: te
2637 double precision, dimension(ixI^S), intent(out) :: tau,sigt5
2638 double precision :: dxmin,taumin
2639 double precision, dimension(ixI^S) :: sigt7,eint
2640 integer :: ix^d
2641
2642 taumin=4.d0
2643 !> w supposed to be wCTprim here
2644 if(rmhd_trac) then
2645 where(te(ixo^s) .lt. block%wextra(ixo^s,tcoff_))
2646 sigt5(ixo^s)=hypertc_kappa*sqrt(block%wextra(ixo^s,tcoff_)**5)
2647 sigt7(ixo^s)=sigt5(ixo^s)*block%wextra(ixo^s,tcoff_)
2648 else where
2649 sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
2650 sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
2651 end where
2652 else
2653 sigt5(ixo^s)=hypertc_kappa*sqrt(te(ixo^s)**5)
2654 sigt7(ixo^s)=sigt5(ixo^s)*te(ixo^s)
2655 end if
2656 eint(ixo^s)=w(ixo^s,p_)/(rmhd_gamma-one)
2657 tau(ixo^s)=max(taumin*dt,sigt7(ixo^s)/eint(ixo^s)/cmax_global**2)
2658 end subroutine get_tau
2659
2660 subroutine add_hypertc_source(qdt,ixI^L,ixO^L,wCT,w,x,wCTprim)
2662 integer, intent(in) :: ixi^l,ixo^l
2663 double precision, intent(in) :: qdt
2664 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
2665 double precision, dimension(ixI^S,1:nw), intent(in) :: wct,wctprim
2666 double precision, dimension(ixI^S,1:nw), intent(inout) :: w
2667 double precision :: invdx
2668 double precision, dimension(ixI^S) :: te,tau,sigt,htc_qsrc,tface,r
2669 double precision, dimension(ixI^S) :: htc_esrc,bsum,bunit
2670 double precision, dimension(ixI^S,1:ndim) :: btot
2671 integer :: idims
2672 integer :: hxc^l,hxo^l,ixc^l,jxc^l,jxo^l,kxc^l
2673
2674 call rmhd_get_rfactor(wctprim,x,ixi^l,ixi^l,r)
2675
2676 !Te(ixI^S)=wCTprim(ixI^S,p_)/wCT(ixI^S,rho_)
2677 te(ixi^s)=wctprim(ixi^s,p_)/(r(ixi^s)*w(ixi^s,rho_))
2678 call get_tau(ixi^l,ixo^l,wctprim,te,tau,sigt)
2679 htc_qsrc=zero
2680 do idims=1,ndim
2681 if(b0field) then
2682 btot(ixo^s,idims)=wct(ixo^s,mag(idims))+block%B0(ixo^s,idims,0)
2683 else
2684 btot(ixo^s,idims)=wct(ixo^s,mag(idims))
2685 endif
2686 enddo
2687 bsum(ixo^s)=sqrt(sum(btot(ixo^s,:)**2,dim=ndim+1))+smalldouble
2688 do idims=1,ndim
2689 invdx=1.d0/dxlevel(idims)
2690 ixc^l=ixo^l;
2691 ixcmin^d=ixomin^d-kr(idims,^d);ixcmax^d=ixomax^d;
2692 jxc^l=ixc^l+kr(idims,^d);
2693 kxc^l=jxc^l+kr(idims,^d);
2694 hxc^l=ixc^l-kr(idims,^d);
2695 hxo^l=ixo^l-kr(idims,^d);
2696 tface(ixc^s)=(7.d0*(te(ixc^s)+te(jxc^s))-(te(hxc^s)+te(kxc^s)))/12.d0
2697 bunit(ixo^s)=btot(ixo^s,idims)/bsum(ixo^s)
2698 htc_qsrc(ixo^s)=htc_qsrc(ixo^s)+sigt(ixo^s)*bunit(ixo^s)*(tface(ixo^s)-tface(hxo^s))*invdx
2699 end do
2700 htc_qsrc(ixo^s)=(htc_qsrc(ixo^s)+wct(ixo^s,q_))/tau(ixo^s)
2701 w(ixo^s,q_)=w(ixo^s,q_)-qdt*htc_qsrc(ixo^s)
2702 end subroutine add_hypertc_source
2703
2704 !> Compute the Lorentz force (JxB)
2705 subroutine get_lorentz_force(ixI^L,ixO^L,w,JxB)
2707 integer, intent(in) :: ixi^l, ixo^l
2708 double precision, intent(in) :: w(ixi^s,1:nw)
2709 double precision, intent(inout) :: jxb(ixi^s,3)
2710 double precision :: a(ixi^s,3), b(ixi^s,3)
2711 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
2712 double precision :: current(ixi^s,7-2*ndir:3)
2713 integer :: idir, idirmin
2714
2715 b=0.0d0
2716 if(b0field) then
2717 do idir = 1, ndir
2718 b(ixo^s, idir) = w(ixo^s,mag(idir))+block%B0(ixo^s,idir,0)
2719 end do
2720 else
2721 do idir = 1, ndir
2722 b(ixo^s, idir) = w(ixo^s,mag(idir))
2723 end do
2724 end if
2725 ! store J current in a
2726 call get_current(w,ixi^l,ixo^l,idirmin,current)
2727 a=0.0d0
2728 do idir=7-2*ndir,3
2729 a(ixo^s,idir)=current(ixo^s,idir)
2730 end do
2731 call cross_product(ixi^l,ixo^l,a,b,jxb)
2732 end subroutine get_lorentz_force
2733
2734 !> Compute 1/(1+v_A^2/c^2) for semirelativistic MHD, where v_A is the Alfven
2735 !> velocity
2736 subroutine rmhd_gamma2_alfven(ixI^L, ixO^L, w, gamma_A2)
2738 integer, intent(in) :: ixi^l, ixo^l
2739 double precision, intent(in) :: w(ixi^s, nw)
2740 double precision, intent(out) :: gamma_a2(ixo^s)
2741 double precision :: rho(ixi^s)
2742
2743 ! rmhd_get_rho cannot be used as x is not a param
2744 if(has_equi_rho0) then
2745 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
2746 else
2747 rho(ixo^s) = w(ixo^s,rho_)
2748 endif
2749 ! Compute the inverse of 1 + B^2/(rho * c^2)
2750 gamma_a2(ixo^s) = 1.0d0/(1.0d0+rmhd_mag_en_all(w, ixi^l, ixo^l)/rho(ixo^s)*inv_squared_c)
2751 end subroutine rmhd_gamma2_alfven
2752
2753 !> Compute 1/sqrt(1+v_A^2/c^2) for semirelativisitic MHD, where v_A is the
2754 !> Alfven velocity
2755 function rmhd_gamma_alfven(w, ixI^L, ixO^L) result(gamma_A)
2757 integer, intent(in) :: ixi^l, ixo^l
2758 double precision, intent(in) :: w(ixi^s, nw)
2759 double precision :: gamma_a(ixo^s)
2760
2761 call rmhd_gamma2_alfven(ixi^l, ixo^l, w, gamma_a)
2762 gamma_a = sqrt(gamma_a)
2763 end function rmhd_gamma_alfven
2764
2765 subroutine rmhd_get_rho(w,x,ixI^L,ixO^L,rho)
2767 integer, intent(in) :: ixi^l, ixo^l
2768 double precision, intent(in) :: w(ixi^s,1:nw),x(ixi^s,1:ndim)
2769 double precision, intent(out) :: rho(ixi^s)
2770
2771 if(has_equi_rho0) then
2772 rho(ixo^s) = w(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i)
2773 else
2774 rho(ixo^s) = w(ixo^s,rho_)
2775 endif
2776 end subroutine rmhd_get_rho
2777
2778 !> handle small or negative internal energy
2779 subroutine rmhd_handle_small_ei(w, x, ixI^L, ixO^L, ie, subname)
2782 integer, intent(in) :: ixi^l,ixo^l, ie
2783 double precision, intent(inout) :: w(ixi^s,1:nw)
2784 double precision, intent(in) :: x(ixi^s,1:ndim)
2785 character(len=*), intent(in) :: subname
2786 double precision :: rho(ixi^s)
2787 integer :: idir
2788 logical :: flag(ixi^s,1:nw)
2789
2790 flag=.false.
2791 if(has_equi_pe0) then
2792 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1<small_e)&
2793 flag(ixo^s,ie)=.true.
2794 else
2795 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
2796 endif
2797 if(any(flag(ixo^s,ie))) then
2798 select case (small_values_method)
2799 case ("replace")
2800 if(has_equi_pe0) then
2801 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
2802 block%equi_vars(ixo^s,equi_pe0_,0)*inv_gamma_1
2803 else
2804 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
2805 endif
2806 case ("average")
2807 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
2808 case default
2809 ! small values error shows primitive variables
2810 w(ixo^s,e_)=w(ixo^s,e_)*gamma_1
2811 call rmhd_get_rho(w,x,ixi^l,ixo^l,rho)
2812 do idir = 1, ndir
2813 w(ixo^s, mom(idir)) = w(ixo^s, mom(idir))/rho(ixo^s)
2814 end do
2815 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
2816 end select
2817 end if
2818 end subroutine rmhd_handle_small_ei
2819
2820 subroutine rmhd_update_temperature(ixI^L,ixO^L,wCT,w,x)
2823
2824 integer, intent(in) :: ixi^l, ixo^l
2825 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
2826 double precision, intent(inout) :: w(ixi^s,1:nw)
2827
2828 double precision :: iz_h(ixo^s),iz_he(ixo^s), pth(ixi^s)
2829
2830 call ionization_degree_from_temperature(ixi^l,ixo^l,wct(ixi^s,te_),iz_h,iz_he)
2831
2832 call rmhd_get_pthermal(w,x,ixi^l,ixo^l,pth)
2833
2834 w(ixo^s,te_)=(2.d0+3.d0*he_abundance)*pth(ixo^s)/(w(ixo^s,rho_)*(1.d0+iz_h(ixo^s)+&
2835 he_abundance*(iz_he(ixo^s)*(iz_he(ixo^s)+1.d0)+1.d0)))
2836 end subroutine rmhd_update_temperature
2837
2838 !> Source terms after split off time-independent magnetic field
2839 subroutine add_source_b0split(qdt,dtfactor,ixI^L,ixO^L,wCT,w,x)
2841 integer, intent(in) :: ixi^l, ixo^l
2842 double precision, intent(in) :: qdt, dtfactor,wct(ixi^s,1:nw), x(ixi^s,1:ndim)
2843 double precision, intent(inout) :: w(ixi^s,1:nw)
2844 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
2845 integer :: idir
2846
2847 a=0.d0
2848 b=0.d0
2849 ! for force-free field J0xB0 =0
2850 if(.not.b0field_forcefree) then
2851 ! store B0 magnetic field in b
2852 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
2853 ! store J0 current in a
2854 do idir=7-2*ndir,3
2855 a(ixo^s,idir)=block%J0(ixo^s,idir)
2856 end do
2857 call cross_product(ixi^l,ixo^l,a,b,axb)
2858 if(local_timestep) then
2859 do idir=1,3
2860 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
2861 enddo
2862 else
2863 axb(ixo^s,:)=axb(ixo^s,:)*qdt
2864 endif
2865 ! add J0xB0 source term in momentum equations
2866 w(ixo^s,mom(1:ndir))=w(ixo^s,mom(1:ndir))+axb(ixo^s,1:ndir)
2867 end if
2868 if(total_energy) then
2869 a=0.d0
2870 ! for free-free field -(vxB0) dot J0 =0
2871 b(ixo^s,:)=wct(ixo^s,mag(:))
2872 ! store full magnetic field B0+B1 in b
2873 if(.not.b0field_forcefree) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
2874 ! store velocity in a
2875 a(ixi^s,1:ndir)=wct(ixi^s,mom(1:ndir))
2876 ! -E = a x b
2877 call cross_product(ixi^l,ixo^l,a,b,axb)
2878 if(local_timestep) then
2879 do idir=1,3
2880 axb(ixo^s,idir)=axb(ixo^s,idir)*block%dt(ixo^s)*dtfactor
2881 enddo
2882 else
2883 axb(ixo^s,:)=axb(ixo^s,:)*qdt
2884 endif
2885 ! add -(vxB) dot J0 source term in energy equation
2886 do idir=7-2*ndir,3
2887 w(ixo^s,e_)=w(ixo^s,e_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
2888 end do
2889 end if
2890 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
2891 end subroutine add_source_b0split
2892
2893 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
2894 !> each direction, non-conservative. If the fourthorder precompiler flag is
2895 !> set, uses fourth order central difference for the laplacian. Then the
2896 !> stencil is 5 (2 neighbours).
2897 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
2899 use mod_usr_methods
2900 use mod_geometry
2901 integer, intent(in) :: ixi^l, ixo^l
2902 double precision, intent(in) :: qdt
2903 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
2904 double precision, intent(inout) :: w(ixi^s,1:nw)
2905 integer :: ixa^l,idir,jdir,kdir,idirmin,idim,jxo^l,hxo^l,ix
2906 integer :: lxo^l, kxo^l
2907 double precision :: tmp(ixi^s),tmp2(ixi^s)
2908 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
2909 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
2910 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
2911
2912 ! Calculating resistive sources involve one extra layer
2913 ixa^l=ixo^l^ladd2;
2914 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
2915 call mpistop("Error in add_source_res1: Non-conforming input limits")
2916 ! Calculate current density and idirmin
2917 call get_current(wct,ixi^l,ixo^l,idirmin,current)
2918 if (rmhd_eta>zero)then
2919 eta(ixa^s)=rmhd_eta
2920 gradeta(ixo^s,1:ndim)=zero
2921 else
2922 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
2923 ! assumes that eta is not function of current?
2924 do idim=1,ndim
2925 call gradient(eta,ixi^l,ixo^l,idim,tmp)
2926 gradeta(ixo^s,idim)=tmp(ixo^s)
2927 end do
2928 end if
2929 if(b0field) then
2930 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
2931 else
2932 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
2933 end if
2934 do idir=1,ndir
2935 ! Put B_idir into tmp2 and eta*Laplace B_idir into tmp
2936 tmp(ixo^s)=zero
2937 tmp2(ixi^s)=bf(ixi^s,idir)
2938 do idim=1,ndim
2939 lxo^l=ixo^l+2*kr(idim,^d);
2940 jxo^l=ixo^l+kr(idim,^d);
2941 hxo^l=ixo^l-kr(idim,^d);
2942 kxo^l=ixo^l-2*kr(idim,^d);
2943 tmp(ixo^s)=tmp(ixo^s)+&
2944 (-tmp2(lxo^s)+16.0d0*tmp2(jxo^s)-30.0d0*tmp2(ixo^s)+16.0d0*tmp2(hxo^s)-tmp2(kxo^s)) &
2945 /(12.0d0 * dxlevel(idim)**2)
2946 end do
2947 ! Multiply by eta
2948 tmp(ixo^s)=tmp(ixo^s)*eta(ixo^s)
2949 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
2950 if (rmhd_eta<zero)then
2951 do jdir=1,ndim; do kdir=idirmin,3
2952 if (lvc(idir,jdir,kdir)/=0)then
2953 if (lvc(idir,jdir,kdir)==1)then
2954 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
2955 else
2956 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
2957 end if
2958 end if
2959 end do; end do
2960 end if
2961 ! Add sources related to eta*laplB-grad(eta) x J to B and e
2962 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
2963 if(total_energy) then
2964 w(ixo^s,e_)=w(ixo^s,e_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
2965 end if
2966 end do ! idir
2967 if(rmhd_energy) then
2968 ! de/dt+=eta*J**2
2969 w(ixo^s,e_)=w(ixo^s,e_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
2970 end if
2971 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
2972 end subroutine add_source_res1
2973
2974 !> Add resistive source to w within ixO
2975 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
2976 subroutine add_source_res2(qdt,ixI^L,ixO^L,wCT,w,x)
2978 use mod_usr_methods
2979 use mod_geometry
2980 integer, intent(in) :: ixi^l, ixo^l
2981 double precision, intent(in) :: qdt
2982 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
2983 double precision, intent(inout) :: w(ixi^s,1:nw)
2984 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
2985 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
2986 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
2987 integer :: ixa^l,idir,idirmin,idirmin1
2988
2989 ixa^l=ixo^l^ladd2;
2990 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
2991 call mpistop("Error in add_source_res2: Non-conforming input limits")
2992 ixa^l=ixo^l^ladd1;
2993 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
2994 ! Determine exact value of idirmin while doing the loop.
2995 call get_current(wct,ixi^l,ixa^l,idirmin,current)
2996 tmpvec=zero
2997 if(rmhd_eta>zero)then
2998 do idir=idirmin,3
2999 tmpvec(ixa^s,idir)=current(ixa^s,idir)*rmhd_eta
3000 end do
3001 else
3002 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
3003 do idir=idirmin,3
3004 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
3005 end do
3006 end if
3007 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
3008 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
3009 if(stagger_grid) then
3010 if(ndim==2.and.ndir==3) then
3011 ! if 2.5D
3012 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
3013 end if
3014 else
3015 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
3016 end if
3017 if(rmhd_energy) then
3018 if(rmhd_eta>zero)then
3019 tmp(ixo^s)=qdt*rmhd_eta*sum(current(ixo^s,:)**2,dim=ndim+1)
3020 else
3021 tmp(ixo^s)=qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
3022 end if
3023 if(total_energy) then
3024 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
3025 ! de1/dt= eta J^2 - B1 dot curl(eta J)
3026 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)-&
3027 qdt*sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1)
3028 else
3029 ! add eta*J**2 source term in the internal energy equation
3030 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)
3031 end if
3032 end if
3033 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res2')
3034 end subroutine add_source_res2
3035
3036 !> Add Hyper-resistive source to w within ixO
3037 !> Uses 9 point stencil (4 neighbours) in each direction.
3038 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
3040 use mod_geometry
3041 integer, intent(in) :: ixi^l, ixo^l
3042 double precision, intent(in) :: qdt
3043 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3044 double precision, intent(inout) :: w(ixi^s,1:nw)
3045 !.. local ..
3046 double precision :: current(ixi^s,7-2*ndir:3)
3047 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
3048 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
3049
3050 ixa^l=ixo^l^ladd3;
3051 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
3052 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
3053 call get_current(wct,ixi^l,ixa^l,idirmin,current)
3054 tmpvec(ixa^s,1:ndir)=zero
3055 do jdir=idirmin,3
3056 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
3057 end do
3058 ixa^l=ixo^l^ladd2;
3059 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
3060 ixa^l=ixo^l^ladd1;
3061 tmpvec(ixa^s,1:ndir)=zero
3062 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
3063 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*rmhd_eta_hyper
3064 ixa^l=ixo^l;
3065 tmpvec2(ixa^s,1:ndir)=zero
3066 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
3067 do idir=1,ndir
3068 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
3069 end do
3070 if(total_energy) then
3071 ! de/dt= +div(B x Ehyper)
3072 ixa^l=ixo^l^ladd1;
3073 tmpvec2(ixa^s,1:ndir)=zero
3074 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
3075 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
3076 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
3077 end do; end do; end do
3078 tmp(ixo^s)=zero
3079 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
3080 w(ixo^s,e_)=w(ixo^s,e_)+tmp(ixo^s)*qdt
3081 end if
3082 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
3083 end subroutine add_source_hyperres
3084
3085 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
3086 ! Add divB related sources to w within ixO
3087 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
3088 ! giving the EGLM-MHD scheme or GLM-MHD scheme
3090 use mod_geometry
3091 integer, intent(in) :: ixi^l, ixo^l
3092 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3093 double precision, intent(inout) :: w(ixi^s,1:nw)
3094 double precision:: divb(ixi^s), gradpsi(ixi^s), ba(ixo^s,1:ndir)
3095 integer :: idir
3096
3097 ! dPsi/dt = - Ch^2/Cp^2 Psi
3098 if (rmhd_glm_alpha < zero) then
3099 w(ixo^s,psi_) = abs(rmhd_glm_alpha)*wct(ixo^s,psi_)
3100 else
3101 ! implicit update of Psi variable
3102 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
3103 if(slab_uniform) then
3104 w(ixo^s,psi_) = dexp(-qdt*cmax_global*rmhd_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
3105 else
3106 w(ixo^s,psi_) = dexp(-qdt*cmax_global*rmhd_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
3107 end if
3108 end if
3109 if(rmhd_glm_extended) then
3110 if(b0field) then
3111 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))+block%B0(ixo^s,1:ndir,0)
3112 else
3113 ba(ixo^s,1:ndir)=wct(ixo^s,mag(1:ndir))
3114 end if
3115 ! gradient of Psi
3116 if(total_energy) then
3117 do idir=1,ndim
3118 select case(typegrad)
3119 case("central")
3120 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
3121 case("limited")
3122 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idir,gradpsi)
3123 end select
3124 ! e = e -qdt (b . grad(Psi))
3125 w(ixo^s,e_) = w(ixo^s,e_)-qdt*ba(ixo^s,idir)*gradpsi(ixo^s)
3126 end do
3127 end if
3128 ! We calculate now div B
3129 call get_divb(wct,ixi^l,ixo^l,divb,rmhd_divb_nth)
3130 ! m = m - qdt b div b
3131 do idir=1,ndir
3132 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-qdt*ba(ixo^s,idir)*divb(ixo^s)
3133 end do
3134 end if
3135 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
3136 end subroutine add_source_glm
3137
3138 !> Add divB related sources to w within ixO corresponding to Powel
3139 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
3141 integer, intent(in) :: ixi^l, ixo^l
3142 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3143 double precision, intent(inout) :: w(ixi^s,1:nw)
3144 double precision :: divb(ixi^s), ba(1:ndir)
3145 integer :: idir, ix^d
3146
3147 ! calculate div B
3148 call get_divb(wct,ixi^l,ixo^l,divb,rmhd_divb_nth)
3149 if(b0field) then
3150 {do ix^db=ixomin^db,ixomax^db\}
3151 ! b = b - qdt v * div b
3152 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
3153 ! m = m - qdt b div b
3154 ^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)\
3155 if (total_energy) then
3156 ! e = e - qdt (v . b) * div b
3157 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)
3158 end if
3159 {end do\}
3160 else
3161 {do ix^db=ixomin^db,ixomax^db\}
3162 ! b = b - qdt v * div b
3163 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
3164 ! m = m - qdt b div b
3165 ^c&w(ix^d,m^c_)=w(ix^d,m^c_)-qdt*wct(ix^d,b^c_)*divb(ix^d)\
3166 if (total_energy) then
3167 ! e = e - qdt (v . b) * div b
3168 w(ix^d,e_)=w(ix^d,e_)-qdt*(^c&wct(ix^d,m^c_)*wct(ix^d,b^c_)+)*divb(ix^d)
3169 end if
3170 {end do\}
3171 end if
3172 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
3173 end subroutine add_source_powel
3174
3175 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
3176 ! Add divB related sources to w within ixO
3177 ! corresponding to Janhunen, just the term in the induction equation.
3179 integer, intent(in) :: ixi^l, ixo^l
3180 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3181 double precision, intent(inout) :: w(ixi^s,1:nw)
3182 double precision :: divb(ixi^s)
3183 integer :: idir, ix^d
3184
3185 ! calculate div B
3186 call get_divb(wct,ixi^l,ixo^l,divb,rmhd_divb_nth)
3187 {do ix^db=ixomin^db,ixomax^db\}
3188 ! b = b - qdt v * div b
3189 ^c&w(ix^d,b^c_)=w(ix^d,b^c_)-qdt*wct(ix^d,m^c_)*divb(ix^d)\
3190 {end do\}
3191 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
3192 end subroutine add_source_janhunen
3193
3194 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
3195 ! Add Linde's divB related sources to wnew within ixO
3197 use mod_geometry
3198 integer, intent(in) :: ixi^l, ixo^l
3199 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3200 double precision, intent(inout) :: w(ixi^s,1:nw)
3201 double precision :: divb(ixi^s),graddivb(ixi^s)
3202 integer :: idim, idir, ixp^l, i^d, iside
3203 logical, dimension(-1:1^D&) :: leveljump
3204
3205 ! Calculate div B
3206 ixp^l=ixo^l^ladd1;
3207 call get_divb(wct,ixi^l,ixp^l,divb,rmhd_divb_nth)
3208 ! for AMR stability, retreat one cell layer from the boarders of level jump
3209 {do i^db=-1,1\}
3210 if(i^d==0|.and.) cycle
3211 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
3212 leveljump(i^d)=.true.
3213 else
3214 leveljump(i^d)=.false.
3215 end if
3216 {end do\}
3217 ixp^l=ixo^l;
3218 do idim=1,ndim
3219 select case(idim)
3220 {case(^d)
3221 do iside=1,2
3222 i^dd=kr(^dd,^d)*(2*iside-3);
3223 if (leveljump(i^dd)) then
3224 if (iside==1) then
3225 ixpmin^d=ixomin^d-i^d
3226 else
3227 ixpmax^d=ixomax^d-i^d
3228 end if
3229 end if
3230 end do
3231 \}
3232 end select
3233 end do
3234 ! Add Linde's diffusive terms
3235 do idim=1,ndim
3236 ! Calculate grad_idim(divb)
3237 select case(typegrad)
3238 case("central")
3239 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
3240 case("limited")
3241 call gradientl(divb,ixi^l,ixp^l,idim,graddivb)
3242 end select
3243 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
3244 if (slab_uniform) then
3245 graddivb(ixp^s)=graddivb(ixp^s)*divbdiff/(^d&1.0d0/dxlevel(^d)**2+)
3246 else
3247 graddivb(ixp^s)=graddivb(ixp^s)*divbdiff &
3248 /(^d&1.0d0/block%ds(ixp^s,^d)**2+)
3249 end if
3250 w(ixp^s,mag(idim))=w(ixp^s,mag(idim))+graddivb(ixp^s)
3251
3252 if (typedivbdiff=='all' .and. total_energy) then
3253 ! e += B_idim*eta*grad_idim(divb)
3254 w(ixp^s,e_)=w(ixp^s,e_)+wct(ixp^s,mag(idim))*graddivb(ixp^s)
3255 end if
3256 end do
3257 if (fix_small_values) call rmhd_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
3258 end subroutine add_source_linde
3259
3260 !> get dimensionless div B = |divB| * volume / area / |B|
3261 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
3263 integer, intent(in) :: ixi^l, ixo^l
3264 double precision, intent(in) :: w(ixi^s,1:nw)
3265 double precision :: divb(ixi^s), dsurface(ixi^s)
3266 double precision :: invb(ixo^s)
3267 integer :: ixa^l,idims
3268
3269 call get_divb(w,ixi^l,ixo^l,divb)
3270 invb(ixo^s)=sqrt(rmhd_mag_en_all(w,ixi^l,ixo^l))
3271 where(invb(ixo^s)/=0.d0)
3272 invb(ixo^s)=1.d0/invb(ixo^s)
3273 end where
3274 if(slab_uniform) then
3275 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
3276 else
3277 ixamin^d=ixomin^d-1;
3278 ixamax^d=ixomax^d-1;
3279 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
3280 do idims=1,ndim
3281 ixa^l=ixo^l-kr(idims,^d);
3282 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
3283 end do
3284 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
3285 block%dvolume(ixo^s)/dsurface(ixo^s)
3286 end if
3287 end subroutine get_normalized_divb
3288
3289 !> Calculate idirmin and the idirmin:3 components of the common current array
3290 !> make sure that dxlevel(^D) is set correctly.
3291 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
3293 use mod_geometry
3294 integer, intent(in) :: ixo^l, ixi^l
3295 double precision, intent(in) :: w(ixi^s,1:nw)
3296 integer, intent(out) :: idirmin
3297 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
3298 double precision :: current(ixi^s,7-2*ndir:3)
3299 integer :: idir, idirmin0
3300
3301 idirmin0 = 7-2*ndir
3302 call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
3303 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
3304 block%J0(ixo^s,idirmin0:3)
3305 end subroutine get_current
3306
3307 !> If resistivity is not zero, check diffusion time limit for dt
3308 subroutine rmhd_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
3310 use mod_usr_methods
3312 use mod_gravity, only: gravity_get_dt
3313 use mod_cak_force, only: cak_get_dt
3314 use mod_fld, only: fld_radforce_get_dt
3316 integer, intent(in) :: ixi^l, ixo^l
3317 double precision, intent(inout) :: dtnew
3318 double precision, intent(in) :: dx^d
3319 double precision, intent(in) :: w(ixi^s,1:nw)
3320 double precision, intent(in) :: x(ixi^s,1:ndim)
3321 double precision :: dxarr(ndim)
3322 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
3323 integer :: idirmin,idim
3324
3325 dtnew = bigdouble
3326
3327 if (.not. dt_c) then
3328 ^d&dxarr(^d)=dx^d;
3329 if (rmhd_eta>zero)then
3330 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/rmhd_eta
3331 else if (rmhd_eta<zero)then
3332 call get_current(w,ixi^l,ixo^l,idirmin,current)
3333 call usr_special_resistivity(w,ixi^l,ixo^l,idirmin,x,current,eta)
3334 dtnew=bigdouble
3335 do idim=1,ndim
3336 if(slab_uniform) then
3337 dtnew=min(dtnew,&
3338 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
3339 else
3340 dtnew=min(dtnew,&
3341 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
3342 end if
3343 end do
3344 end if
3345 if(rmhd_eta_hyper>zero) then
3346 if(slab_uniform) then
3347 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/rmhd_eta_hyper,dtnew)
3348 else
3349 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/rmhd_eta_hyper,dtnew)
3350 end if
3351 end if
3352 if(rmhd_radiation_force) then
3353 select case(rmhd_radiation_formalism)
3354 case('fld')
3355 call fld_radforce_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
3356 case('afld')
3357 call afld_radforce_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
3358 case default
3359 call mpistop('Radiation formalism unknown')
3360 end select
3361 endif
3362 if(rmhd_viscosity) then
3363 call viscosity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
3364 end if
3365 if(rmhd_gravity) then
3366 call gravity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
3367 end if
3368 if (rmhd_cak_force) then
3369 call cak_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
3370 end if
3371 else
3372 {^ifoned dtnew = dx1*unit_velocity/const_c}
3373 {^nooned dtnew = min(dx^d*unit_velocity/const_c)}
3374 endif
3375 end subroutine rmhd_get_dt
3376
3377 ! Add geometrical source terms to w
3378 subroutine rmhd_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
3380 use mod_geometry
3381 integer, intent(in) :: ixi^l, ixo^l
3382 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
3383 double precision, intent(inout) :: wct(ixi^s,1:nw),wprim(ixi^s,1:nw),w(ixi^s,1:nw)
3384 double precision :: tmp,tmp1,invr,cot
3385 integer :: ix^d
3386 integer :: mr_,mphi_ ! Polar var. names
3387 integer :: br_,bphi_
3388
3389 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
3390 br_=mag(1); bphi_=mag(1)-1+phi_
3391 select case (coordinate)
3392 case (cylindrical)
3393 {do ix^db=ixomin^db,ixomax^db\}
3394 ! include dt in invr, invr is always used with qdt
3395 if(local_timestep) then
3396 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
3397 else
3398 invr=qdt/x(ix^d,1)
3399 end if
3400 if(rmhd_energy) then
3401 tmp=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
3402 else
3403 tmp=rmhd_adiab*wprim(ix^d,rho_)**rmhd_gamma+half*(^c&wprim(ix^d,b^c_)**2+)
3404 end if
3405 if(phi_>0) then
3406 w(ix^d,mr_)=w(ix^d,mr_)+invr*(tmp-&
3407 wprim(ix^d,bphi_)**2+wprim(ix^d,mphi_)*wct(ix^d,mphi_))
3408 w(ix^d,mphi_)=w(ix^d,mphi_)+invr*(&
3409 -wct(ix^d,mphi_)*wprim(ix^d,mr_) &
3410 +wprim(ix^d,bphi_)*wprim(ix^d,br_))
3411 if(.not.stagger_grid) then
3412 w(ix^d,bphi_)=w(ix^d,bphi_)+invr*&
3413 (wprim(ix^d,bphi_)*wprim(ix^d,mr_) &
3414 -wprim(ix^d,br_)*wprim(ix^d,mphi_))
3415 end if
3416 else
3417 w(ix^d,mr_)=w(ix^d,mr_)+invr*tmp
3418 end if
3419 if(rmhd_glm) w(ix^d,br_)=w(ix^d,br_)+wprim(ix^d,psi_)*invr
3420 {end do\}
3421 case (spherical)
3422 {do ix^db=ixomin^db,ixomax^db\}
3423 ! include dt in invr, invr is always used with qdt
3424 if(local_timestep) then
3425 invr=block%dt(ix^d) * dtfactor/x(ix^d,1)
3426 else
3427 invr=qdt/x(ix^d,1)
3428 end if
3429 if(rmhd_energy) then
3430 tmp1=wprim(ix^d,p_)+half*(^c&wprim(ix^d,b^c_)**2+)
3431 else
3432 tmp1=rmhd_adiab*wprim(ix^d,rho_)**rmhd_gamma+half*(^c&wprim(ix^d,b^c_)**2+)
3433 end if
3434 ! m1
3435 {^ifonec
3436 w(ix^d,mom(1))=w(ix^d,mom(1))+two*tmp1*invr
3437 }
3438 {^noonec
3439 w(ix^d,mom(1))=w(ix^d,mom(1))+invr*&
3440 (two*tmp1+(^ce&wprim(ix^d,m^ce_)*wct(ix^d,m^ce_)-wprim(ix^d,b^ce_)**2+))
3441 }
3442 ! b1
3443 if(rmhd_glm) then
3444 w(ix^d,mag(1))=w(ix^d,mag(1))+invr*2.0d0*wprim(ix^d,psi_)
3445 end if
3446 {^ifoned
3447 cot=0.d0
3448 }
3449 {^nooned
3450 cot=1.d0/tan(x(ix^d,2))
3451 }
3452 {^iftwoc
3453 ! m2
3454 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
3455 +wprim(ix^d,b1_)*wprim(ix^d,b2_))
3456 ! b2
3457 if(.not.stagger_grid) then
3458 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
3459 if(rmhd_glm) then
3460 tmp=tmp+wprim(ix^d,psi_)*cot
3461 end if
3462 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
3463 end if
3464 }
3465 {^ifthreec
3466 ! m2
3467 w(ix^d,mom(2))=w(ix^d,mom(2))+invr*(tmp1*cot-wprim(ix^d,m1_)*wct(ix^d,m2_)&
3468 +wprim(ix^d,b1_)*wprim(ix^d,b2_)&
3469 +(wprim(ix^d,m3_)*wct(ix^d,m3_)-wprim(ix^d,b3_)**2)*cot)
3470 ! b2
3471 if(.not.stagger_grid) then
3472 tmp=wprim(ix^d,m1_)*wprim(ix^d,b2_)-wprim(ix^d,m2_)*wprim(ix^d,b1_)
3473 if(rmhd_glm) then
3474 tmp=tmp+wprim(ix^d,psi_)*cot
3475 end if
3476 w(ix^d,mag(2))=w(ix^d,mag(2))+tmp*invr
3477 end if
3478 ! m3
3479 w(ix^d,mom(3))=w(ix^d,mom(3))-invr*&
3480 (wprim(ix^d,m3_)*wct(ix^d,m1_) &
3481 -wprim(ix^d,b3_)*wprim(ix^d,b1_) &
3482 +(wprim(ix^d,m2_)*wct(ix^d,m3_) &
3483 -wprim(ix^d,b2_)*wprim(ix^d,b3_))*cot)
3484 ! b3
3485 if(.not.stagger_grid) then
3486 w(ix^d,mag(3))=w(ix^d,mag(3))+invr*&
3487 (wprim(ix^d,m1_)*wprim(ix^d,b3_) &
3488 -wprim(ix^d,m3_)*wprim(ix^d,b1_) &
3489 -(wprim(ix^d,m3_)*wprim(ix^d,b2_) &
3490 -wprim(ix^d,m2_)*wprim(ix^d,b3_))*cot)
3491 end if
3492 }
3493 {end do\}
3494 end select
3495 end subroutine rmhd_add_source_geom
3496
3497 ! Add geometrical source terms to w
3498 subroutine rmhd_add_source_geom_split(qdt,dtfactor, ixI^L,ixO^L,wCT,wprim,w,x)
3500 use mod_geometry
3501 integer, intent(in) :: ixi^l, ixo^l
3502 double precision, intent(in) :: qdt, dtfactor, x(ixi^s,1:ndim)
3503 double precision, intent(inout) :: wct(ixi^s,1:nw), wprim(ixi^s,1:nw),w(ixi^s,1:nw)
3504 double precision :: tmp(ixi^s),tmp1(ixi^s),tmp2(ixi^s),invrho(ixo^s),invr(ixo^s)
3505 integer :: iw,idir, h1x^l{^nooned, h2x^l}
3506 integer :: mr_,mphi_ ! Polar var. names
3507 integer :: br_,bphi_
3508
3509 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
3510 br_=mag(1); bphi_=mag(1)-1+phi_
3511 if(has_equi_rho0) then
3512 invrho(ixo^s) = 1d0/(wct(ixo^s,rho_) + block%equi_vars(ixo^s,equi_rho0_,b0i))
3513 else
3514 invrho(ixo^s) = 1d0/wct(ixo^s,rho_)
3515 end if
3516 ! include dt in invr, invr is always used with qdt
3517 if(local_timestep) then
3518 invr(ixo^s) = block%dt(ixo^s) * dtfactor/x(ixo^s,1)
3519 else
3520 invr(ixo^s) = qdt/x(ixo^s,1)
3521 end if
3522
3523 select case (coordinate)
3524 case (cylindrical)
3525 call rmhd_get_p_total(wct,x,ixi^l,ixo^l,tmp)
3526 if(phi_>0) then
3527 w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*(tmp(ixo^s)-&
3528 wct(ixo^s,bphi_)**2+wct(ixo^s,mphi_)**2*invrho(ixo^s))
3529 w(ixo^s,mphi_)=w(ixo^s,mphi_)+qdt*invr(ixo^s)*(&
3530 -wct(ixo^s,mphi_)*wct(ixo^s,mr_)*invrho(ixo^s) &
3531 +wct(ixo^s,bphi_)*wct(ixo^s,br_))
3532 if(.not.stagger_grid) then
3533 w(ixo^s,bphi_)=w(ixo^s,bphi_)+invr(ixo^s)*&
3534 (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
3535 -wct(ixo^s,br_)*wct(ixo^s,mphi_)) &
3536 *invrho(ixo^s)
3537 end if
3538 else
3539 w(ixo^s,mr_)=w(ixo^s,mr_)+invr(ixo^s)*tmp(ixo^s)
3540 end if
3541 if(rmhd_glm) w(ixo^s,br_)=w(ixo^s,br_)+wct(ixo^s,psi_)*invr(ixo^s)
3542 case (spherical)
3543 h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
3544 call rmhd_get_p_total(wct,x,ixi^l,ixo^l,tmp1)
3545 tmp(ixo^s)=tmp1(ixo^s)
3546 if(b0field) then
3547 tmp2(ixo^s)=sum(block%B0(ixo^s,:,0)*wct(ixo^s,mag(:)),dim=ndim+1)
3548 tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
3549 end if
3550 ! m1
3551 tmp(ixo^s)=tmp(ixo^s)*x(ixo^s,1) &
3552 *(block%surfaceC(ixo^s,1)-block%surfaceC(h1x^s,1))/block%dvolume(ixo^s)
3553 if(ndir>1) then
3554 do idir=2,ndir
3555 tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom(idir))**2*invrho(ixo^s)-wct(ixo^s,mag(idir))**2
3556 if(b0field) tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,idir,0)*wct(ixo^s,mag(idir))
3557 end do
3558 end if
3559 w(ixo^s,mom(1))=w(ixo^s,mom(1))+tmp(ixo^s)*invr(ixo^s)
3560 ! b1
3561 if(rmhd_glm) then
3562 w(ixo^s,mag(1))=w(ixo^s,mag(1))+invr(ixo^s)*2.0d0*wct(ixo^s,psi_)
3563 end if
3564 {^nooned
3565 ! m2
3566 tmp(ixo^s)=tmp1(ixo^s)
3567 if(b0field) then
3568 tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
3569 end if
3570 if(local_timestep) then
3571 tmp1(ixo^s) = block%dt(ixo^s) * tmp(ixo^s)
3572 else
3573 tmp1(ixo^s) = qdt * tmp(ixo^s)
3574 endif
3575 ! This will make hydrostatic p=const an exact solution
3576 w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp1(ixo^s) &
3577 *(block%surfaceC(ixo^s,2)-block%surfaceC(h2x^s,2)) &
3578 /block%dvolume(ixo^s)
3579 tmp(ixo^s)=-(wct(ixo^s,mom(1))*wct(ixo^s,mom(2))*invrho(ixo^s) &
3580 -wct(ixo^s,mag(1))*wct(ixo^s,mag(2)))
3581 if (b0field) then
3582 tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(2)) &
3583 +wct(ixo^s,mag(1))*block%B0(ixo^s,2,0)
3584 end if
3585 if(ndir==3) then
3586 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(3))**2*invrho(ixo^s) &
3587 -wct(ixo^s,mag(3))**2)*dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
3588 if (b0field) then
3589 tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,3,0)*wct(ixo^s,mag(3))&
3590 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
3591 end if
3592 end if
3593 w(ixo^s,mom(2))=w(ixo^s,mom(2))+tmp(ixo^s)*invr(ixo^s)
3594 ! b2
3595 if(.not.stagger_grid) then
3596 tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
3597 -wct(ixo^s,mom(2))*wct(ixo^s,mag(1)))*invrho(ixo^s)
3598 if(b0field) then
3599 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(1))*block%B0(ixo^s,2,0) &
3600 -wct(ixo^s,mom(2))*block%B0(ixo^s,1,0))*invrho(ixo^s)
3601 end if
3602 if(rmhd_glm) then
3603 tmp(ixo^s)=tmp(ixo^s) &
3604 + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
3605 end if
3606 w(ixo^s,mag(2))=w(ixo^s,mag(2))+tmp(ixo^s)*invr(ixo^s)
3607 end if
3608 }
3609 if(ndir==3) then
3610 ! m3
3611 tmp(ixo^s)=-(wct(ixo^s,mom(3))*wct(ixo^s,mom(1))*invrho(ixo^s) &
3612 -wct(ixo^s,mag(3))*wct(ixo^s,mag(1))) {^nooned &
3613 -(wct(ixo^s,mom(2))*wct(ixo^s,mom(3))*invrho(ixo^s) &
3614 -wct(ixo^s,mag(2))*wct(ixo^s,mag(3))) &
3615 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
3616 if (b0field) then
3617 tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(3)) &
3618 +wct(ixo^s,mag(1))*block%B0(ixo^s,3,0) {^nooned &
3619 +(block%B0(ixo^s,2,0)*wct(ixo^s,mag(3)) &
3620 +wct(ixo^s,mag(2))*block%B0(ixo^s,3,0)) &
3621 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
3622 end if
3623 w(ixo^s,mom(3))=w(ixo^s,mom(3))+tmp(ixo^s)*invr(ixo^s)
3624 ! b3
3625 if(.not.stagger_grid) then
3626 tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
3627 -wct(ixo^s,mom(3))*wct(ixo^s,mag(1)))*invrho(ixo^s) {^nooned &
3628 -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
3629 -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
3630 *invrho(ixo^s)/dsin(x(ixo^s,2)) }
3631 if (b0field) then
3632 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom(1))*block%B0(ixo^s,3,0) &
3633 -wct(ixo^s,mom(3))*block%B0(ixo^s,1,0))*invrho(ixo^s){^nooned &
3634 -(wct(ixo^s,mom(3))*block%B0(ixo^s,2,0) &
3635 -wct(ixo^s,mom(2))*block%B0(ixo^s,3,0))*dcos(x(ixo^s,2)) &
3636 *invrho(ixo^s)/dsin(x(ixo^s,2)) }
3637 end if
3638 w(ixo^s,mag(3))=w(ixo^s,mag(3))+tmp(ixo^s)*invr(ixo^s)
3639 end if
3640 end if
3641 end select
3642 end subroutine rmhd_add_source_geom_split
3643
3644 !> Compute 2 times total magnetic energy
3645 function rmhd_mag_en_all(w, ixI^L, ixO^L) result(mge)
3647 integer, intent(in) :: ixi^l, ixo^l
3648 double precision, intent(in) :: w(ixi^s, nw)
3649 double precision :: mge(ixo^s)
3650
3651 if (b0field) then
3652 mge = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
3653 else
3654 mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
3655 end if
3656 end function rmhd_mag_en_all
3657
3658 subroutine rmhd_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
3660 use mod_usr_methods
3661 integer, intent(in) :: ixi^l, ixo^l, idir
3662 double precision, intent(in) :: qt
3663 double precision, intent(inout) :: wlc(ixi^s,1:nw), wrc(ixi^s,1:nw)
3664 double precision, intent(inout) :: wlp(ixi^s,1:nw), wrp(ixi^s,1:nw)
3665 type(state) :: s
3666 double precision :: db(ixo^s), dpsi(ixo^s)
3667 integer :: ix^d
3668
3669 if(stagger_grid) then
3670 {do ix^db=ixomin^db,ixomax^db\}
3671 wlc(ix^d,mag(idir))=s%ws(ix^d,idir)
3672 wrc(ix^d,mag(idir))=s%ws(ix^d,idir)
3673 wlp(ix^d,mag(idir))=s%ws(ix^d,idir)
3674 wrp(ix^d,mag(idir))=s%ws(ix^d,idir)
3675 {end do\}
3676 else
3677 ! Solve the Riemann problem for the linear 2x2 system for normal
3678 ! B-field and GLM_Psi according to Dedner 2002:
3679 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
3680 ! Gives the Riemann solution on the interface
3681 ! for the normal B component and Psi in the GLM-MHD system.
3682 ! 23/04/2013 Oliver Porth
3683 {do ix^db=ixomin^db,ixomax^db\}
3684 db(ix^d)=wrp(ix^d,mag(idir))-wlp(ix^d,mag(idir))
3685 dpsi(ix^d)=wrp(ix^d,psi_)-wlp(ix^d,psi_)
3686 wlp(ix^d,mag(idir))=half*(wrp(ix^d,mag(idir))+wlp(ix^d,mag(idir))-dpsi(ix^d)/cmax_global)
3687 wlp(ix^d,psi_)=half*(wrp(ix^d,psi_)+wlp(ix^d,psi_)-db(ix^d)*cmax_global)
3688 wrp(ix^d,mag(idir))=wlp(ix^d,mag(idir))
3689 wrp(ix^d,psi_)=wlp(ix^d,psi_)
3690 if(total_energy) then
3691 wrc(ix^d,e_)=wrc(ix^d,e_)-half*wrc(ix^d,mag(idir))**2
3692 wlc(ix^d,e_)=wlc(ix^d,e_)-half*wlc(ix^d,mag(idir))**2
3693 end if
3694 wrc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
3695 wrc(ix^d,psi_)=wlp(ix^d,psi_)
3696 wlc(ix^d,mag(idir))=wlp(ix^d,mag(idir))
3697 wlc(ix^d,psi_)=wlp(ix^d,psi_)
3698 ! modify total energy according to the change of magnetic field
3699 if(total_energy) then
3700 wrc(ix^d,e_)=wrc(ix^d,e_)+half*wrc(ix^d,mag(idir))**2
3701 wlc(ix^d,e_)=wlc(ix^d,e_)+half*wlc(ix^d,mag(idir))**2
3702 end if
3703 {end do\}
3704 end if
3705 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
3706 end subroutine rmhd_modify_wlr
3707
3708 subroutine rmhd_boundary_adjust(igrid,psb)
3710 integer, intent(in) :: igrid
3711 type(state), target :: psb(max_blocks)
3712 integer :: ib, idims, iside, ixo^l, i^d
3713
3714 block=>ps(igrid)
3715 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
3716 do idims=1,ndim
3717 ! to avoid using as yet unknown corner info in more than 1D, we
3718 ! fill only interior mesh ranges of the ghost cell ranges at first,
3719 ! and progressively enlarge the ranges to include corners later
3720 do iside=1,2
3721 i^d=kr(^d,idims)*(2*iside-3);
3722 if (neighbor_type(i^d,igrid)/=1) cycle
3723 ib=(idims-1)*2+iside
3724 if(.not.boundary_divbfix(ib)) cycle
3725 if(any(typeboundary(:,ib)==bc_special)) then
3726 ! MF nonlinear force-free B field extrapolation and data driven
3727 ! require normal B of the first ghost cell layer to be untouched by
3728 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
3729 select case (idims)
3730 {case (^d)
3731 if (iside==2) then
3732 ! maximal boundary
3733 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
3734 ixomax^dd=ixghi^dd;
3735 else
3736 ! minimal boundary
3737 ixomin^dd=ixglo^dd;
3738 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
3739 end if \}
3740 end select
3741 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
3742 end if
3743 end do
3744 end do
3745 end subroutine rmhd_boundary_adjust
3746
3747 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
3749 integer, intent(in) :: ixg^l,ixo^l,ib
3750 double precision, intent(inout) :: w(ixg^s,1:nw)
3751 double precision, intent(in) :: x(ixg^s,1:ndim)
3752 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
3753 integer :: ix^d,ixf^l
3754
3755 select case(ib)
3756 case(1)
3757 ! 2nd order CD for divB=0 to set normal B component better
3758 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
3759 {^iftwod
3760 ixfmin1=ixomin1+1
3761 ixfmax1=ixomax1+1
3762 ixfmin2=ixomin2+1
3763 ixfmax2=ixomax2-1
3764 if(slab_uniform) then
3765 dx1x2=dxlevel(1)/dxlevel(2)
3766 do ix1=ixfmax1,ixfmin1,-1
3767 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
3768 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
3769 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
3770 enddo
3771 else
3772 do ix1=ixfmax1,ixfmin1,-1
3773 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
3774 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
3775 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
3776 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
3777 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
3778 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
3779 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
3780 end do
3781 end if
3782 }
3783 {^ifthreed
3784 ixfmin1=ixomin1+1
3785 ixfmax1=ixomax1+1
3786 ixfmin2=ixomin2+1
3787 ixfmax2=ixomax2-1
3788 ixfmin3=ixomin3+1
3789 ixfmax3=ixomax3-1
3790 if(slab_uniform) then
3791 dx1x2=dxlevel(1)/dxlevel(2)
3792 dx1x3=dxlevel(1)/dxlevel(3)
3793 do ix1=ixfmax1,ixfmin1,-1
3794 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
3795 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
3796 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
3797 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
3798 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
3799 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
3800 end do
3801 else
3802 do ix1=ixfmax1,ixfmin1,-1
3803 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
3804 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
3805 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
3806 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
3807 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
3808 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
3809 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
3810 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
3811 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
3812 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
3813 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
3814 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
3815 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
3816 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
3817 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
3818 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
3819 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
3820 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
3821 end do
3822 end if
3823 }
3824 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
3825 case(2)
3826 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
3827 {^iftwod
3828 ixfmin1=ixomin1-1
3829 ixfmax1=ixomax1-1
3830 ixfmin2=ixomin2+1
3831 ixfmax2=ixomax2-1
3832 if(slab_uniform) then
3833 dx1x2=dxlevel(1)/dxlevel(2)
3834 do ix1=ixfmin1,ixfmax1
3835 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
3836 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
3837 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
3838 enddo
3839 else
3840 do ix1=ixfmin1,ixfmax1
3841 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
3842 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
3843 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
3844 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
3845 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
3846 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
3847 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
3848 end do
3849 end if
3850 }
3851 {^ifthreed
3852 ixfmin1=ixomin1-1
3853 ixfmax1=ixomax1-1
3854 ixfmin2=ixomin2+1
3855 ixfmax2=ixomax2-1
3856 ixfmin3=ixomin3+1
3857 ixfmax3=ixomax3-1
3858 if(slab_uniform) then
3859 dx1x2=dxlevel(1)/dxlevel(2)
3860 dx1x3=dxlevel(1)/dxlevel(3)
3861 do ix1=ixfmin1,ixfmax1
3862 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
3863 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
3864 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
3865 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
3866 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
3867 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
3868 end do
3869 else
3870 do ix1=ixfmin1,ixfmax1
3871 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
3872 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
3873 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
3874 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
3875 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
3876 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
3877 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
3878 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
3879 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
3880 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
3881 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
3882 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
3883 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
3884 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
3885 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
3886 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
3887 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
3888 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
3889 end do
3890 end if
3891 }
3892 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
3893 case(3)
3894 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
3895 {^iftwod
3896 ixfmin1=ixomin1+1
3897 ixfmax1=ixomax1-1
3898 ixfmin2=ixomin2+1
3899 ixfmax2=ixomax2+1
3900 if(slab_uniform) then
3901 dx2x1=dxlevel(2)/dxlevel(1)
3902 do ix2=ixfmax2,ixfmin2,-1
3903 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
3904 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
3905 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
3906 enddo
3907 else
3908 do ix2=ixfmax2,ixfmin2,-1
3909 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
3910 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
3911 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
3912 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
3913 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
3914 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
3915 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
3916 end do
3917 end if
3918 }
3919 {^ifthreed
3920 ixfmin1=ixomin1+1
3921 ixfmax1=ixomax1-1
3922 ixfmin3=ixomin3+1
3923 ixfmax3=ixomax3-1
3924 ixfmin2=ixomin2+1
3925 ixfmax2=ixomax2+1
3926 if(slab_uniform) then
3927 dx2x1=dxlevel(2)/dxlevel(1)
3928 dx2x3=dxlevel(2)/dxlevel(3)
3929 do ix2=ixfmax2,ixfmin2,-1
3930 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
3931 ix2+1,ixfmin3:ixfmax3,mag(2)) &
3932 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
3933 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
3934 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
3935 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
3936 end do
3937 else
3938 do ix2=ixfmax2,ixfmin2,-1
3939 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
3940 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
3941 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
3942 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
3943 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
3944 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
3945 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
3946 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
3947 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
3948 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
3949 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
3950 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
3951 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
3952 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
3953 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
3954 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
3955 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
3956 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
3957 end do
3958 end if
3959 }
3960 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
3961 case(4)
3962 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
3963 {^iftwod
3964 ixfmin1=ixomin1+1
3965 ixfmax1=ixomax1-1
3966 ixfmin2=ixomin2-1
3967 ixfmax2=ixomax2-1
3968 if(slab_uniform) then
3969 dx2x1=dxlevel(2)/dxlevel(1)
3970 do ix2=ixfmin2,ixfmax2
3971 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
3972 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
3973 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
3974 end do
3975 else
3976 do ix2=ixfmin2,ixfmax2
3977 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
3978 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
3979 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
3980 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
3981 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
3982 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
3983 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
3984 end do
3985 end if
3986 }
3987 {^ifthreed
3988 ixfmin1=ixomin1+1
3989 ixfmax1=ixomax1-1
3990 ixfmin3=ixomin3+1
3991 ixfmax3=ixomax3-1
3992 ixfmin2=ixomin2-1
3993 ixfmax2=ixomax2-1
3994 if(slab_uniform) then
3995 dx2x1=dxlevel(2)/dxlevel(1)
3996 dx2x3=dxlevel(2)/dxlevel(3)
3997 do ix2=ixfmin2,ixfmax2
3998 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
3999 ix2-1,ixfmin3:ixfmax3,mag(2)) &
4000 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
4001 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
4002 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
4003 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
4004 end do
4005 else
4006 do ix2=ixfmin2,ixfmax2
4007 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
4008 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
4009 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
4010 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
4011 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
4012 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
4013 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
4014 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
4015 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
4016 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
4017 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
4018 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
4019 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
4020 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
4021 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
4022 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
4023 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
4024 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
4025 end do
4026 end if
4027 }
4028 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
4029 {^ifthreed
4030 case(5)
4031 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
4032 ixfmin1=ixomin1+1
4033 ixfmax1=ixomax1-1
4034 ixfmin2=ixomin2+1
4035 ixfmax2=ixomax2-1
4036 ixfmin3=ixomin3+1
4037 ixfmax3=ixomax3+1
4038 if(slab_uniform) then
4039 dx3x1=dxlevel(3)/dxlevel(1)
4040 dx3x2=dxlevel(3)/dxlevel(2)
4041 do ix3=ixfmax3,ixfmin3,-1
4042 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
4043 ixfmin2:ixfmax2,ix3+1,mag(3)) &
4044 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
4045 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
4046 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
4047 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
4048 end do
4049 else
4050 do ix3=ixfmax3,ixfmin3,-1
4051 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
4052 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
4053 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
4054 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
4055 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
4056 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
4057 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
4058 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
4059 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
4060 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
4061 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
4062 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
4063 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
4064 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
4065 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
4066 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
4067 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
4068 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
4069 end do
4070 end if
4071 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
4072 case(6)
4073 if(total_energy) call rmhd_to_primitive(ixg^l,ixo^l,w,x)
4074 ixfmin1=ixomin1+1
4075 ixfmax1=ixomax1-1
4076 ixfmin2=ixomin2+1
4077 ixfmax2=ixomax2-1
4078 ixfmin3=ixomin3-1
4079 ixfmax3=ixomax3-1
4080 if(slab_uniform) then
4081 dx3x1=dxlevel(3)/dxlevel(1)
4082 dx3x2=dxlevel(3)/dxlevel(2)
4083 do ix3=ixfmin3,ixfmax3
4084 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
4085 ixfmin2:ixfmax2,ix3-1,mag(3)) &
4086 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
4087 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
4088 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
4089 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
4090 end do
4091 else
4092 do ix3=ixfmin3,ixfmax3
4093 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
4094 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
4095 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
4096 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
4097 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
4098 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
4099 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
4100 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
4101 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
4102 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
4103 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
4104 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
4105 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
4106 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
4107 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
4108 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
4109 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
4110 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
4111 end do
4112 end if
4113 if(total_energy) call rmhd_to_conserved(ixg^l,ixo^l,w,x)
4114 }
4115 case default
4116 call mpistop("Special boundary is not defined for this region")
4117 end select
4118 end subroutine fixdivb_boundary
4119
4120 {^nooned
4121 subroutine rmhd_clean_divb_multigrid(qdt, qt, active)
4122 use mod_forest
4125 use mod_geometry
4126 double precision, intent(in) :: qdt !< Current time step
4127 double precision, intent(in) :: qt !< Current time
4128 logical, intent(inout) :: active !< Output if the source is active
4129 integer :: id
4130 integer, parameter :: max_its = 50
4131 double precision :: residual_it(max_its), max_divb
4132 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
4133 double precision :: res
4134 double precision, parameter :: max_residual = 1d-3
4135 double precision, parameter :: residual_reduction = 1d-10
4136 integer :: iigrid, igrid
4137 integer :: n, nc, lvl, ix^l, ixc^l, idim
4138 type(tree_node), pointer :: pnode
4139
4140 mg%operator_type = mg_laplacian
4141 ! Set boundary conditions
4142 do n = 1, 2*ndim
4143 idim = (n+1)/2
4144 select case (typeboundary(mag(idim), n))
4145 case (bc_symm)
4146 ! d/dx B = 0, take phi = 0
4147 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
4148 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
4149 case (bc_asymm)
4150 ! B = 0, so grad(phi) = 0
4151 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
4152 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
4153 case (bc_cont)
4154 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
4155 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
4156 case (bc_special)
4157 ! Assume Dirichlet boundary conditions, derivative zero
4158 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
4159 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
4160 case (bc_periodic)
4161 ! Nothing to do here
4162 case default
4163 write(*,*) "rmhd_clean_divb_multigrid warning: unknown boundary type"
4164 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
4165 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
4166 end select
4167 end do
4168
4169 ix^l=ixm^ll^ladd1;
4170 max_divb = 0.0d0
4171 ! Store divergence of B as right-hand side
4172 do iigrid = 1, igridstail
4173 igrid = igrids(iigrid);
4174 pnode => igrid_to_node(igrid, mype)%node
4175 id = pnode%id
4176 lvl = mg%boxes(id)%lvl
4177 nc = mg%box_size_lvl(lvl)
4178
4179 ! Geometry subroutines expect this to be set
4180 block => ps(igrid)
4181 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
4182
4183 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
4185 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
4186 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
4187 end do
4188
4189 ! Solve laplacian(phi) = divB
4190 if(stagger_grid) then
4191 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
4192 mpi_max, icomm, ierrmpi)
4193
4194 if (mype == 0) print *, "Performing multigrid divB cleaning"
4195 if (mype == 0) print *, "iteration vs residual"
4196 ! Solve laplacian(phi) = divB
4197 do n = 1, max_its
4198 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
4199 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
4200 if (residual_it(n) < residual_reduction * max_divb) exit
4201 end do
4202 if (mype == 0 .and. n > max_its) then
4203 print *, "divb_multigrid warning: not fully converged"
4204 print *, "current amplitude of divb: ", residual_it(max_its)
4205 print *, "multigrid smallest grid: ", &
4206 mg%domain_size_lvl(:, mg%lowest_lvl)
4207 print *, "note: smallest grid ideally has <= 8 cells"
4208 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
4209 print *, "note: dx/dy/dz should be similar"
4210 end if
4211 else
4212 do n = 1, max_its
4213 call mg_fas_vcycle(mg, max_res=res)
4214 if (res < max_residual) exit
4215 end do
4216 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
4217 end if
4218
4219 ! Correct the magnetic field
4220 do iigrid = 1, igridstail
4221 igrid = igrids(iigrid);
4222 pnode => igrid_to_node(igrid, mype)%node
4223 id = pnode%id
4224 ! Geometry subroutines expect this to be set
4225 block => ps(igrid)
4226 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
4227 ! Compute the gradient of phi
4228 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
4229 if(stagger_grid) then
4230 do idim =1, ndim
4231 ixcmin^d=ixmlo^d-kr(idim,^d);
4232 ixcmax^d=ixmhi^d;
4233 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
4234 ! Apply the correction B* = B - gradient(phi)
4235 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
4236 end do
4237 ! store cell-center magnetic energy
4238 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
4239 ! change cell-center magnetic field
4240 call rmhd_face_to_center(ixm^ll,ps(igrid))
4241 else
4242 do idim = 1, ndim
4243 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
4244 end do
4245 ! store cell-center magnetic energy
4246 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
4247 ! Apply the correction B* = B - gradient(phi)
4248 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
4249 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
4250 end if
4251 if(total_energy) then
4252 ! Determine magnetic energy difference
4253 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
4254 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
4255 ! Keep thermal pressure the same
4256 ps(igrid)%w(ixm^t, e_) = ps(igrid)%w(ixm^t, e_) + tmp(ixm^t)
4257 end if
4258 end do
4259 active = .true.
4260 end subroutine rmhd_clean_divb_multigrid
4261 }
4262
4263 !> get electric field though averaging neighors to update faces in CT
4264 subroutine rmhd_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
4266 use mod_usr_methods
4267
4268 integer, intent(in) :: ixi^l, ixo^l
4269 double precision, intent(in) :: qt,qdt
4270 ! cell-center primitive variables
4271 double precision, intent(in) :: wp(ixi^s,1:nw)
4272 type(state) :: sct, s
4273 type(ct_velocity) :: vcts
4274 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
4275 double precision, intent(inout) :: fe(ixi^s,sdim:3)
4276
4277 double precision :: circ(ixi^s,1:ndim)
4278 ! non-ideal electric field on cell edges
4279 double precision, dimension(ixI^S,sdim:3) :: e_resi
4280 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
4281 integer :: idim1,idim2,idir,iwdim1,iwdim2
4282
4283 associate(bfaces=>s%ws,x=>s%x)
4284
4285 ! Calculate contribution to FEM of each edge,
4286 ! that is, estimate value of line integral of
4287 ! electric field in the positive idir direction.
4288
4289 ! if there is resistivity, get eta J
4290 if(rmhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
4291
4292 do idim1=1,ndim
4293 iwdim1 = mag(idim1)
4294 i1kr^d=kr(idim1,^d);
4295 do idim2=1,ndim
4296 iwdim2 = mag(idim2)
4297 i2kr^d=kr(idim2,^d);
4298 do idir=sdim,3! Direction of line integral
4299 ! Allow only even permutations
4300 if (lvc(idim1,idim2,idir)==1) then
4301 ixcmax^d=ixomax^d;
4302 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4303 ! average cell-face electric field to cell edges
4304 {do ix^db=ixcmin^db,ixcmax^db\}
4305 fe(ix^d,idir)=quarter*&
4306 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
4307 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
4308 ! add resistive electric field at cell edges E=-vxB+eta J
4309 if(rmhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
4310 ! times time step and edge length
4311 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
4312 {end do\}
4313 end if
4314 end do
4315 end do
4316 end do
4317
4318 ! allow user to change inductive electric field, especially for boundary driven applications
4319 if(associated(usr_set_electric_field)) &
4320 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
4321
4322 circ(ixi^s,1:ndim)=zero
4323
4324 ! Calculate circulation on each face
4325 do idim1=1,ndim ! Coordinate perpendicular to face
4326 ixcmax^d=ixomax^d;
4327 ixcmin^d=ixomin^d-kr(idim1,^d);
4328 do idim2=1,ndim
4329 ixa^l=ixc^l-kr(idim2,^d);
4330 do idir=sdim,3 ! Direction of line integral
4331 ! Assemble indices
4332 if(lvc(idim1,idim2,idir)==1) then
4333 ! Add line integrals in direction idir
4334 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4335 +(fe(ixc^s,idir)&
4336 -fe(ixa^s,idir))
4337 else if(lvc(idim1,idim2,idir)==-1) then
4338 ! Add line integrals in direction idir
4339 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4340 -(fe(ixc^s,idir)&
4341 -fe(ixa^s,idir))
4342 end if
4343 end do
4344 end do
4345 {do ix^db=ixcmin^db,ixcmax^db\}
4346 ! Divide by the area of the face to get dB/dt
4347 if(s%surfaceC(ix^d,idim1) > smalldouble) then
4348 ! Time update cell-face magnetic field component
4349 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
4350 end if
4351 {end do\}
4352 end do
4353
4354 end associate
4355
4356 end subroutine rmhd_update_faces_average
4357
4358 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
4359 subroutine rmhd_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
4361 use mod_usr_methods
4362 use mod_geometry
4363
4364 integer, intent(in) :: ixi^l, ixo^l
4365 double precision, intent(in) :: qt, qdt
4366 ! cell-center primitive variables
4367 double precision, intent(in) :: wp(ixi^s,1:nw)
4368 type(state) :: sct, s
4369 type(ct_velocity) :: vcts
4370 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
4371 double precision, intent(inout) :: fe(ixi^s,sdim:3)
4372
4373 double precision :: circ(ixi^s,1:ndim)
4374 ! electric field at cell centers
4375 double precision :: ecc(ixi^s,sdim:3)
4376 double precision :: ein(ixi^s,sdim:3)
4377 ! gradient of E at left and right side of a cell face
4378 double precision :: el(ixi^s),er(ixi^s)
4379 ! gradient of E at left and right side of a cell corner
4380 double precision :: elc,erc
4381 ! non-ideal electric field on cell edges
4382 double precision, dimension(ixI^S,sdim:3) :: e_resi
4383 ! current on cell edges
4384 double precision :: jce(ixi^s,sdim:3)
4385 ! location at cell faces
4386 double precision :: xs(ixgs^t,1:ndim)
4387 double precision :: gradi(ixgs^t)
4388 integer :: ixc^l,ixa^l
4389 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
4390
4391 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
4392
4393 ! if there is resistivity, get eta J
4394 if(rmhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
4395
4396 if(b0field) then
4397 {do ix^db=iximin^db,iximax^db\}
4398 ! Calculate electric field at cell centers
4399 {^ifthreed
4400 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_)
4401 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_)
4402 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_)
4403 }
4404 {^iftwod
4405 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
4406 }
4407 {^ifoned
4408 ecc(ix^d,3)=0.d0
4409 }
4410 {end do\}
4411 else
4412 {do ix^db=iximin^db,iximax^db\}
4413 ! Calculate electric field at cell centers
4414 {^ifthreed
4415 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
4416 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
4417 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
4418 }
4419 {^iftwod
4420 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
4421 }
4422 {^ifoned
4423 ecc(ix^d,3)=0.d0
4424 }
4425 {end do\}
4426 end if
4427
4428 ! Calculate contribution to FEM of each edge,
4429 ! that is, estimate value of line integral of
4430 ! electric field in the positive idir direction.
4431 ! evaluate electric field along cell edges according to equation (41)
4432 do idim1=1,ndim
4433 iwdim1 = mag(idim1)
4434 i1kr^d=kr(idim1,^d);
4435 do idim2=1,ndim
4436 iwdim2 = mag(idim2)
4437 i2kr^d=kr(idim2,^d);
4438 do idir=sdim,3 ! Direction of line integral
4439 ! Allow only even permutations
4440 if (lvc(idim1,idim2,idir)==1) then
4441 ixcmax^d=ixomax^d;
4442 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4443 ! Assemble indices
4444 ! average cell-face electric field to cell edges
4445 {do ix^db=ixcmin^db,ixcmax^db\}
4446 fe(ix^d,idir)=quarter*&
4447 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
4448 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
4449 if(partial_energy) ein(ix^d,idir)=fe(ix^d,idir)
4450 {end do\}
4451 ! add slope in idim2 direction from equation (50)
4452 ixamin^d=ixcmin^d;
4453 ixamax^d=ixcmax^d+i1kr^d;
4454 {do ix^db=ixamin^db,ixamax^db\}
4455 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
4456 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
4457 {end do\}
4458 {!dir$ ivdep
4459 do ix^db=ixcmin^db,ixcmax^db\}
4460 if(vnorm(ix^d,idim1)>0.d0) then
4461 elc=el(ix^d)
4462 else if(vnorm(ix^d,idim1)<0.d0) then
4463 elc=el({ix^d+i1kr^d})
4464 else
4465 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
4466 end if
4467 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
4468 erc=er(ix^d)
4469 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
4470 erc=er({ix^d+i1kr^d})
4471 else
4472 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
4473 end if
4474 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
4475 {end do\}
4476
4477 ! add slope in idim1 direction from equation (50)
4478 ixamin^d=ixcmin^d;
4479 ixamax^d=ixcmax^d+i2kr^d;
4480 {do ix^db=ixamin^db,ixamax^db\}
4481 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
4482 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
4483 {end do\}
4484 {!dir$ ivdep
4485 do ix^db=ixcmin^db,ixcmax^db\}
4486 if(vnorm(ix^d,idim2)>0.d0) then
4487 elc=el(ix^d)
4488 else if(vnorm(ix^d,idim2)<0.d0) then
4489 elc=el({ix^d+i2kr^d})
4490 else
4491 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
4492 end if
4493 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
4494 erc=er(ix^d)
4495 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
4496 erc=er({ix^d+i2kr^d})
4497 else
4498 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
4499 end if
4500 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
4501 ! difference between average and upwind interpolated E
4502 if(partial_energy) ein(ix^d,idir)=fe(ix^d,idir)-ein(ix^d,idir)
4503 ! add resistive electric field at cell edges E=-vxB+eta J
4504 if(rmhd_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
4505 ! times time step and edge length
4506 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
4507 {end do\}
4508 end if
4509 end do
4510 end do
4511 end do
4512
4513 if(partial_energy) then
4514 ! add upwind diffused magnetic energy back to energy
4515 ! calculate current density at cell edges
4516 jce=0.d0
4517 do idim1=1,ndim
4518 do idim2=1,ndim
4519 do idir=sdim,3
4520 if (lvc(idim1,idim2,idir)==0) cycle
4521 ixcmax^d=ixomax^d;
4522 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4523 ixamax^d=ixcmax^d-kr(idir,^d)+1;
4524 ixamin^d=ixcmin^d;
4525 ! current at transverse faces
4526 xs(ixa^s,:)=x(ixa^s,:)
4527 xs(ixa^s,idim2)=x(ixa^s,idim2)+half*s%dx(ixa^s,idim2)
4528 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi)
4529 if (lvc(idim1,idim2,idir)==1) then
4530 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
4531 else
4532 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
4533 end if
4534 end do
4535 end do
4536 end do
4537 do idir=sdim,3
4538 ixcmax^d=ixomax^d;
4539 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4540 ! E dot J on cell edges
4541 ein(ixc^s,idir)=ein(ixc^s,idir)*jce(ixc^s,idir)
4542 ! average from cell edge to cell center
4543 {^ifthreed
4544 if(idir==1) then
4545 {do ix^db=ixomin^db,ixomax^db\}
4546 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1,ix2-1,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
4547 +ein(ix1,ix2-1,ix3-1,idir))
4548 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
4549 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
4550 {end do\}
4551 else if(idir==2) then
4552 {do ix^db=ixomin^db,ixomax^db\}
4553 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2,ix3-1,idir)&
4554 +ein(ix1-1,ix2,ix3-1,idir))
4555 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
4556 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
4557 {end do\}
4558 else
4559 {do ix^db=ixomin^db,ixomax^db\}
4560 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,ix3,idir)+ein(ix1,ix2-1,ix3,idir)&
4561 +ein(ix1-1,ix2-1,ix3,idir))
4562 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
4563 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
4564 {end do\}
4565 end if
4566 }
4567 {^iftwod
4568 !idir=3
4569 {do ix^db=ixomin^db,ixomax^db\}
4570 jce(ix^d,idir)=0.25d0*(ein(ix^d,idir)+ein(ix1-1,ix2,idir)+ein(ix1,ix2-1,idir)&
4571 +ein(ix1-1,ix2-1,idir))
4572 if(jce(ix^d,idir)<0.d0) jce(ix^d,idir)=0.d0
4573 w(ix^d,e_)=w(ix^d,e_)+qdt*jce(ix^d,idir)
4574 {end do\}
4575 }
4576 ! save additional numerical resistive heating to an extra variable
4577 if(nwextra>0) then
4578 block%w(ixo^s,nw)=block%w(ixo^s,nw)+jce(ixo^s,idir)
4579 end if
4580 end do
4581 end if
4582
4583 ! allow user to change inductive electric field, especially for boundary driven applications
4584 if(associated(usr_set_electric_field)) &
4585 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
4586
4587 circ(ixi^s,1:ndim)=zero
4588
4589 ! Calculate circulation on each face
4590 do idim1=1,ndim ! Coordinate perpendicular to face
4591 ixcmax^d=ixomax^d;
4592 ixcmin^d=ixomin^d-kr(idim1,^d);
4593 do idim2=1,ndim
4594 ixa^l=ixc^l-kr(idim2,^d);
4595 do idir=sdim,3 ! Direction of line integral
4596 ! Assemble indices
4597 if(lvc(idim1,idim2,idir)==1) then
4598 ! Add line integrals in direction idir
4599 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4600 +(fe(ixc^s,idir)&
4601 -fe(ixa^s,idir))
4602 else if(lvc(idim1,idim2,idir)==-1) then
4603 ! Add line integrals in direction idir
4604 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4605 -(fe(ixc^s,idir)&
4606 -fe(ixa^s,idir))
4607 end if
4608 end do
4609 end do
4610 {do ix^db=ixcmin^db,ixcmax^db\}
4611 ! Divide by the area of the face to get dB/dt
4612 if(s%surfaceC(ix^d,idim1) > smalldouble) then
4613 ! Time update cell-face magnetic field component
4614 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
4615 end if
4616 {end do\}
4617 end do
4618
4619 end associate
4620
4621 end subroutine rmhd_update_faces_contact
4622
4623 !> update faces
4624 subroutine rmhd_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
4626 use mod_usr_methods
4628
4629 integer, intent(in) :: ixi^l, ixo^l
4630 double precision, intent(in) :: qt, qdt
4631 ! cell-center primitive variables
4632 double precision, intent(in) :: wp(ixi^s,1:nw)
4633 type(state) :: sct, s
4634 type(ct_velocity) :: vcts
4635 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
4636 double precision, intent(inout) :: fe(ixi^s,sdim:3)
4637
4638 double precision :: vtill(ixi^s,2)
4639 double precision :: vtilr(ixi^s,2)
4640 double precision :: bfacetot(ixi^s,ndim)
4641 double precision :: btill(ixi^s,ndim)
4642 double precision :: btilr(ixi^s,ndim)
4643 double precision :: cp(ixi^s,2)
4644 double precision :: cm(ixi^s,2)
4645 double precision :: circ(ixi^s,1:ndim)
4646 ! non-ideal electric field on cell edges
4647 double precision, dimension(ixI^S,sdim:3) :: e_resi
4648 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
4649 integer :: idim1,idim2,idir,ix^d
4650
4651 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
4652 cbarmax=>vcts%cbarmax)
4653
4654 ! Calculate contribution to FEM of each edge,
4655 ! that is, estimate value of line integral of
4656 ! electric field in the positive idir direction.
4657
4658 ! Loop over components of electric field
4659
4660 ! idir: electric field component we need to calculate
4661 ! idim1: directions in which we already performed the reconstruction
4662 ! idim2: directions in which we perform the reconstruction
4663
4664 ! if there is resistivity, get eta J
4665 if(rmhd_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
4666
4667 do idir=sdim,3
4668 ! Indices
4669 ! idir: electric field component
4670 ! idim1: one surface
4671 ! idim2: the other surface
4672 ! cyclic permutation: idim1,idim2,idir=1,2,3
4673 ! Velocity components on the surface
4674 ! follow cyclic premutations:
4675 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
4676
4677 ixcmax^d=ixomax^d;
4678 ixcmin^d=ixomin^d-1+kr(idir,^d);
4679
4680 ! Set indices and directions
4681 idim1=mod(idir,3)+1
4682 idim2=mod(idir+1,3)+1
4683
4684 jxc^l=ixc^l+kr(idim1,^d);
4685 ixcp^l=ixc^l+kr(idim2,^d);
4686
4687 ! Reconstruct transverse transport velocities
4688 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
4689 vtill(ixi^s,2),vtilr(ixi^s,2))
4690
4691 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
4692 vtill(ixi^s,1),vtilr(ixi^s,1))
4693
4694 ! Reconstruct magnetic fields
4695 ! Eventhough the arrays are larger, reconstruct works with
4696 ! the limits ixG.
4697 if(b0field) then
4698 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
4699 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
4700 else
4701 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
4702 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
4703 end if
4704 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
4705 btill(ixi^s,idim1),btilr(ixi^s,idim1))
4706
4707 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
4708 btill(ixi^s,idim2),btilr(ixi^s,idim2))
4709
4710 ! Take the maximum characteristic
4711
4712 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
4713 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
4714
4715 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
4716 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
4717
4718
4719 ! Calculate eletric field
4720 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
4721 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
4722 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
4723 /(cp(ixc^s,1)+cm(ixc^s,1)) &
4724 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
4725 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
4726 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
4727 /(cp(ixc^s,2)+cm(ixc^s,2))
4728
4729 ! add resistive electric field at cell edges E=-vxB+eta J
4730 if(rmhd_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
4731 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
4732
4733 if (.not.slab) then
4734 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
4735 fe(ixc^s,idir)=zero
4736 end where
4737 end if
4738
4739 end do
4740
4741 ! allow user to change inductive electric field, especially for boundary driven applications
4742 if(associated(usr_set_electric_field)) &
4743 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
4744
4745 circ(ixi^s,1:ndim)=zero
4746
4747 ! Calculate circulation on each face: interal(fE dot dl)
4748 do idim1=1,ndim ! Coordinate perpendicular to face
4749 ixcmax^d=ixomax^d;
4750 ixcmin^d=ixomin^d-kr(idim1,^d);
4751 do idim2=1,ndim
4752 do idir=sdim,3 ! Direction of line integral
4753 ! Assemble indices
4754 if(lvc(idim1,idim2,idir)/=0) then
4755 hxc^l=ixc^l-kr(idim2,^d);
4756 ! Add line integrals in direction idir
4757 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
4758 +lvc(idim1,idim2,idir)&
4759 *(fe(ixc^s,idir)&
4760 -fe(hxc^s,idir))
4761 end if
4762 end do
4763 end do
4764 {do ix^db=ixcmin^db,ixcmax^db\}
4765 ! Divide by the area of the face to get dB/dt
4766 if(s%surfaceC(ix^d,idim1) > smalldouble) then
4767 ! Time update cell-face magnetic field component
4768 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
4769 end if
4770 {end do\}
4771 end do
4772
4773 end associate
4774 end subroutine rmhd_update_faces_hll
4775
4776 !> calculate eta J at cell edges
4777 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
4779 use mod_usr_methods
4780 use mod_geometry
4781
4782 integer, intent(in) :: ixi^l, ixo^l
4783 ! cell-center primitive variables
4784 double precision, intent(in) :: wp(ixi^s,1:nw)
4785 type(state), intent(in) :: sct, s
4786 ! current on cell edges
4787 double precision :: jce(ixi^s,sdim:3)
4788
4789 ! current on cell centers
4790 double precision :: jcc(ixi^s,7-2*ndir:3)
4791 ! location at cell faces
4792 double precision :: xs(ixgs^t,1:ndim)
4793 ! resistivity
4794 double precision :: eta(ixi^s)
4795 double precision :: gradi(ixgs^t)
4796 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
4797
4798 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
4799 ! calculate current density at cell edges
4800 jce=0.d0
4801 do idim1=1,ndim
4802 do idim2=1,ndim
4803 do idir=sdim,3
4804 if (lvc(idim1,idim2,idir)==0) cycle
4805 ixcmax^d=ixomax^d;
4806 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4807 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
4808 ixbmin^d=ixcmin^d;
4809 ! current at transverse faces
4810 xs(ixb^s,:)=x(ixb^s,:)
4811 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
4812 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
4813 if (lvc(idim1,idim2,idir)==1) then
4814 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
4815 else
4816 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
4817 end if
4818 end do
4819 end do
4820 end do
4821 ! get resistivity
4822 if(rmhd_eta>zero)then
4823 jce(ixi^s,:)=jce(ixi^s,:)*rmhd_eta
4824 else
4825 ixa^l=ixo^l^ladd1;
4826 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
4827 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
4828 ! calcuate eta on cell edges
4829 do idir=sdim,3
4830 ixcmax^d=ixomax^d;
4831 ixcmin^d=ixomin^d+kr(idir,^d)-1;
4832 jcc(ixc^s,idir)=0.d0
4833 {do ix^db=0,1\}
4834 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
4835 ixamin^d=ixcmin^d+ix^d;
4836 ixamax^d=ixcmax^d+ix^d;
4837 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
4838 {end do\}
4839 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
4840 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
4841 end do
4842 end if
4843
4844 end associate
4845 end subroutine get_resistive_electric_field
4846
4847 !> calculate cell-center values from face-center values
4848 subroutine rmhd_face_to_center(ixO^L,s)
4850 ! Non-staggered interpolation range
4851 integer, intent(in) :: ixo^l
4852 type(state) :: s
4853 integer :: ix^d
4854
4855 ! calculate cell-center values from face-center values in 2nd order
4856 ! because the staggered arrays have an additional place to the left.
4857 ! Interpolate to cell barycentre using arithmetic average
4858 ! This might be done better later, to make the method less diffusive.
4859 {!dir$ ivdep
4860 do ix^db=ixomin^db,ixomax^db\}
4861 {^ifthreed
4862 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
4863 +s%ws(ix1-1,ix2,ix3,1)*s%surfaceC(ix1-1,ix2,ix3,1))
4864 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
4865 +s%ws(ix1,ix2-1,ix3,2)*s%surfaceC(ix1,ix2-1,ix3,2))
4866 s%w(ix^d,b3_)=half/s%surface(ix^d,3)*(s%ws(ix^d,3)*s%surfaceC(ix^d,3)&
4867 +s%ws(ix1,ix2,ix3-1,3)*s%surfaceC(ix1,ix2,ix3-1,3))
4868 }
4869 {^iftwod
4870 s%w(ix^d,b1_)=half/s%surface(ix^d,1)*(s%ws(ix^d,1)*s%surfaceC(ix^d,1)&
4871 +s%ws(ix1-1,ix2,1)*s%surfaceC(ix1-1,ix2,1))
4872 s%w(ix^d,b2_)=half/s%surface(ix^d,2)*(s%ws(ix^d,2)*s%surfaceC(ix^d,2)&
4873 +s%ws(ix1,ix2-1,2)*s%surfaceC(ix1,ix2-1,2))
4874 }
4875 {end do\}
4876 ! calculate cell-center values from face-center values in 4th order
4877 !do idim=1,ndim
4878 ! gxO^L=ixO^L-2*kr(idim,^D);
4879 ! hxO^L=ixO^L-kr(idim,^D);
4880 ! jxO^L=ixO^L+kr(idim,^D);
4881
4882 ! ! Interpolate to cell barycentre using fourth order central formula
4883 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
4884 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
4885 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
4886 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
4887 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
4888 !end do
4889
4890 ! calculate cell-center values from face-center values in 6th order
4891 !do idim=1,ndim
4892 ! fxO^L=ixO^L-3*kr(idim,^D);
4893 ! gxO^L=ixO^L-2*kr(idim,^D);
4894 ! hxO^L=ixO^L-kr(idim,^D);
4895 ! jxO^L=ixO^L+kr(idim,^D);
4896 ! kxO^L=ixO^L+2*kr(idim,^D);
4897
4898 ! ! Interpolate to cell barycentre using sixth order central formula
4899 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
4900 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
4901 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
4902 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
4903 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
4904 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
4905 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
4906 !end do
4907 end subroutine rmhd_face_to_center
4908
4909 !> calculate magnetic field from vector potential
4910 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
4913 integer, intent(in) :: ixis^l, ixi^l, ixo^l
4914 double precision, intent(inout) :: ws(ixis^s,1:nws)
4915 double precision, intent(in) :: x(ixi^s,1:ndim)
4916 double precision :: adummy(ixis^s,1:3)
4917
4918 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
4919 end subroutine b_from_vector_potential
4920
4921 subroutine rfactor_from_temperature_ionization(w,x,ixI^L,ixO^L,Rfactor)
4924 integer, intent(in) :: ixi^l, ixo^l
4925 double precision, intent(in) :: w(ixi^s,1:nw)
4926 double precision, intent(in) :: x(ixi^s,1:ndim)
4927 double precision, intent(out):: rfactor(ixi^s)
4928 double precision :: iz_h(ixo^s),iz_he(ixo^s)
4929
4930 call ionization_degree_from_temperature(ixi^l,ixo^l,w(ixi^s,te_),iz_h,iz_he)
4931 ! assume the first and second ionization of Helium have the same degree
4932 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)
4933 end subroutine rfactor_from_temperature_ionization
4934
4935 subroutine rfactor_from_constant_ionization(w,x,ixI^L,ixO^L,Rfactor)
4937 integer, intent(in) :: ixi^l, ixo^l
4938 double precision, intent(in) :: w(ixi^s,1:nw)
4939 double precision, intent(in) :: x(ixi^s,1:ndim)
4940 double precision, intent(out):: rfactor(ixi^s)
4941
4942 rfactor(ixo^s)=rr
4943 end subroutine rfactor_from_constant_ionization
4944end module mod_rmhd_phys
Module for including anisotropic flux limited diffusion (AFLD)-approximation in Radiation-hydrodynami...
Definition mod_afld.t:9
subroutine afld_get_diffcoef_central(w, wct, wctprim, x, ixil, ixol, primitives_filled)
Calculates cell-centered diffusion coefficient to be used in multigrid.
Definition mod_afld.t:608
subroutine, public add_afld_rad_force(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 This subroutine handles th...
Definition mod_afld.t:118
subroutine, public afld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x)
get dt limit for radiation force: NOTE: only uniform cartesian here!
Definition mod_afld.t:195
subroutine, public afld_get_radpress(w, x, ixil, ixol, rad_pressure, nth)
Calculate Radiation Pressure Returns Radiation Pressure as tensor.
Definition mod_afld.t:443
subroutine, public afld_init(he_abundance, afld_gamma)
Initialising FLD-module: Read opacities Initialise Multigrid adimensionalise kappa Add extra variable...
Definition mod_afld.t:80
subroutine, public get_afld_energy_interact(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 This subroutine handles th...
Definition mod_afld.t:222
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
subroutine cak_init(phys_gamma)
Initialize the module.
subroutine cak_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Check time step for total radiation contribution.
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 const_rad_a
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.
Nicolas Moens with updates by RK (16/03/2026) Module for including flux limited diffusion (FLD)-appro...
Definition mod_fld.t:9
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure, nth)
Calculate Radiation Pressure Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
Definition mod_fld.t:395
subroutine, public fld_get_diffcoef_central(w, wct, wctprim, x, ixil, ixol, primitives_filled)
Calculates cell-centered diffusion coefficient to be used in multigrid.
Definition mod_fld.t:660
subroutine, public add_fld_rad_force(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 This subroutine handles th...
Definition mod_fld.t:132
subroutine, public fld_init(he_abundance, r_gamma)
Initialising FLD-module: Read opacities Initialise Multigrid adimensionalise kappa Add extra variable...
Definition mod_fld.t:84
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x)
get dt limit for radiation force: NOTE: only uniform cartesian here!
Definition mod_fld.t:168
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 spherical
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, parameter bc_noinflow
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.
double precision unit_opacity
Physical scaling factor for Opacity.
integer, parameter unitpar
file handle for IO
double precision unit_mass
Physical scaling factor for mass.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
double precision unit_numberdensity
Physical scaling factor for number density.
character(len=std_len) convert_type
Which format to use when converting.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
logical stagger_grid
True for using stagger grid.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
double precision bdip
amplitude of background dipolar, quadrupolar, octupolar, user's field
integer b0i
background magnetic field location indicator
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
logical local_timestep
each cell has its own timestep or not
double precision dt
global time step
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
double precision unit_velocity
Physical scaling factor for velocity.
double precision c_norm
Normalised speed of light.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision unit_radflux
Physical scaling factor for radiation flux.
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(wprim, 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 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
Radiation-magneto-hydrodynamics module.
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)...
integer, public, protected rmhd_trac_type
Which TRAC method is used.
character(len=8), public rmhd_pressure
In the case of no rmhd_energy, how to compute pressure.
subroutine, public rmhd_phys_init()
logical, public, protected rmhd_thermal_conduction
Whether thermal conduction is used.
double precision, public rmhd_gamma
The adiabatic index.
character(len=8), public rmhd_radiation_formalism
Formalism to treat radiation.
logical, public divbwave
Add divB wave in Roe solver.
integer, public, protected rmhd_trac_finegrid
Distance between two adjacent traced magnetic field lines (in finest cell size)
double precision, public, protected h_ion_fr
Ionization fraction of H H_ion_fr = H+/(H+ + H)
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
logical, public, protected rmhd_hyperbolic_thermal_conduction
Whether thermal conduction is used.
double precision, public, protected rr
logical, public rmhd_equi_thermal
double precision, public rmhd_etah
Hall resistivity.
logical, public, protected rmhd_radiation_diffusion
Treat radiation energy diffusion.
subroutine, public rmhd_face_to_center(ixol, s)
calculate cell-center values from face-center values
procedure(sub_get_pthermal), pointer, public rmhd_get_pthermal
integer, public, protected psi_
Indices of the GLM psi.
type(tc_fluid), allocatable, public tc_fl
type of fluid for thermal conduction
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
subroutine, public b_from_vector_potential(ixisl, ixil, ixol, ws, x)
calculate magnetic field from vector potential
logical, public, protected rmhd_cak_force
Whether CAK radiation line force is activated.
logical, public, protected rmhd_radiation_force
Treat radiation fld_Rad_force.
logical, public, protected rmhd_glm
Whether GLM-MHD is used to control div B.
double precision, public, protected small_r_e
The smallest allowed radiation energy.
double precision, public rmhd_eta_hyper
The MHD hyper-resistivity.
logical, public clean_initial_divb
clean initial divB
integer, public, protected rmhd_n_tracer
Number of tracer species.
logical, public, protected rmhd_particles
Whether particles module is added.
integer, public, protected b
double precision, public kbmpmua4
kb/(m_p mu)* 1/a_rad**4,
integer, public, protected m
subroutine, public rmhd_get_trad(w, x, ixil, ixol, trad)
Calculates radiation temperature.
integer, public equi_rho0_
equi vars indices in the stateequi_vars array
double precision, public rmhd_adiab
The adiabatic constant.
subroutine, public rmhd_get_pthermal_plus_pradiation(w, x, ixil, ixol, pth_plus_prad)
Calculates the sum of the gas pressure and the max Prad tensor element.
integer, public, protected q_
Index of the heat flux q.
integer, public, protected tweight_
logical, public has_equi_rho0
whether split off equilibrium density
double precision, public rmhd_eta
The MHD resistivity.
integer, public, protected p_
Index of the gas pressure (-1 if not present) should equal e_.
subroutine, public get_normalized_divb(w, ixil, ixol, divb)
get dimensionless div B = |divB| * volume / area / |B|
integer, public, protected rho_
Index of the density (in the w array)
integer, public, protected c_
double precision function, dimension(ixo^s), public rmhd_mag_en_all(w, ixil, ixol)
Compute 2 times total magnetic energy.
type(te_fluid), allocatable, public te_fl_rmhd
type of fluid for thermal emission synthesis
logical, public, protected rmhd_gravity
Whether gravity is added.
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
logical, public, protected rmhd_glm_extended
Whether extended GLM-MHD is used with additional sources.
logical, public, protected rmhd_viscosity
Whether viscosity is added.
logical, public, protected rmhd_partial_ionization
Whether plasma is partially ionized.
integer, public, protected tcoff_
Index of the cutoff temperature for the TRAC method.
integer, public, protected e_
Index of the energy density (-1 if not present)
logical, public, protected rmhd_radiation_advection
Treat radiation advection.
double precision, public, protected he_ion_fr2
Ratio of number He2+ / number He+ + He2+ He_ion_fr2 = He2+/(He2+ + He+)
subroutine, public rmhd_get_rho(w, x, ixil, ixol, rho)
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
logical, public, protected rmhd_energy_interact
Treat radiation-gas energy interaction.
subroutine, public rmhd_get_tgas(w, x, ixil, ixol, tgas)
Calculates gas temperature.
character(len=std_len), public, protected type_ct
Method type of constrained transport.
procedure(sub_convert), pointer, public rmhd_to_conserved
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
logical, public partial_energy
Whether an internal or hydrodynamic energy equation is used.
procedure(sub_convert), pointer, public rmhd_to_primitive
logical, public, protected rmhd_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
logical, public, protected rmhd_trac
Whether TRAC method is used.
subroutine, public rmhd_clean_divb_multigrid(qdt, qt, active)
subroutine, public rmhd_set_mg_bounds
Set the boundaries for the diffusion of E.
subroutine, public rmhd_get_v(w, x, ixil, ixol, v)
Calculate v vector.
double precision, public hypertc_kappa
The thermal conductivity kappa in hyperbolic thermal conduction.
logical, public has_equi_pe0
whether split off equilibrium thermal pressure
subroutine, public rmhd_get_pradiation(w, x, ixil, ixol, prad, nth)
Calculate radiation pressure within ixO^L.
integer, public, protected te_
Indices of temperature.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
integer, public, protected r_e
Index of the radiation energy.
procedure(sub_get_pthermal), pointer, public rmhd_get_temperature
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
logical, public, protected b0field_forcefree
B0 field is force-free.
double precision, public rmhd_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
integer, public, protected rmhd_divb_nth
Whether divB is computed with a fourth order approximation.
subroutine, public rmhd_ei_to_e(ixil, ixol, w, x)
Transform internal energy to total energy.
integer, public equi_pe0_
double precision, public, protected he_ion_fr
Ionization fraction of He He_ion_fr = (He2+ + He+)/(He2+ + He+ + He)
logical, public, protected rmhd_energy
Whether an energy equation is used.
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
double precision, public, protected rmhd_trac_mask
Height of the mask used in the TRAC method.
logical, public, protected eq_state_units
subroutine, public rmhd_e_to_ei(ixil, ixol, w, x)
Transform total energy to internal energy.
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...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
Module with all the methods that users can customize in AMRVAC.
procedure(rfactor), pointer usr_rfactor
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_equi_vars), pointer usr_set_equi_vars
procedure(special_mg_bc), pointer usr_special_mg_bc
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(wprim, 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