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