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