MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_twofl_phys.t
Go to the documentation of this file.
1!> Magneto-hydrodynamics module
3
4#include "amrvac.h"
5
7 use mod_global_parameters, only: std_len
12 use mod_comm_lib, only: mpistop
13
14 implicit none
15 private
16 !! E_c = E_kin + E_mag + E_int
17 !! E_n = E_kin + E_int
18 integer, public, parameter :: eq_energy_tot=2
19 !! E_c = E_int
20 !! E_n = E_int
21 integer, public, parameter :: eq_energy_int=1
22 !! E_n, E_c are calculated from density as c_adiab rho^gamma
23 !! No energy equation => no variable assigned for it
24 integer, public, parameter :: eq_energy_none=0
25 !! E_c = E_kin + E_int
26 !! E_n = E_kin + E_int
27 integer, public, parameter :: eq_energy_ki=3
28
29 integer, public, protected :: twofl_eq_energy = eq_energy_tot
30
31 !> Whether hyperdiffusivity is used
32 logical, public, protected :: twofl_hyperdiffusivity = .false.
33 logical, public, protected :: twofl_dump_hyperdiffusivity_coef = .false.
34 double precision, public, protected, allocatable :: c_shk(:)
35 double precision, public, protected, allocatable :: c_hyp(:)
36
37 !> Whether thermal conduction is used
38 logical, public, protected :: twofl_thermal_conduction_c = .false.
39 !> type of TC used: 1: adapted module (mhd implementation), 2: adapted module (hd implementation)
40 integer, parameter, private :: mhd_tc =1
41 integer, parameter, private :: hd_tc =2
42 integer, protected :: use_twofl_tc_c = mhd_tc
43
44 !> Whether radiative cooling is added
45 logical, public, protected :: twofl_radiative_cooling_c = .false.
46 type(rc_fluid), public, allocatable :: rc_fl_c
47
48 !> Whether viscosity is added
49 logical, public, protected :: twofl_viscosity = .false.
50
51 !> Whether gravity is added: common flag for charges and neutrals
52 logical, public, protected :: twofl_gravity = .false.
53
54 !> whether dump full variables (when splitting is used) in a separate dat file
55 logical, public, protected :: twofl_dump_full_vars = .false.
56
57 !> Whether Hall-MHD is used
58 logical, public, protected :: twofl_hall = .false.
59
60 type(tc_fluid), public, allocatable :: tc_fl_c
61 type(te_fluid), public, allocatable :: te_fl_c
62
63 type(tc_fluid), allocatable :: tc_fl_n
64 logical, public, protected :: twofl_thermal_conduction_n = .false.
65 logical, public, protected :: twofl_radiative_cooling_n = .false.
66 type(rc_fluid), allocatable :: rc_fl_n
67
68 !> Whether TRAC method is used
69 logical, public, protected :: twofl_trac = .false.
70
71 !> Whether GLM-MHD is used
72 logical, public, protected :: twofl_glm = .false.
73
74 !> Which TRAC method is used
75 integer, public, protected :: twofl_trac_type=1
76
77 !> Height of the mask used in the TRAC method
78 double precision, public, protected :: twofl_trac_mask = 0.d0
79
80 !> Whether divB cleaning sources are added splitting from fluid solver
81 logical, public, protected :: source_split_divb = .false.
82
83 !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
84 !> taking values within [0, 1]
85 double precision, public :: twofl_glm_alpha = 0.5d0
86
87 !> Index of the density (in the w array)
88 integer, public :: rho_c_
89
90 !> Indices of the momentum density
91 integer, allocatable, public :: mom_c(:)
92 !> Indices of the momentum density for the form of better vectorization
93 integer, public, protected :: ^c&m^C_
94
95 !> Index of the energy density (-1 if not present)
96 integer, public :: e_c_=-1
97 !> Indices of the magnetic field for the form of better vectorization
98 integer, public, protected :: ^c&b^C_
99
100 !> Index of the cutoff temperature for the TRAC method
101 integer, public :: tcoff_c_
102 integer, public :: tweight_c_
103
104 !> Indices of the GLM psi
105 integer, public, protected :: psi_
106
107 !> equi vars flags
108 logical, public :: has_equi_rho_c0 = .false.
109 logical, public :: has_equi_pe_c0 = .false.
110
111 !> equi vars indices in the state%equi_vars array
112 integer, public :: equi_rho_c0_ = -1
113 integer, public :: equi_pe_c0_ = -1
114 logical, public :: twofl_equi_thermal_c = .false.
115
116 logical, public :: twofl_equi_thermal = .false.
117 !neutrals:
118
119 integer, public :: rho_n_
120 integer, allocatable, public :: mom_n(:)
121 integer, public :: e_n_
122 integer, public :: tcoff_n_
123 integer, public :: tweight_n_
124 logical, public :: has_equi_rho_n0 = .false.
125 logical, public :: has_equi_pe_n0 = .false.
126 integer, public :: equi_rho_n0_ = -1
127 integer, public :: equi_pe_n0_ = -1
128
129 ! related to collisions:
130 !> collisional alpha
131 double precision, public :: twofl_alpha_coll = 0d0
132 logical, public :: twofl_alpha_coll_constant = .true.
133 !> whether include thermal exchange collisional terms
134 logical, public :: twofl_coll_inc_te = .true.
135 !> whether include ionization/recombination inelastic collisional terms
136 logical, public :: twofl_coll_inc_ionrec = .false.
137 logical, public :: twofl_equi_thermal_n = .false.
138 double precision, public :: dtcollpar = -1d0 !negative value does not impose restriction on the timestep
139 !> whether dump collisional terms in a separte dat file
140 logical, public, protected :: twofl_dump_coll_terms = .false.
141
142 ! TODO Helium abundance not used, radiative cooling init uses it
143 ! not in parameters list anymore
144 double precision, public, protected :: he_abundance = 0d0
145 ! two fluid is only H plasma
146 double precision, public, protected :: rc = 2d0
147 double precision, public, protected :: rn = 1d0
148
149 !> The adiabatic index
150 double precision, public :: twofl_gamma = 5.d0/3.0d0
151
152 !> The adiabatic constant
153 double precision, public :: twofl_adiab = 1.0d0
154
155 !> The MHD resistivity
156 double precision, public :: twofl_eta = 0.0d0
157
158 !> The MHD hyper-resistivity
159 double precision, public :: twofl_eta_hyper = 0.0d0
160
161 !> The MHD Hall coefficient
162 double precision, public :: twofl_etah = 0.0d0
163
164 !> Method type to clean divergence of B
165 character(len=std_len), public, protected :: typedivbfix = 'linde'
166
167 !> Method type of constrained transport
168 character(len=std_len), public, protected :: type_ct = 'uct_contact'
169
170 !> Whether divB is computed with a fourth order approximation
171 integer, public, protected :: twofl_divb_nth = 1
172
173 !> Method type in a integer for good performance
174 integer :: type_divb
175
176 !> Coefficient of diffusive divB cleaning
177 double precision :: divbdiff = 0.8d0
178
179 !> Update all equations due to divB cleaning
180 character(len=std_len) :: typedivbdiff = 'all'
181
182 !> clean initial divB
183 logical, public :: clean_initial_divb = .false.
184
185 !> Add divB wave in Roe solver
186 logical, public :: divbwave = .true.
187
188 !> To control divB=0 fix for boundary
189 logical, public, protected :: boundary_divbfix(2*^nd)=.true.
190
191 !> To skip * layer of ghost cells during divB=0 fix for boundary
192 integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
193
194 !> B0 field is force-free
195 logical, public, protected :: b0field_forcefree=.true.
196
197 logical :: twofl_cbounds_species = .true.
198
199 !> added from modules: gravity
200 !> source split or not
201 logical :: grav_split= .false.
202
203 !> gamma minus one and its inverse
204 double precision :: gamma_1, inv_gamma_1
205
206 ! DivB cleaning methods
207 integer, parameter :: divb_none = 0
208 integer, parameter :: divb_multigrid = -1
209 integer, parameter :: divb_glm = 1
210 integer, parameter :: divb_powel = 2
211 integer, parameter :: divb_janhunen = 3
212 integer, parameter :: divb_linde = 4
213 integer, parameter :: divb_lindejanhunen = 5
214 integer, parameter :: divb_lindepowel = 6
215 integer, parameter :: divb_lindeglm = 7
216 integer, parameter :: divb_ct = 8
217
218 ! Public methods
219 public :: twofl_phys_init
220 public :: twofl_to_conserved
221 public :: twofl_to_primitive
222 public :: get_divb
223 public :: get_rhoc_tot
224 public :: twofl_get_v_c_idim
225 ! TODO needed for the roe, see if can be used for n
227 public :: get_rhon_tot
228 public :: get_alpha_coll
229 public :: get_gamma_ion_rec
230 public :: twofl_get_v_n_idim
231 public :: get_current
232 public :: twofl_get_pthermal_c
233 public :: twofl_get_pthermal_n
234 public :: twofl_face_to_center
235 public :: get_normalized_divb
237 public :: usr_mask_gamma_ion_rec
238 public :: usr_mask_alpha
239
240 {^nooned
242 }
243
244 abstract interface
245
246 subroutine implicit_mult_factor_subroutine(ixI^L, ixO^L, step_dt, JJ, res)
247 integer, intent(in) :: ixi^l, ixo^l
248 double precision, intent(in) :: step_dt
249 double precision, intent(in) :: jj(ixi^s)
250 double precision, intent(out) :: res(ixi^s)
251
252 end subroutine implicit_mult_factor_subroutine
253
254 subroutine mask_subroutine(ixI^L,ixO^L,w,x,res)
256 integer, intent(in) :: ixi^l, ixo^l
257 double precision, intent(in) :: x(ixi^s,1:ndim)
258 double precision, intent(in) :: w(ixi^s,1:nw)
259 double precision, intent(inout) :: res(ixi^s)
260 end subroutine mask_subroutine
261
262 subroutine mask_subroutine2(ixI^L,ixO^L,w,x,res1, res2)
264 integer, intent(in) :: ixi^l, ixo^l
265 double precision, intent(in) :: x(ixi^s,1:ndim)
266 double precision, intent(in) :: w(ixi^s,1:nw)
267 double precision, intent(inout) :: res1(ixi^s),res2(ixi^s)
268 end subroutine mask_subroutine2
269
270 end interface
271
272 procedure(implicit_mult_factor_subroutine), pointer :: calc_mult_factor => null()
273 integer, protected :: twofl_implicit_calc_mult_method = 1
274 procedure(mask_subroutine), pointer :: usr_mask_alpha => null()
275 procedure(mask_subroutine2), pointer :: usr_mask_gamma_ion_rec => null()
276
277contains
278
279 !> Read this module"s parameters from a file
280 subroutine twofl_read_params(files)
282 character(len=*), intent(in) :: files(:)
283 integer :: n
284
285 namelist /twofl_list/ twofl_eq_energy, twofl_gamma, twofl_adiab,&
289 typedivbdiff, type_ct, divbwave, si_unit, b0field,&
296 twofl_dump_coll_terms,twofl_implicit_calc_mult_method,&
299 twofl_trac, twofl_trac_type, twofl_trac_mask,twofl_cbounds_species
300
301 do n = 1, size(files)
302 open(unitpar, file=trim(files(n)), status="old")
303 read(unitpar, twofl_list, end=111)
304111 close(unitpar)
305 end do
306
307 end subroutine twofl_read_params
308
309 subroutine twofl_init_hyper(files)
312 character(len=*), intent(in) :: files(:)
313 integer :: n
314
315 namelist /hyperdiffusivity_list/ c_shk, c_hyp
316
317 do n = 1, size(files)
318 open(unitpar, file=trim(files(n)), status="old")
319 read(unitpar, hyperdiffusivity_list, end=113)
320113 close(unitpar)
321 end do
322
323 call hyperdiffusivity_init()
324
325 !!DEBUG
326 if(mype .eq. 0) then
327 print*, "Using Hyperdiffusivity"
328 print*, "C_SHK ", c_shk(:)
329 print*, "C_HYP ", c_hyp(:)
330 endif
331
332 end subroutine twofl_init_hyper
333
334 !> Write this module's parameters to a snapsoht
335 subroutine twofl_write_info(fh)
337 integer, intent(in) :: fh
338 integer, parameter :: n_par = 1
339 double precision :: values(n_par)
340 character(len=name_len) :: names(n_par)
341 integer, dimension(MPI_STATUS_SIZE) :: st
342 integer :: er
343
344 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
345
346 names(1) = "gamma"
347 values(1) = twofl_gamma
348 call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
349 call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
350 end subroutine twofl_write_info
351
352 subroutine twofl_phys_init()
357 !use mod_gravity, only: gravity_init
360 {^nooned
362 }
363 integer :: itr, idir
364
365 call twofl_read_params(par_files)
366 physics_type = "twofl"
367 if (twofl_cbounds_species) then
368 number_species = 2
369 endif
370 phys_energy=.true.
371 !> Solve total energy equation or not
372 ! for the two fluid the true value means
373 ! E_charges = E_mag + E_kin_charges + E_int_charges
374 ! E_neutrals = E_kin_neutrals + E_int_neutrals
375 phys_total_energy=.false.
376
377 !> Solve internal energy instead of total energy
378 ! for the two fluid the true value means
379 ! E_charges = E_int_charges
380 ! E_neutrals = E_int_neutrals
381 phys_internal_e=.false.
382
383 ! For the two fluid phys_energy=.true. and phys_internal_e=.false. and phys_total_energy = .false. means
384 ! E_charges = E_kin_charges + E_int_charges
385 ! E_neutrals = E_kin_neutrals + E_int_neutrals
386 phys_gamma = twofl_gamma
387
389 phys_internal_e = .true.
390 elseif(twofl_eq_energy == eq_energy_tot) then
391 phys_total_energy = .true.
392 elseif(twofl_eq_energy == eq_energy_none) then
393 phys_energy = .false.
394 endif
395
398
399 if(.not. phys_energy) then
402 if(mype==0) write(*,*) 'WARNING: set twofl_thermal_conduction_n=F when twofl_energy=F'
403 end if
406 if(mype==0) write(*,*) 'WARNING: set twofl_radiative_cooling_n=F when twofl_energy=F'
407 end if
410 if(mype==0) write(*,*) 'WARNING: set twofl_thermal_conduction_c=F when twofl_energy=F'
411 end if
414 if(mype==0) write(*,*) 'WARNING: set twofl_radiative_cooling_c=F when twofl_energy=F'
415 end if
416 if(twofl_trac) then
417 twofl_trac=.false.
418 if(mype==0) write(*,*) 'WARNING: set twofl_trac=F when twofl_energy=F'
419 end if
420 end if
421 {^ifoned
422 if(twofl_trac .and. twofl_trac_type .gt. 1) then
424 if(mype==0) write(*,*) 'WARNING: set twofl_trac_type=1 for 1D simulation'
425 end if
426 }
427 if(twofl_trac .and. twofl_trac_type .le. 3) then
428 twofl_trac_mask=bigdouble
429 if(mype==0) write(*,*) 'WARNING: set twofl_trac_mask==bigdouble for global TRAC method'
430 end if
432
433 ! set default gamma for polytropic/isothermal process
434 if(ndim==1) typedivbfix='none'
435 select case (typedivbfix)
436 case ('none')
437 type_divb = divb_none
438 {^nooned
439 case ('multigrid')
440 type_divb = divb_multigrid
441 use_multigrid = .true.
442 mg%operator_type = mg_laplacian
443 phys_global_source_after => twofl_clean_divb_multigrid
444 }
445 case ('glm')
446 twofl_glm = .true.
447 need_global_cmax = .true.
448 type_divb = divb_glm
449 case ('powel', 'powell')
450 type_divb = divb_powel
451 case ('janhunen')
452 type_divb = divb_janhunen
453 case ('linde')
454 type_divb = divb_linde
455 case ('lindejanhunen')
456 type_divb = divb_lindejanhunen
457 case ('lindepowel')
458 type_divb = divb_lindepowel
459 case ('lindeglm')
460 twofl_glm = .true.
461 need_global_cmax = .true.
462 type_divb = divb_lindeglm
463 case ('ct')
464 type_divb = divb_ct
465 stagger_grid = .true.
466 case default
467 call mpistop('Unknown divB fix')
468 end select
469
470 select case(type_ct)
471 case('average')
472 transverse_ghost_cells = 1
473 case('uct_contact')
474 transverse_ghost_cells = 1
475 case('uct_hll')
476 transverse_ghost_cells = 2
477 case default
478 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
479 end select
480
481 allocate(start_indices(number_species))
482 allocate(stop_indices(number_species))
483 start_indices(1)=1
484 !allocate charges first and the same order as in mhd module
485 rho_c_ = var_set_fluxvar("rho_c", "rho_c")
486 !set variables from mod_variables to point to charges vars
487 iw_rho = rho_c_
488
489 allocate(mom_c(ndir))
490 do idir=1,ndir
491 mom_c(idir) = var_set_fluxvar("m_c","v_c",idir)
492 enddo
493 m^c_=mom_c(^c);
494
495 allocate(iw_mom(ndir))
496 iw_mom(1:ndir) = mom_c(1:ndir)
497
498 ! Set index of energy variable
499 if (phys_energy) then
500 e_c_ = var_set_fluxvar("e_c", "p_c")
501 iw_e = e_c_
502 else
503 e_c_ = -1
504 end if
505
506 ! ambipolar sts assumes mag and energy charges are continuous
507 allocate(mag(ndir))
508 mag(:) = var_set_bfield(ndir)
509 b^c_=mag(^c);
510
511 if (twofl_glm) then
512 psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
513 else
514 psi_ = -1
515 end if
516
517 ! set cutoff temperature when using the TRAC method, as well as an auxiliary weight
518 tweight_c_ = -1
519 if(twofl_trac) then
520 tcoff_c_ = var_set_wextra()
521 iw_tcoff = tcoff_c_
522 if(twofl_trac_type > 2) then
523 tweight_c_ = var_set_wextra()
524 endif
525 else
526 tcoff_c_ = -1
527 end if
528
529 !now allocate neutrals
530
531 ! TODO so far number_species is only used to treat them differently
532 ! in the solvers (different cbounds)
533 if (twofl_cbounds_species) then
534 stop_indices(1)=nwflux
535 start_indices(2)=nwflux+1
536 endif
537
538 ! Determine flux variables
539 rho_n_ = var_set_fluxvar("rho_n", "rho_n")
540 allocate(mom_n(ndir))
541 do idir=1,ndir
542 mom_n(idir) = var_set_fluxvar("m_n","v_n",idir)
543 enddo
544 if (phys_energy) then
545 e_n_ = var_set_fluxvar("e_n", "p_n")
546 else
547 e_n_ = -1
548 end if
549
550 tweight_n_ = -1
551 if(twofl_trac) then
552 tcoff_n_ = var_set_wextra()
553 if(twofl_trac_type > 2) then
554 tweight_n_ = var_set_wextra()
555 endif
556 else
557 tcoff_n_ = -1
558 end if
559
560 stop_indices(number_species)=nwflux
561
562 ! set indices of equi vars and update number_equi_vars
564 if(has_equi_rho_n0) then
567 endif
568 if(has_equi_pe_n0) then
571 endif
572 if(has_equi_rho_c0) then
575 iw_equi_rho = equi_rho_c0_
576 endif
577 if(has_equi_pe_c0) then
580 iw_equi_p = equi_pe_c0_
581 endif
582
583 ! set number of variables which need update ghostcells
584 nwgc=nwflux+nwaux
585
586 ! determine number of stagger variables
587 nws=ndim
588
589 ! Check whether custom flux types have been defined
590 if (.not. allocated(flux_type)) then
591 allocate(flux_type(ndir, nw))
592 flux_type = flux_default
593 else if (any(shape(flux_type) /= [ndir, nw])) then
594 call mpistop("phys_check error: flux_type has wrong shape")
595 end if
596
597 if(ndim>1) then
598 if(twofl_glm) then
599 flux_type(:,psi_)=flux_special
600 do idir=1,ndir
601 flux_type(idir,mag(idir))=flux_special
602 end do
603 else
604 do idir=1,ndir
605 flux_type(idir,mag(idir))=flux_tvdlf
606 end do
607 end if
608 end if
609
610 phys_get_dt => twofl_get_dt
611 phys_get_cmax => twofl_get_cmax
612 !phys_get_tcutoff => twofl_get_tcutoff_c
613 if(twofl_cbounds_species) then
614 if (mype .eq. 0) print*, "Using different cbounds for each species nspecies = ", number_species
615 phys_get_cbounds => twofl_get_cbounds_species
616 phys_get_h_speed => twofl_get_h_speed_species
617 else
618 if (mype .eq. 0) print*, "Using same cbounds for all species"
619 phys_get_cbounds => twofl_get_cbounds_one
620 phys_get_h_speed => twofl_get_h_speed_one
621 endif
622 phys_get_flux => twofl_get_flux
623 phys_add_source_geom => twofl_add_source_geom
624 phys_add_source => twofl_add_source
625 phys_to_conserved => twofl_to_conserved
626 phys_to_primitive => twofl_to_primitive
627 phys_check_params => twofl_check_params
628 phys_check_w => twofl_check_w
629 phys_write_info => twofl_write_info
630 phys_handle_small_values => twofl_handle_small_values
631 !set equilibrium variables for the new grid
632 if(number_equi_vars>0) then
633 phys_set_equi_vars => set_equi_vars_grid
634 endif
635 ! convert_type is not known here, so associate the corresp. subroutine in check_params
636 if(type_divb==divb_glm) then
637 phys_modify_wlr => twofl_modify_wlr
638 end if
639
640 ! if using ct stagger grid, boundary divb=0 is not done here
641 if(stagger_grid) then
642 select case(type_ct)
643 case('average')
644 transverse_ghost_cells = 1
645 phys_get_ct_velocity => twofl_get_ct_velocity_average
646 phys_update_faces => twofl_update_faces_average
647 case('uct_contact')
648 transverse_ghost_cells = 1
649 phys_get_ct_velocity => twofl_get_ct_velocity_contact
650 phys_update_faces => twofl_update_faces_contact
651 case('uct_hll')
652 transverse_ghost_cells = 2
653 phys_get_ct_velocity => twofl_get_ct_velocity_hll
654 phys_update_faces => twofl_update_faces_hll
655 case default
656 call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
657 end select
658 phys_face_to_center => twofl_face_to_center
659 phys_modify_wlr => twofl_modify_wlr
660 else if(ndim>1) then
661 phys_boundary_adjust => twofl_boundary_adjust
662 end if
663
664 {^nooned
665 ! clean initial divb
667 }
668
669 ! derive units from basic units
670 call twofl_physical_units()
671
672 if(.not. phys_energy .and. (twofl_thermal_conduction_c&
674 call mpistop("thermal conduction needs twofl_energy=T")
675 end if
676
677 ! initialize thermal conduction module
680 call sts_init()
682 endif
684 allocate(tc_fl_c)
685 if(has_equi_pe_c0 .and. has_equi_rho_c0) then
686 tc_fl_c%get_temperature_from_eint => twofl_get_temperature_from_eint_c_with_equi
687 if(phys_internal_e) then
688 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_eint_c_with_equi
689 else
690 if(twofl_eq_energy == eq_energy_ki) then
691 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_eki_c_with_equi
692 else
693 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_etot_c_with_equi
694 endif
695 endif
696 if(twofl_equi_thermal_c) then
697 tc_fl_c%subtract_equi = .true.
698 tc_fl_c%get_temperature_equi => twofl_get_temperature_c_equi
699 tc_fl_c%get_rho_equi => twofl_get_rho_c_equi
700 else
701 tc_fl_c%subtract_equi = .false.
702 endif
703 else
704 if(phys_internal_e) then
705 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_eint_c
706 else
707 if(twofl_eq_energy == eq_energy_ki) then
708 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_eki_c
709 else
710 tc_fl_c%get_temperature_from_conserved => twofl_get_temperature_from_etot_c
711 endif
712 endif
713 tc_fl_c%get_temperature_from_eint => twofl_get_temperature_from_eint_c
714 endif
715 if(use_twofl_tc_c .eq. mhd_tc) then
716 call tc_get_mhd_params(tc_fl_c,tc_c_params_read_mhd)
717 call add_sts_method(twofl_get_tc_dt_mhd_c,twofl_sts_set_source_tc_c_mhd,e_c_,1,e_c_,1,.false.)
718 else if(use_twofl_tc_c .eq. hd_tc) then
719 call tc_get_hd_params(tc_fl_c,tc_c_params_read_hd)
720 call add_sts_method(twofl_get_tc_dt_hd_c,twofl_sts_set_source_tc_c_hd,e_c_,1,e_c_,1,.false.)
721 endif
722 if(.not. phys_internal_e) then
723 call set_conversion_methods_to_head(twofl_e_to_ei_c, twofl_ei_to_e_c)
724 endif
725 call set_error_handling_to_head(twofl_tc_handle_small_e_c)
726 tc_fl_c%get_rho => get_rhoc_tot
727 tc_fl_c%e_ = e_c_
728 tc_fl_c%Tcoff_ = tcoff_c_
729 end if
731 allocate(tc_fl_n)
732 call tc_get_hd_params(tc_fl_n,tc_n_params_read_hd)
733 if(has_equi_pe_n0 .and. has_equi_rho_n0) then
734 tc_fl_n%get_temperature_from_eint => twofl_get_temperature_from_eint_n_with_equi
735 if(twofl_equi_thermal_n) then
736 tc_fl_n%subtract_equi = .true.
737 tc_fl_n%get_temperature_equi => twofl_get_temperature_n_equi
738 tc_fl_n%get_rho_equi => twofl_get_rho_n_equi
739 else
740 tc_fl_n%subtract_equi = .false.
741 endif
742 else
743 tc_fl_n%get_temperature_from_eint => twofl_get_temperature_from_eint_n
744 endif
745 if(phys_internal_e) then
746 if(has_equi_pe_n0 .and. has_equi_rho_n0) then
747 tc_fl_n%get_temperature_from_conserved => twofl_get_temperature_from_eint_n_with_equi
748 else
749 tc_fl_n%get_temperature_from_conserved => twofl_get_temperature_from_eint_n
750 endif
751 call add_sts_method(twofl_get_tc_dt_hd_n,twofl_sts_set_source_tc_n_hd,e_n_,1,e_n_,1,.false.)
752 else
753 if(has_equi_pe_n0 .and. has_equi_rho_n0) then
754 tc_fl_n%get_temperature_from_conserved => twofl_get_temperature_from_etot_n_with_equi
755 else
756 tc_fl_n%get_temperature_from_conserved => twofl_get_temperature_from_etot_n
757 endif
758 call add_sts_method(twofl_get_tc_dt_hd_n,twofl_sts_set_source_tc_n_hd,e_n_,1,e_n_,1,.false.)
759 call set_conversion_methods_to_head(twofl_e_to_ei_n, twofl_ei_to_e_n)
760 endif
761 call set_error_handling_to_head(twofl_tc_handle_small_e_n)
762 tc_fl_n%get_rho => get_rhon_tot
763 tc_fl_n%e_ = e_n_
764 tc_fl_n%Tcoff_ = tcoff_n_
765 end if
766
767
768 if(.not. phys_energy .and. (twofl_radiative_cooling_c&
769 .or. twofl_radiative_cooling_n)) then
770 call mpistop("radiative cooling needs twofl_energy=T")
771 end if
772
773 if(twofl_equi_thermal .and. (.not. has_equi_pe_c0 .or. .not. has_equi_pe_n0)) then
774 call mpistop("twofl_equi_thermal=T has_equi_pe_n0 and has _equi_pe_c0=T")
775 endif
776
777 ! initialize thermal conduction module
780 ! Initialize radiative cooling module
783 allocate(rc_fl_c)
784 call radiative_cooling_init(rc_fl_c,rc_params_read_c)
785 rc_fl_c%get_rho => get_rhoc_tot
786 rc_fl_c%get_pthermal => twofl_get_pthermal_c
787 rc_fl_c%get_var_Rfactor => rfactor_c
788 rc_fl_c%e_ = e_c_
789 rc_fl_c%Tcoff_ = tcoff_c_
790 rc_fl_c%has_equi = has_equi_pe_c0 .and. has_equi_rho_c0
791 if(twofl_equi_thermal_c) then
792 rc_fl_c%subtract_equi = .true.
793 rc_fl_c%get_rho_equi => twofl_get_rho_c_equi
794 rc_fl_c%get_pthermal_equi => twofl_get_pe_c_equi
795 rc_fl_c%get_temperature_equi => twofl_get_temperature_c_equi
796 else
797 rc_fl_c%subtract_equi = .false.
798 end if
799 end if
801 call mpistop("twofl_radiative_cooling_n not implemented yet")
802 endif
803 end if
804
805{^ifthreed
806 allocate(te_fl_c)
807 te_fl_c%get_rho=> get_rhoc_tot
808 te_fl_c%get_pthermal=> twofl_get_pthermal_c
809 te_fl_c%get_var_Rfactor => rfactor_c
810 phys_te_images => twofl_te_images
811}
812
813 ! Initialize viscosity module
814 !if (twofl_viscosity) call viscosity_init(phys_wider_stencil)
815
816 ! Initialize gravity module
817 if(twofl_gravity) then
818 ! call gravity_init()
819 call grav_params_read(par_files)
820 end if
821
822 ! For Hall, we need one more reconstructed layer since currents are computed
823 ! in getflux: assuming one additional ghost layer (two for FOURTHORDER) was
824 ! added in nghostcells.
825 if (twofl_hall) then
826 phys_wider_stencil = 1
827 end if
828
830 allocate(c_shk(1:nwflux))
831 allocate(c_hyp(1:nwflux))
832 call twofl_init_hyper(par_files)
833 end if
834
835 end subroutine twofl_phys_init
836
837{^ifthreed
838 subroutine twofl_te_images
841
842 select case(convert_type)
843 case('EIvtiCCmpi','EIvtuCCmpi')
845 case('ESvtiCCmpi','ESvtuCCmpi')
847 case('SIvtiCCmpi','SIvtuCCmpi')
849 case('WIvtiCCmpi','WIvtuCCmpi')
851 case default
852 call mpistop("Error in synthesize emission: Unknown convert_type")
853 end select
854 end subroutine twofl_te_images
855}
856
857 ! wrappers for STS functions in thermal_conductivity module
858 ! which take as argument the tc_fluid (defined in the physics module)
859 subroutine twofl_sts_set_source_tc_c_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
863 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
864 double precision, intent(in) :: x(ixi^s,1:ndim)
865 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
866 double precision, intent(in) :: my_dt
867 logical, intent(in) :: fix_conserve_at_step
868 call sts_set_source_tc_mhd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl_c)
869 end subroutine twofl_sts_set_source_tc_c_mhd
870
871 subroutine twofl_sts_set_source_tc_c_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
875 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
876 double precision, intent(in) :: x(ixi^s,1:ndim)
877 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
878 double precision, intent(in) :: my_dt
879 logical, intent(in) :: fix_conserve_at_step
880 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl_c)
881 end subroutine twofl_sts_set_source_tc_c_hd
882
883 function twofl_get_tc_dt_mhd_c(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
884 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
885 !where tc_k_para_i=tc_k_para*B_i**2/B**2
886 !and T=p/rho
889
890 integer, intent(in) :: ixi^l, ixo^l
891 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
892 double precision, intent(in) :: w(ixi^s,1:nw)
893 double precision :: dtnew
894
895 dtnew=get_tc_dt_mhd(w,ixi^l,ixo^l,dx^d,x,tc_fl_c)
896 end function twofl_get_tc_dt_mhd_c
897
898 function twofl_get_tc_dt_hd_c(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
899 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
900 !where tc_k_para_i=tc_k_para*B_i**2/B**2
901 !and T=p/rho
904
905 integer, intent(in) :: ixi^l, ixo^l
906 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
907 double precision, intent(in) :: w(ixi^s,1:nw)
908 double precision :: dtnew
909
910 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl_c)
911 end function twofl_get_tc_dt_hd_c
912
913 subroutine twofl_tc_handle_small_e_c(w, x, ixI^L, ixO^L, step)
916
917 integer, intent(in) :: ixi^l,ixo^l
918 double precision, intent(inout) :: w(ixi^s,1:nw)
919 double precision, intent(in) :: x(ixi^s,1:ndim)
920 integer, intent(in) :: step
921
922 character(len=140) :: error_msg
923
924 write(error_msg,"(a,i3)") "Charges thermal conduction step ", step
925 call twofl_handle_small_ei_c(w,x,ixi^l,ixo^l,e_c_,error_msg)
926 end subroutine twofl_tc_handle_small_e_c
927
928 subroutine twofl_sts_set_source_tc_n_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux)
932 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
933 double precision, intent(in) :: x(ixi^s,1:ndim)
934 double precision, intent(inout) :: wres(ixi^s,1:nw), w(ixi^s,1:nw)
935 double precision, intent(in) :: my_dt
936 logical, intent(in) :: fix_conserve_at_step
937 call sts_set_source_tc_hd(ixi^l,ixo^l,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,tc_fl_n)
938 end subroutine twofl_sts_set_source_tc_n_hd
939
940 subroutine twofl_tc_handle_small_e_n(w, x, ixI^L, ixO^L, step)
942
943 integer, intent(in) :: ixi^l,ixo^l
944 double precision, intent(inout) :: w(ixi^s,1:nw)
945 double precision, intent(in) :: x(ixi^s,1:ndim)
946 integer, intent(in) :: step
947
948 character(len=140) :: error_msg
949
950 write(error_msg,"(a,i3)") "Neutral thermal conduction step ", step
951 call twofl_handle_small_ei_n(w,x,ixi^l,ixo^l,e_n_,error_msg)
952 end subroutine twofl_tc_handle_small_e_n
953
954 function twofl_get_tc_dt_hd_n(w,ixI^L,ixO^L,dx^D,x) result(dtnew)
955 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
956 !where tc_k_para_i=tc_k_para*B_i**2/B**2
957 !and T=p/rho
960
961 integer, intent(in) :: ixi^l, ixo^l
962 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
963 double precision, intent(in) :: w(ixi^s,1:nw)
964 double precision :: dtnew
965
966 dtnew=get_tc_dt_hd(w,ixi^l,ixo^l,dx^d,x,tc_fl_n)
967 end function twofl_get_tc_dt_hd_n
968
969 subroutine tc_n_params_read_hd(fl)
972 type(tc_fluid), intent(inout) :: fl
973 integer :: n
974 logical :: tc_saturate=.false.
975 double precision :: tc_k_para=0d0
976
977 namelist /tc_n_list/ tc_saturate, tc_k_para
978
979 do n = 1, size(par_files)
980 open(unitpar, file=trim(par_files(n)), status="old")
981 read(unitpar, tc_n_list, end=111)
982111 close(unitpar)
983 end do
984 fl%tc_saturate = tc_saturate
985 fl%tc_k_para = tc_k_para
986
987 end subroutine tc_n_params_read_hd
988
989 subroutine rc_params_read_n(fl)
991 use mod_constants, only: bigdouble
992 type(rc_fluid), intent(inout) :: fl
993 integer :: n
994 ! list parameters
995 integer :: ncool = 4000
996
997 !> Name of cooling curve
998 character(len=std_len) :: coolcurve='JCorona'
999
1000 !> Fixed temperature not lower than tlow
1001 logical :: tfix=.false.
1002
1003 !> Lower limit of temperature
1004 double precision :: tlow=bigdouble
1005
1006 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1007 logical :: rc_split=.false.
1008
1009 namelist /rc_list_n/ coolcurve, ncool, tlow, tfix, rc_split
1010
1011 do n = 1, size(par_files)
1012 open(unitpar, file=trim(par_files(n)), status="old")
1013 read(unitpar, rc_list_n, end=111)
1014111 close(unitpar)
1015 end do
1016
1017 fl%ncool=ncool
1018 fl%coolcurve=coolcurve
1019 fl%tlow=tlow
1020 fl%Tfix=tfix
1021 fl%rc_split=rc_split
1022 end subroutine rc_params_read_n
1023
1024 !end wrappers
1025
1026 ! fill in tc_fluid fields from namelist
1027 subroutine tc_c_params_read_mhd(fl)
1029 type(tc_fluid), intent(inout) :: fl
1030
1031 integer :: n
1032
1033 ! list parameters
1034 logical :: tc_perpendicular=.false.
1035 logical :: tc_saturate=.false.
1036 double precision :: tc_k_para=0d0
1037 double precision :: tc_k_perp=0d0
1038 character(len=std_len) :: tc_slope_limiter="MC"
1039
1040 namelist /tc_c_list/ tc_perpendicular, tc_saturate, tc_slope_limiter, tc_k_para, tc_k_perp
1041 do n = 1, size(par_files)
1042 open(unitpar, file=trim(par_files(n)), status="old")
1043 read(unitpar, tc_c_list, end=111)
1044111 close(unitpar)
1045 end do
1046
1047 fl%tc_perpendicular = tc_perpendicular
1048 fl%tc_saturate = tc_saturate
1049 fl%tc_k_para = tc_k_para
1050 fl%tc_k_perp = tc_k_perp
1051 select case(tc_slope_limiter)
1052 case ('no','none')
1053 fl%tc_slope_limiter = 0
1054 case ('MC')
1055 ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
1056 fl%tc_slope_limiter = 1
1057 case('minmod')
1058 ! minmod limiter
1059 fl%tc_slope_limiter = 2
1060 case ('superbee')
1061 ! Roes superbee limiter (eq.3.51i)
1062 fl%tc_slope_limiter = 3
1063 case ('koren')
1064 ! Barry Koren Right variant
1065 fl%tc_slope_limiter = 4
1066 case default
1067 call mpistop("Unknown tc_slope_limiter, choose MC, minmod")
1068 end select
1069 end subroutine tc_c_params_read_mhd
1070
1071 subroutine tc_c_params_read_hd(fl)
1074 type(tc_fluid), intent(inout) :: fl
1075 integer :: n
1076 logical :: tc_saturate=.false.
1077 double precision :: tc_k_para=0d0
1078
1079 namelist /tc_c_list/ tc_saturate, tc_k_para
1080
1081 do n = 1, size(par_files)
1082 open(unitpar, file=trim(par_files(n)), status="old")
1083 read(unitpar, tc_c_list, end=111)
1084111 close(unitpar)
1085 end do
1086 fl%tc_saturate = tc_saturate
1087 fl%tc_k_para = tc_k_para
1088
1089 end subroutine tc_c_params_read_hd
1090
1091!! end th cond
1092
1093!!rad cool
1094 subroutine rc_params_read_c(fl)
1096 use mod_constants, only: bigdouble
1097 type(rc_fluid), intent(inout) :: fl
1098 integer :: n
1099 ! list parameters
1100 integer :: ncool = 4000
1101
1102 !> Name of cooling curve
1103 character(len=std_len) :: coolcurve='JCcorona'
1104
1105 !> Fixed temperature not lower than tlow
1106 logical :: tfix=.false.
1107
1108 !> Lower limit of temperature
1109 double precision :: tlow=bigdouble
1110
1111 !> Add cooling source in a split way (.true.) or un-split way (.false.)
1112 logical :: rc_split=.false.
1113
1114
1115 namelist /rc_list_c/ coolcurve, ncool, tlow, tfix, rc_split
1116
1117 do n = 1, size(par_files)
1118 open(unitpar, file=trim(par_files(n)), status="old")
1119 read(unitpar, rc_list_c, end=111)
1120111 close(unitpar)
1121 end do
1122
1123 fl%ncool=ncool
1124 fl%coolcurve=coolcurve
1125 fl%tlow=tlow
1126 fl%Tfix=tfix
1127 fl%rc_split=rc_split
1128 end subroutine rc_params_read_c
1129
1130!! end rad cool
1131
1132 !> sets the equilibrium variables
1133 subroutine set_equi_vars_grid_faces(igrid,x,ixI^L,ixO^L)
1136 use mod_usr_methods
1137 integer, intent(in) :: igrid, ixi^l, ixo^l
1138 double precision, intent(in) :: x(ixi^s,1:ndim)
1139
1140 double precision :: delx(ixi^s,1:ndim)
1141 double precision :: xc(ixi^s,1:ndim),xshift^d
1142 integer :: idims, ixc^l, hxo^l, ix, idims2
1143
1144 if(slab_uniform)then
1145 ^d&delx(ixi^s,^d)=rnode(rpdx^d_,igrid)\
1146 else
1147 ! for all non-cartesian and stretched cartesian coordinates
1148 delx(ixi^s,1:ndim)=ps(igrid)%dx(ixi^s,1:ndim)
1149 endif
1150
1151
1152 do idims=1,ndim
1153 hxo^l=ixo^l-kr(idims,^d);
1154 if(stagger_grid) then
1155 ! ct needs all transverse cells
1156 ixcmax^d=ixomax^d+nghostcells-nghostcells*kr(idims,^d); ixcmin^d=hxomin^d-nghostcells+nghostcells*kr(idims,^d);
1157 else
1158 ! ixC is centered index in the idims direction from ixOmin-1/2 to ixOmax+1/2
1159 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
1160 end if
1161 ! always xshift=0 or 1/2
1162 xshift^d=half*(one-kr(^d,idims));
1163 do idims2=1,ndim
1164 select case(idims2)
1165 {case(^d)
1166 do ix = ixc^lim^d
1167 ! xshift=half: this is the cell center coordinate
1168 ! xshift=0: this is the cell edge i+1/2 coordinate
1169 xc(ix^d%ixC^s,^d)=x(ix^d%ixC^s,^d)+(half-xshift^d)*delx(ix^d%ixC^s,^d)
1170 end do\}
1171 end select
1172 end do
1173 call usr_set_equi_vars(ixi^l,ixc^l,xc,ps(igrid)%equi_vars(ixi^s,1:number_equi_vars,idims))
1174 end do
1175
1176 end subroutine set_equi_vars_grid_faces
1177
1178 !> sets the equilibrium variables
1179 subroutine set_equi_vars_grid(igrid)
1181 use mod_usr_methods
1182
1183 integer, intent(in) :: igrid
1184
1185 !values at the center
1186 call usr_set_equi_vars(ixg^ll,ixg^ll,ps(igrid)%x,ps(igrid)%equi_vars(ixg^t,1:number_equi_vars,0))
1187
1188 !values at the interfaces
1189 call set_equi_vars_grid_faces(igrid,ps(igrid)%x,ixg^ll,ixm^ll)
1190
1191 end subroutine set_equi_vars_grid
1192
1193 ! w, wnew conserved
1194 function convert_vars_splitting(ixI^L,ixO^L, w, x, nwc) result(wnew)
1196 integer, intent(in) :: ixi^l,ixo^l, nwc
1197 double precision, intent(in) :: w(ixi^s, 1:nw)
1198 double precision, intent(in) :: x(ixi^s,1:ndim)
1199 double precision :: wnew(ixo^s, 1:nwc)
1200 double precision :: rho(ixi^s)
1201
1202 call get_rhon_tot(w,x,ixi^l,ixo^l,rho(ixi^s))
1203 wnew(ixo^s,rho_n_) = rho(ixo^s)
1204 wnew(ixo^s,mom_n(:)) = w(ixo^s,mom_n(:))
1205 call get_rhoc_tot(w,x,ixi^l,ixo^l,rho(ixi^s))
1206 wnew(ixo^s,rho_c_) = rho(ixo^s)
1207 wnew(ixo^s,mom_c(:)) = w(ixo^s,mom_c(:))
1208
1209 if (b0field) then
1210 ! add background magnetic field B0 to B
1211 wnew(ixo^s,mag(:))=w(ixo^s,mag(:))+block%B0(ixo^s,:,0)
1212 else
1213 wnew(ixo^s,mag(:))=w(ixo^s,mag(:))
1214 end if
1215
1216 if(phys_energy) then
1217 wnew(ixo^s,e_n_) = w(ixo^s,e_n_)
1218 if(has_equi_pe_n0) then
1219 wnew(ixo^s,e_n_) = wnew(ixo^s,e_n_) + block%equi_vars(ixo^s,equi_pe_n0_,0)* inv_gamma_1
1220 endif
1221 wnew(ixo^s,e_c_) = w(ixo^s,e_c_)
1222 if(has_equi_pe_c0) then
1223 wnew(ixo^s,e_c_) = wnew(ixo^s,e_c_) + block%equi_vars(ixo^s,equi_pe_c0_,0)* inv_gamma_1
1224 endif
1225 if(b0field .and. phys_total_energy) then
1226 wnew(ixo^s,e_c_)=wnew(ixo^s,e_c_)+0.5d0*sum(block%B0(ixo^s,:,0)**2,dim=ndim+1) &
1227 + sum(w(ixo^s,mag(:))*block%B0(ixo^s,:,0),dim=ndim+1)
1228 endif
1229 endif
1230
1231 end function convert_vars_splitting
1232
1233 !> copied from mod_gravity
1234 subroutine grav_params_read(files)
1236 character(len=*), intent(in) :: files(:)
1237 integer :: n
1238
1239 namelist /grav_list/ grav_split
1240
1241 do n = 1, size(files)
1242 open(unitpar, file=trim(files(n)), status="old")
1243 read(unitpar, grav_list, end=111)
1244111 close(unitpar)
1245 end do
1246
1247 end subroutine grav_params_read
1248
1249 subroutine associate_dump_hyper()
1252 integer :: ii
1253 do ii = 1,ndim
1254 if(ii==1) then
1255 call add_convert_method(dump_hyperdiffusivity_coef_x, nw, cons_wnames(1:nw), "hyper_x")
1256 elseif(ii==2) then
1257 call add_convert_method(dump_hyperdiffusivity_coef_y, nw, cons_wnames(1:nw), "hyper_y")
1258 else
1259 call add_convert_method(dump_hyperdiffusivity_coef_z, nw, cons_wnames(1:nw), "hyper_z")
1260 endif
1261 enddo
1262 end subroutine associate_dump_hyper
1263
1264 subroutine twofl_check_params
1266 use mod_usr_methods
1268
1269 ! after user parameter setting
1270 gamma_1=twofl_gamma-1.d0
1271 if (.not. phys_energy) then
1272 if (twofl_gamma <= 0.0d0) call mpistop ("Error: twofl_gamma <= 0")
1273 if (twofl_adiab < 0.0d0) call mpistop ("Error: twofl_adiab < 0")
1275 else
1276 if (twofl_gamma <= 0.0d0 .or. twofl_gamma == 1.0d0) &
1277 call mpistop ("Error: twofl_gamma <= 0 or twofl_gamma == 1")
1278 inv_gamma_1=1.d0/gamma_1
1279 small_e = small_pressure * inv_gamma_1
1280 end if
1281
1282 ! this has to be done here as use_imex_scheme is not set in init subroutine,
1283 ! but here it is
1284 if(use_imex_scheme) then
1285 if(has_collisions()) then
1286 ! implicit collisional terms update
1287 phys_implicit_update => twofl_implicit_coll_terms_update
1288 phys_evaluate_implicit => twofl_evaluate_implicit
1289 if(mype .eq. 1) then
1290 print*, "IMPLICIT UPDATE with calc_mult_factor", twofl_implicit_calc_mult_method
1291 endif
1292 if(twofl_implicit_calc_mult_method == 1) then
1293 calc_mult_factor => calc_mult_factor1
1294 else
1295 calc_mult_factor => calc_mult_factor2
1296 endif
1297 endif
1298 else
1299 ! check dtcoll par for explicit implementation of the coll. terms
1300 if(dtcollpar .le. 0d0 .or. dtcollpar .ge. 1d0) then
1301 if (mype .eq. 0) print*, "Explicit update of coll terms requires 0<dtcollpar<1, dtcollpar set to 0.8."
1302 dtcollpar = 0.8
1303 endif
1304
1305 endif
1306! if(H_ion_fr == 0d0 .and. He_ion_fr == 0d0) then
1307! call mpistop("H_ion_fr or He_ion_fr must be > 0 or use hd module")
1308! endif
1309! if(H_ion_fr == 1d0 .and. He_ion_fr == 1d0) then
1310! call mpistop("H_ion_fr or He_ion_fr must be < 1 or use mhd module")
1311! endif
1312 if (number_equi_vars > 0 .and. .not. associated(usr_set_equi_vars)) then
1313 call mpistop("usr_set_equi_vars has to be implemented in the user file")
1314 endif
1315 if(convert .or. autoconvert) then
1316 if(convert_type .eq. 'dat_generic_mpi') then
1317 if(twofl_dump_full_vars) then
1318 if(mype .eq. 0) print*, " add conversion method: split -> full "
1319 call add_convert_method(convert_vars_splitting, nw, cons_wnames, "new")
1320 endif
1321 if(twofl_dump_coll_terms) then
1322 if(mype .eq. 0) print*, " add conversion method: dump coll terms "
1323 call add_convert_method(dump_coll_terms, 3, (/"alpha ", "gamma_rec", "gamma_ion"/), "_coll")
1324 endif
1326 if(mype .eq. 0) print*, " add conversion method: dump hyperdiffusivity coeff. "
1327 call associate_dump_hyper()
1328 endif
1329 endif
1330 endif
1331 end subroutine twofl_check_params
1332
1333 subroutine twofl_physical_units()
1335 double precision :: mp,kb,miu0,c_lightspeed
1336 double precision :: a,b
1337 ! Derive scaling units
1338 if(si_unit) then
1339 mp=mp_si
1340 kb=kb_si
1341 miu0=miu0_si
1342 c_lightspeed=c_si
1343 else
1344 mp=mp_cgs
1345 kb=kb_cgs
1346 miu0=4.d0*dpi
1347 c_lightspeed=const_c
1348 end if
1349
1350 a=1d0
1351 b=1d0
1352 rc=2d0
1353 rn=1d0
1354 ! assume unit_length is alway specified
1355 if(unit_density/=1.d0 .or. unit_numberdensity/=1.d0) then
1356 if(unit_density/=1.d0) then
1358 else if(unit_numberdensity/=1.d0) then
1360 end if
1361 if(unit_temperature/=1.d0) then
1366 else if(unit_magneticfield/=1.d0) then
1371 else if(unit_pressure/=1.d0) then
1376 else if(unit_velocity/=1.d0) then
1381 else if(unit_time/=1.d0) then
1386 end if
1387 else if(unit_temperature/=1.d0) then
1388 ! units of temperature and velocity are dependent
1389 if(unit_magneticfield/=1.d0) then
1395 else if(unit_pressure/=1.d0) then
1401 end if
1402 else if(unit_magneticfield/=1.d0) then
1403 ! units of magnetic field and pressure are dependent
1404 if(unit_velocity/=1.d0) then
1410 else if(unit_time/=0.d0) then
1416 end if
1417 else if(unit_pressure/=1.d0) then
1418 if(unit_velocity/=1.d0) then
1424 else if(unit_time/=0.d0) then
1430 end if
1431 end if
1432 ! Additional units needed for particles
1433 c_norm=c_lightspeed/unit_velocity
1435 if (.not. si_unit) unit_charge = unit_charge*const_c
1437 end subroutine twofl_physical_units
1438
1439 subroutine twofl_check_w(primitive,ixI^L,ixO^L,w,flag)
1441
1442 logical, intent(in) :: primitive
1443 integer, intent(in) :: ixi^l, ixo^l
1444 double precision, intent(in) :: w(ixi^s,nw)
1445 double precision :: tmp(ixi^s)
1446 logical, intent(inout) :: flag(ixi^s,1:nw)
1447
1448 flag=.false.
1449
1450 if(has_equi_rho_n0) then
1451 tmp(ixo^s) = w(ixo^s,rho_n_) + block%equi_vars(ixo^s,equi_rho_n0_,0)
1452 else
1453 tmp(ixo^s) = w(ixo^s,rho_n_)
1454 endif
1455 where(tmp(ixo^s) < small_density) flag(ixo^s,rho_n_) = .true.
1456 if(has_equi_rho_c0) then
1457 tmp(ixo^s) = w(ixo^s,rho_c_) + block%equi_vars(ixo^s,equi_rho_c0_,0)
1458 else
1459 tmp(ixo^s) = w(ixo^s,rho_c_)
1460 endif
1461 where(tmp(ixo^s) < small_density) flag(ixo^s,rho_c_) = .true.
1462 if(phys_energy) then
1463 if(primitive) then
1464 tmp(ixo^s) = w(ixo^s,e_n_)
1465 if(has_equi_pe_n0) then
1466 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_n0_,0)
1467 endif
1468 where(tmp(ixo^s) < small_pressure) flag(ixo^s,e_n_) = .true.
1469 tmp(ixo^s) = w(ixo^s,e_c_)
1470 if(has_equi_pe_c0) then
1471 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_c0_,0)
1472 endif
1473 where(tmp(ixo^s) < small_pressure) flag(ixo^s,e_c_) = .true.
1474 else
1475 if(phys_internal_e) then
1476 tmp(ixo^s)=w(ixo^s,e_n_)
1477 if(has_equi_pe_n0) then
1478 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
1479 endif
1480 where(tmp(ixo^s) < small_e) flag(ixo^s,e_n_) = .true.
1481 tmp(ixo^s)=w(ixo^s,e_c_)
1482 if(has_equi_pe_c0) then
1483 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
1484 endif
1485 where(tmp(ixo^s) < small_e) flag(ixo^s,e_c_) = .true.
1486 else
1487 !neutrals
1488 tmp(ixo^s)=w(ixo^s,e_n_)-&
1489 twofl_kin_en_n(w,ixi^l,ixo^l)
1490 if(has_equi_pe_n0) then
1491 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
1492 endif
1493 where(tmp(ixo^s) < small_e) flag(ixo^s,e_n_) = .true.
1494 if(phys_total_energy) then
1495 tmp(ixo^s)=w(ixo^s,e_c_)-&
1496 twofl_kin_en_c(w,ixi^l,ixo^l)-twofl_mag_en(w,ixi^l,ixo^l)
1497 else
1498 tmp(ixo^s)=w(ixo^s,e_c_)-&
1499 twofl_kin_en_c(w,ixi^l,ixo^l)
1500 end if
1501 if(has_equi_pe_c0) then
1502 tmp(ixo^s) = tmp(ixo^s)+block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
1503 endif
1504 where(tmp(ixo^s) < small_e) flag(ixo^s,e_c_) = .true.
1505 end if
1506 endif
1507 end if
1508
1509 end subroutine twofl_check_w
1510
1511 !> Transform primitive variables into conservative ones
1512 subroutine twofl_to_conserved(ixI^L,ixO^L,w,x)
1514 integer, intent(in) :: ixi^l, ixo^l
1515 double precision, intent(inout) :: w(ixi^s, nw)
1516 double precision, intent(in) :: x(ixi^s, 1:ndim)
1517 integer :: idir
1518 double precision :: rhoc(ixi^s)
1519 double precision :: rhon(ixi^s)
1520
1521 !if (fix_small_values) then
1522 ! call twofl_handle_small_values(.true., w, x, ixI^L, ixO^L, 'twofl_to_conserved')
1523 !end if
1524
1525 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
1526 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
1527
1528 ! Calculate total energy from pressure, kinetic and magnetic energy
1529 if(phys_energy) then
1530 if(phys_internal_e) then
1531 w(ixo^s,e_n_)=w(ixo^s,e_n_)*inv_gamma_1
1532 w(ixo^s,e_c_)=w(ixo^s,e_c_)*inv_gamma_1
1533 else
1534 w(ixo^s,e_n_)=w(ixo^s,e_n_)*inv_gamma_1&
1535 +half*sum(w(ixo^s,mom_n(:))**2,dim=ndim+1)*rhon(ixo^s)
1536 if(phys_total_energy) then
1537 w(ixo^s,e_c_)=w(ixo^s,e_c_)*inv_gamma_1&
1538 +half*sum(w(ixo^s,mom_c(:))**2,dim=ndim+1)*rhoc(ixo^s)&
1539 +twofl_mag_en(w, ixi^l, ixo^l)
1540 else
1541 ! kinetic energy + internal energy is evolved
1542 w(ixo^s,e_c_)=w(ixo^s,e_c_)*inv_gamma_1&
1543 +half*sum(w(ixo^s,mom_c(:))**2,dim=ndim+1)*rhoc(ixo^s)
1544 end if
1545 end if
1546 end if
1547
1548 ! Convert velocity to momentum
1549 do idir = 1, ndir
1550 w(ixo^s, mom_n(idir)) = rhon(ixo^s) * w(ixo^s, mom_n(idir))
1551 w(ixo^s, mom_c(idir)) = rhoc(ixo^s) * w(ixo^s, mom_c(idir))
1552 end do
1553 end subroutine twofl_to_conserved
1554
1555 !> Transform conservative variables into primitive ones
1556 subroutine twofl_to_primitive(ixI^L,ixO^L,w,x)
1558 integer, intent(in) :: ixi^l, ixo^l
1559 double precision, intent(inout) :: w(ixi^s, nw)
1560 double precision, intent(in) :: x(ixi^s, 1:ndim)
1561 integer :: idir
1562 double precision :: rhoc(ixi^s)
1563 double precision :: rhon(ixi^s)
1564
1565 if (fix_small_values) then
1566 call twofl_handle_small_values(.false., w, x, ixi^l, ixo^l, 'twofl_to_primitive')
1567 end if
1568
1569 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
1570 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
1571
1572 if(phys_energy) then
1573 if(phys_internal_e) then
1574 w(ixo^s,e_n_)=w(ixo^s,e_n_)*gamma_1
1575 w(ixo^s,e_c_)=w(ixo^s,e_c_)*gamma_1
1576 else
1577 ! neutrals evolved energy = ke + e_int
1578 w(ixo^s,e_n_)=gamma_1*(w(ixo^s,e_n_)&
1579 -twofl_kin_en_n(w,ixi^l,ixo^l))
1580 ! charges
1581 if(phys_total_energy) then
1582 ! evolved energy = ke + e_int + e_mag
1583 w(ixo^s,e_c_)=gamma_1*(w(ixo^s,e_c_)&
1584 -twofl_kin_en_c(w,ixi^l,ixo^l)&
1585 -twofl_mag_en(w,ixi^l,ixo^l))
1586 else
1587 ! evolved energy = ke + e_int
1588 w(ixo^s,e_c_)=gamma_1*(w(ixo^s,e_c_)&
1589 -twofl_kin_en_c(w,ixi^l,ixo^l))
1590 end if
1591 end if
1592 end if
1593
1594 ! Convert momentum to velocity
1595 do idir = 1, ndir
1596 w(ixo^s, mom_c(idir)) = w(ixo^s, mom_c(idir))/rhoc(ixo^s)
1597 w(ixo^s, mom_n(idir)) = w(ixo^s, mom_n(idir))/rhon(ixo^s)
1598 end do
1599
1600 end subroutine twofl_to_primitive
1601
1602!!USED IN TC
1603 !> Transform internal energy to total energy
1604 subroutine twofl_ei_to_e_c(ixI^L,ixO^L,w,x)
1606 integer, intent(in) :: ixi^l, ixo^l
1607 double precision, intent(inout) :: w(ixi^s, nw)
1608 double precision, intent(in) :: x(ixi^s, 1:ndim)
1609
1610 ! Calculate total energy from internal, kinetic and magnetic energy
1611 if(twofl_eq_energy == eq_energy_ki) then
1612 w(ixo^s,e_c_)=w(ixo^s,e_c_)&
1613 +twofl_kin_en_c(w,ixi^l,ixo^l)
1614 else
1615 w(ixo^s,e_c_)=w(ixo^s,e_c_)&
1616 +twofl_kin_en_c(w,ixi^l,ixo^l)&
1617 +twofl_mag_en(w,ixi^l,ixo^l)
1618 endif
1619 end subroutine twofl_ei_to_e_c
1620
1621 !> Transform total energy to internal energy
1622 subroutine twofl_e_to_ei_c(ixI^L,ixO^L,w,x)
1624 integer, intent(in) :: ixi^l, ixo^l
1625 double precision, intent(inout) :: w(ixi^s, nw)
1626 double precision, intent(in) :: x(ixi^s, 1:ndim)
1627
1628 if(twofl_eq_energy == eq_energy_ki) then
1629 w(ixo^s,e_c_)=w(ixo^s,e_c_)&
1630 -twofl_kin_en_c(w,ixi^l,ixo^l)
1631 else
1632 ! Calculate ei = e - ek - eb
1633 w(ixo^s,e_c_)=w(ixo^s,e_c_)&
1634 -twofl_kin_en_c(w,ixi^l,ixo^l)&
1635 -twofl_mag_en(w,ixi^l,ixo^l)
1636 endif
1637 end subroutine twofl_e_to_ei_c
1638
1639 !Neutrals
1640 subroutine twofl_ei_to_e_n(ixI^L,ixO^L,w,x)
1642 integer, intent(in) :: ixi^l, ixo^l
1643 double precision, intent(inout) :: w(ixi^s, nw)
1644 double precision, intent(in) :: x(ixi^s, 1:ndim)
1645
1646 ! Calculate total energy from internal and kinetic energy
1647
1648 w(ixo^s,e_n_)=w(ixo^s,e_n_)+twofl_kin_en_n(w,ixi^l,ixo^l)
1649
1650 end subroutine twofl_ei_to_e_n
1651
1652 !> Transform total energy to internal energy
1653 subroutine twofl_e_to_ei_n(ixI^L,ixO^L,w,x)
1655 integer, intent(in) :: ixi^l, ixo^l
1656 double precision, intent(inout) :: w(ixi^s, nw)
1657 double precision, intent(in) :: x(ixi^s, 1:ndim)
1658
1659 ! Calculate ei = e - ek
1660 w(ixo^s,e_n_)=w(ixo^s,e_n_)-twofl_kin_en_n(w,ixi^l,ixo^l)
1661
1662 call twofl_handle_small_ei_n(w,x,ixi^l,ixo^l,e_n_,"e_to_ei_n")
1663 end subroutine twofl_e_to_ei_n
1664
1665 subroutine twofl_handle_small_values(primitive, w, x, ixI^L, ixO^L, subname)
1668 logical, intent(in) :: primitive
1669 integer, intent(in) :: ixi^l,ixo^l
1670 double precision, intent(inout) :: w(ixi^s,1:nw)
1671 double precision, intent(in) :: x(ixi^s,1:ndim)
1672 character(len=*), intent(in) :: subname
1673
1674 integer :: idir
1675 logical :: flag(ixi^s,1:nw)
1676 double precision :: tmp2(ixi^s)
1677 double precision :: tmp1(ixi^s)
1678
1679 call twofl_check_w(primitive, ixi^l, ixo^l, w, flag)
1680
1681 if(any(flag)) then
1682 select case (small_values_method)
1683 case ("replace")
1684 if(has_equi_rho_c0) then
1685 where(flag(ixo^s,rho_c_)) w(ixo^s,rho_c_) = &
1686 small_density-block%equi_vars(ixo^s,equi_rho_c0_,0)
1687 else
1688 where(flag(ixo^s,rho_c_)) w(ixo^s,rho_c_) = small_density
1689 end if
1690 if(has_equi_rho_n0) then
1691 where(flag(ixo^s,rho_n_)) w(ixo^s,rho_n_) = &
1692 small_density-block%equi_vars(ixo^s,equi_rho_n0_,0)
1693 else
1694 where(flag(ixo^s,rho_n_)) w(ixo^s,rho_n_) = small_density
1695 end if
1696 do idir = 1, ndir
1697 if(small_values_fix_iw(mom_n(idir))) then
1698 where(flag(ixo^s,rho_n_)) w(ixo^s, mom_n(idir)) = 0.0d0
1699 end if
1700 if(small_values_fix_iw(mom_c(idir))) then
1701 where(flag(ixo^s,rho_c_)) w(ixo^s, mom_c(idir)) = 0.0d0
1702 end if
1703 end do
1704
1705 if(phys_energy) then
1706 if(primitive) then
1707 if(has_equi_pe_n0) then
1708 tmp1(ixo^s) = small_pressure - &
1709 block%equi_vars(ixo^s,equi_pe_n0_,0)
1710 else
1711 tmp1(ixo^s) = small_pressure
1712 end if
1713 if(has_equi_pe_c0) then
1714 tmp2(ixo^s) = small_e - &
1715 block%equi_vars(ixo^s,equi_pe_c0_,0)
1716 else
1717 tmp2(ixo^s) = small_pressure
1718 end if
1719 else
1720 ! conserved
1721 if(has_equi_pe_n0) then
1722 tmp1(ixo^s) = small_e - &
1723 block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
1724 else
1725 tmp1(ixo^s) = small_e
1726 end if
1727 if(has_equi_pe_c0) then
1728 tmp2(ixo^s) = small_e - &
1729 block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
1730 else
1731 tmp2(ixo^s) = small_e
1732 end if
1733 if(phys_internal_e) then
1734 where(flag(ixo^s,e_n_))
1735 w(ixo^s,e_n_)=tmp1(ixo^s)
1736 end where
1737 where(flag(ixo^s,e_c_))
1738 w(ixo^s,e_c_)=tmp2(ixo^s)
1739 end where
1740 else
1741 where(flag(ixo^s,e_n_))
1742 w(ixo^s,e_n_) = tmp1(ixo^s)+&
1743 twofl_kin_en_n(w,ixi^l,ixo^l)
1744 end where
1745 if(phys_total_energy) then
1746 where(flag(ixo^s,e_c_))
1747 w(ixo^s,e_c_) = tmp2(ixo^s)+&
1748 twofl_kin_en_c(w,ixi^l,ixo^l)+&
1749 twofl_mag_en(w,ixi^l,ixo^l)
1750 end where
1751 else
1752 where(flag(ixo^s,e_c_))
1753 w(ixo^s,e_c_) = tmp2(ixo^s)+&
1754 twofl_kin_en_c(w,ixi^l,ixo^l)
1755 end where
1756 end if
1757 end if
1758 end if
1759 end if
1760 case ("average")
1761 call small_values_average(ixi^l, ixo^l, w, x, flag)
1762 case default
1763 if(.not.primitive) then
1764 !convert w to primitive
1765 ! Calculate pressure = (gamma-1) * (e-ek-eb)
1766 if(phys_energy) then
1767 if(phys_internal_e) then
1768 w(ixo^s,e_c_)=w(ixo^s,e_c_)*gamma_1
1769 w(ixo^s,e_n_)=w(ixo^s,e_n_)*gamma_1
1770 else
1771 w(ixo^s,e_n_)=gamma_1*(w(ixo^s,e_n_)&
1772 -twofl_kin_en_n(w,ixi^l,ixo^l))
1773 if(phys_total_energy) then
1774 w(ixo^s,e_c_)=gamma_1*(w(ixo^s,e_c_)&
1775 -twofl_kin_en_c(w,ixi^l,ixo^l)&
1776 -twofl_mag_en(w,ixi^l,ixo^l))
1777 else
1778 w(ixo^s,e_c_)=gamma_1*(w(ixo^s,e_c_)&
1779 -twofl_kin_en_c(w,ixi^l,ixo^l))
1780
1781 end if
1782 end if
1783 end if
1784 ! Convert momentum to velocity
1785 if(has_equi_rho_n0) then
1786 tmp1(ixo^s) = w(ixo^s,rho_n_) + block%equi_vars(ixo^s,equi_rho_n0_,0)
1787 else
1788 tmp1(ixo^s) = w(ixo^s,rho_n_)
1789 end if
1790
1791 if(has_equi_rho_c0) then
1792 tmp2(ixo^s) = w(ixo^s,rho_c_) + block%equi_vars(ixo^s,equi_rho_c0_,0)
1793 else
1794 tmp2(ixo^s) = w(ixo^s,rho_c_)
1795 end if
1796 do idir = 1, ndir
1797 w(ixo^s, mom_n(idir)) = w(ixo^s, mom_n(idir))/tmp1(ixo^s)
1798 w(ixo^s, mom_c(idir)) = w(ixo^s, mom_c(idir))/tmp2(ixo^s)
1799 end do
1800 end if
1801 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
1802 end select
1803 end if
1804 end subroutine twofl_handle_small_values
1805
1806 !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
1807 subroutine twofl_get_cmax(w,x,ixI^L,ixO^L,idim,cmax)
1809
1810 integer, intent(in) :: ixi^l, ixo^l, idim
1811 ! w in primitive form
1812 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
1813 double precision, intent(inout) :: cmax(ixi^s)
1814 double precision :: cmax2(ixi^s),rhon(ixi^s)
1815
1816 call twofl_get_csound_c_idim(w,x,ixi^l,ixo^l,idim,cmax)
1817 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
1818 if(phys_energy) then
1819 if(has_equi_pe_n0) then
1820 cmax2(ixo^s)=sqrt(twofl_gamma*(w(ixo^s,e_n_)+&
1821 block%equi_vars(ixo^s,equi_pe_n0_,b0i))/rhon(ixo^s))
1822 else
1823 cmax2(ixo^s)=sqrt(twofl_gamma*w(ixo^s,e_n_)/rhon(ixo^s))
1824 end if
1825 else
1826 cmax2(ixo^s)=sqrt(twofl_gamma*twofl_adiab*rhon(ixo^s)**gamma_1)
1827 end if
1828 cmax(ixo^s)=max(abs(w(ixo^s,mom_n(idim)))+cmax2(ixo^s),&
1829 abs(w(ixo^s,mom_c(idim)))+cmax(ixo^s))
1830
1831 end subroutine twofl_get_cmax
1832
1833 ! COPIED from hd/moh_hd_phys
1834 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
1835 subroutine twofl_get_tcutoff_n(ixI^L,ixO^L,w,x,tco_local,Tmax_local)
1837 integer, intent(in) :: ixi^l,ixo^l
1838 double precision, intent(in) :: x(ixi^s,1:ndim),w(ixi^s,1:nw)
1839 double precision, intent(out) :: tco_local, tmax_local
1840
1841 double precision, parameter :: delta=0.25d0
1842 double precision :: tmp1(ixi^s),te(ixi^s),lts(ixi^s)
1843 integer :: jxo^l,hxo^l
1844 logical :: lrlt(ixi^s)
1845
1846 {^ifoned
1847 ! reuse lts as rhon
1848 call get_rhon_tot(w,x,ixi^l,ixi^l,lts)
1849 tmp1(ixi^s)=w(ixi^s,e_n_)-0.5d0*sum(w(ixi^s,mom_n(:))**2,dim=ndim+1)/lts(ixi^s)
1850 te(ixi^s)=tmp1(ixi^s)/lts(ixi^s)*(twofl_gamma-1.d0)
1851
1852 tmax_local=maxval(te(ixo^s))
1853
1854 hxo^l=ixo^l-1;
1855 jxo^l=ixo^l+1;
1856 lts(ixo^s)=0.5d0*abs(te(jxo^s)-te(hxo^s))/te(ixo^s)
1857 lrlt=.false.
1858 where(lts(ixo^s) > delta)
1859 lrlt(ixo^s)=.true.
1860 end where
1861 tco_local=zero
1862 if(any(lrlt(ixo^s))) then
1863 tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
1864 end if
1865 }
1866 end subroutine twofl_get_tcutoff_n
1867
1868 !> get adaptive cutoff temperature for TRAC (Johnston 2019 ApJL, 873, L22)
1869 subroutine twofl_get_tcutoff_c(ixI^L,ixO^L,w,x,Tco_local,Tmax_local)
1871 use mod_geometry
1872 integer, intent(in) :: ixi^l,ixo^l
1873 double precision, intent(in) :: x(ixi^s,1:ndim)
1874 double precision, intent(inout) :: w(ixi^s,1:nw)
1875 double precision, intent(out) :: tco_local,tmax_local
1876
1877 double precision, parameter :: trac_delta=0.25d0
1878 double precision :: tmp1(ixi^s),te(ixi^s),lts(ixi^s)
1879 double precision, dimension(ixI^S,1:ndir) :: bunitvec
1880 double precision, dimension(ixI^S,1:ndim) :: gradt
1881 double precision :: bdir(ndim)
1882 double precision :: ltr(ixi^s),ltrc,ltrp,altr(ixi^s)
1883 integer :: idims,jxo^l,hxo^l,ixa^d,ixb^d
1884 integer :: jxp^l,hxp^l,ixp^l
1885 logical :: lrlt(ixi^s)
1886
1887 ! reuse lts as rhoc
1888 call get_rhoc_tot(w,x,ixi^l,ixi^l,lts)
1889 if(phys_internal_e) then
1890 tmp1(ixi^s)=w(ixi^s,e_c_)
1891 else
1892 tmp1(ixi^s)=w(ixi^s,e_c_)-0.5d0*(sum(w(ixi^s,mom_c(:))**2,dim=ndim+1)/&
1893 lts(ixi^s)+sum(w(ixi^s,mag(:))**2,dim=ndim+1))
1894 end if
1895 te(ixi^s)=tmp1(ixi^s)/lts(ixi^s)*(twofl_gamma-1.d0)
1896 tmax_local=maxval(te(ixo^s))
1897
1898 {^ifoned
1899 select case(twofl_trac_type)
1900 case(0)
1901 !> test case, fixed cutoff temperature
1902 w(ixi^s,tcoff_c_)=2.5d5/unit_temperature
1903 case(1)
1904 hxo^l=ixo^l-1;
1905 jxo^l=ixo^l+1;
1906 lts(ixo^s)=0.5d0*abs(te(jxo^s)-te(hxo^s))/te(ixo^s)
1907 lrlt=.false.
1908 where(lts(ixo^s) > trac_delta)
1909 lrlt(ixo^s)=.true.
1910 end where
1911 if(any(lrlt(ixo^s))) then
1912 tco_local=maxval(te(ixo^s), mask=lrlt(ixo^s))
1913 end if
1914 case(2)
1915 !> iijima et al. 2021, LTRAC method
1916 ltrc=1.5d0
1917 ltrp=2.5d0
1918 ixp^l=ixo^l^ladd1;
1919 hxo^l=ixo^l-1;
1920 jxo^l=ixo^l+1;
1921 hxp^l=ixp^l-1;
1922 jxp^l=ixp^l+1;
1923 lts(ixp^s)=0.5d0*abs(te(jxp^s)-te(hxp^s))/te(ixp^s)
1924 ltr(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
1925 w(ixo^s,tcoff_c_)=te(ixo^s)*&
1926 (0.25*(ltr(jxo^s)+two*ltr(ixo^s)+ltr(hxo^s)))**0.4d0
1927 case default
1928 call mpistop("twofl_trac_type not allowed for 1D simulation")
1929 end select
1930 }
1931 {^nooned
1932 select case(twofl_trac_type)
1933 case(0)
1934 !> test case, fixed cutoff temperature
1935 w(ixi^s,tcoff_c_)=2.5d5/unit_temperature
1936 case(1,4,6)
1937 ! temperature gradient at cell centers
1938 do idims=1,ndim
1939 call gradient(te,ixi^l,ixo^l,idims,tmp1)
1940 gradt(ixo^s,idims)=tmp1(ixo^s)
1941 end do
1942 ! B vector
1943 if(b0field) then
1944 bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))+block%B0(ixo^s,:,0)
1945 else
1946 bunitvec(ixo^s,:)=w(ixo^s,iw_mag(:))
1947 end if
1948 if(twofl_trac_type .gt. 1) then
1949 ! B direction at cell center
1950 bdir=zero
1951 {do ixa^d=0,1\}
1952 ixb^d=(ixomin^d+ixomax^d-1)/2+ixa^d;
1953 bdir(1:ndim)=bdir(1:ndim)+bunitvec(ixb^d,1:ndim)
1954 {end do\}
1955 if(sum(bdir(:)**2) .gt. zero) then
1956 bdir(1:ndim)=bdir(1:ndim)/dsqrt(sum(bdir(:)**2))
1957 end if
1958 block%special_values(3:ndim+2)=bdir(1:ndim)
1959 end if
1960 tmp1(ixo^s)=dsqrt(sum(bunitvec(ixo^s,:)**2,dim=ndim+1))
1961 where(tmp1(ixo^s)/=0.d0)
1962 tmp1(ixo^s)=1.d0/tmp1(ixo^s)
1963 elsewhere
1964 tmp1(ixo^s)=bigdouble
1965 end where
1966 ! b unit vector: magnetic field direction vector
1967 do idims=1,ndim
1968 bunitvec(ixo^s,idims)=bunitvec(ixo^s,idims)*tmp1(ixo^s)
1969 end do
1970 ! temperature length scale inversed
1971 lts(ixo^s)=abs(sum(gradt(ixo^s,1:ndim)*bunitvec(ixo^s,1:ndim),dim=ndim+1))/te(ixo^s)
1972 ! fraction of cells size to temperature length scale
1973 if(slab_uniform) then
1974 lts(ixo^s)=minval(dxlevel)*lts(ixo^s)
1975 else
1976 lts(ixo^s)=minval(block%ds(ixo^s,:),dim=ndim+1)*lts(ixo^s)
1977 end if
1978 lrlt=.false.
1979 where(lts(ixo^s) > trac_delta)
1980 lrlt(ixo^s)=.true.
1981 end where
1982 if(any(lrlt(ixo^s))) then
1983 block%special_values(1)=maxval(te(ixo^s), mask=lrlt(ixo^s))
1984 else
1985 block%special_values(1)=zero
1986 end if
1987 block%special_values(2)=tmax_local
1988 case(2)
1989 !> iijima et al. 2021, LTRAC method
1990 ltrc=1.5d0
1991 ltrp=4.d0
1992 ixp^l=ixo^l^ladd1;
1993 ! temperature gradient at cell centers
1994 do idims=1,ndim
1995 call gradient(te,ixi^l,ixp^l,idims,tmp1)
1996 gradt(ixp^s,idims)=tmp1(ixp^s)
1997 end do
1998 ! B vector
1999 if(b0field) then
2000 bunitvec(ixp^s,:)=w(ixp^s,iw_mag(:))+block%B0(ixp^s,:,0)
2001 else
2002 bunitvec(ixp^s,:)=w(ixp^s,iw_mag(:))
2003 end if
2004 tmp1(ixp^s)=dsqrt(sum(bunitvec(ixp^s,:)**2,dim=ndim+1))
2005 where(tmp1(ixp^s)/=0.d0)
2006 tmp1(ixp^s)=1.d0/tmp1(ixp^s)
2007 elsewhere
2008 tmp1(ixp^s)=bigdouble
2009 end where
2010 ! b unit vector: magnetic field direction vector
2011 do idims=1,ndim
2012 bunitvec(ixp^s,idims)=bunitvec(ixp^s,idims)*tmp1(ixp^s)
2013 end do
2014 ! temperature length scale inversed
2015 lts(ixp^s)=abs(sum(gradt(ixp^s,1:ndim)*bunitvec(ixp^s,1:ndim),dim=ndim+1))/te(ixp^s)
2016 ! fraction of cells size to temperature length scale
2017 if(slab_uniform) then
2018 lts(ixp^s)=minval(dxlevel)*lts(ixp^s)
2019 else
2020 lts(ixp^s)=minval(block%ds(ixp^s,:),dim=ndim+1)*lts(ixp^s)
2021 end if
2022 ltr(ixp^s)=max(one, (exp(lts(ixp^s))/ltrc)**ltrp)
2023
2024 altr(ixi^s)=zero
2025 do idims=1,ndim
2026 hxo^l=ixo^l-kr(idims,^d);
2027 jxo^l=ixo^l+kr(idims,^d);
2028 altr(ixo^s)=altr(ixo^s) &
2029 +0.25*(ltr(hxo^s)+two*ltr(ixo^s)+ltr(jxo^s))*bunitvec(ixo^s,idims)**2
2030 w(ixo^s,tcoff_c_)=te(ixo^s)*altr(ixo^s)**(0.4*ltrp)
2031 end do
2032 case(3,5)
2033 !> do nothing here
2034 case default
2035 call mpistop("unknown twofl_trac_type")
2036 end select
2037 }
2038 end subroutine twofl_get_tcutoff_c
2039
2040 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
2041 subroutine twofl_get_h_speed_one(wprim,x,ixI^L,ixO^L,idim,Hspeed)
2043
2044 integer, intent(in) :: ixi^l, ixo^l, idim
2045 double precision, intent(in) :: wprim(ixi^s, nw)
2046 double precision, intent(in) :: x(ixi^s,1:ndim)
2047 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
2048
2049 double precision :: csound(ixi^s,ndim),tmp(ixi^s)
2050 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
2051
2052 hspeed=0.d0
2053 ixa^l=ixo^l^ladd1;
2054 do id=1,ndim
2055 call twofl_get_csound_prim(wprim,x,ixi^l,ixa^l,id,tmp)
2056 csound(ixa^s,id)=tmp(ixa^s)
2057 end do
2058 ixcmax^d=ixomax^d;
2059 ixcmin^d=ixomin^d+kr(idim,^d)-1;
2060 jxcmax^d=ixcmax^d+kr(idim,^d);
2061 jxcmin^d=ixcmin^d+kr(idim,^d);
2062 hspeed(ixc^s,1)=0.5d0*abs(&
2063 0.5d0 * (wprim(jxc^s,mom_c(idim))+ wprim(jxc^s,mom_n(idim))) &
2064 +csound(jxc^s,idim)- &
2065 0.5d0 * (wprim(ixc^s,mom_c(idim)) + wprim(ixc^s,mom_n(idim)))&
2066 +csound(ixc^s,idim))
2067
2068 do id=1,ndim
2069 if(id==idim) cycle
2070 ixamax^d=ixcmax^d+kr(id,^d);
2071 ixamin^d=ixcmin^d+kr(id,^d);
2072 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(&
2073 0.5d0 * (wprim(ixa^s,mom_c(id)) + wprim(ixa^s,mom_n(id)))&
2074 +csound(ixa^s,id)-&
2075 0.5d0 * (wprim(ixc^s,mom_c(id)) + wprim(ixc^s,mom_n(id)))&
2076 +csound(ixc^s,id)))
2077
2078
2079 ixamax^d=ixcmax^d-kr(id,^d);
2080 ixamin^d=ixcmin^d-kr(id,^d);
2081 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(&
2082 0.5d0 * (wprim(ixc^s,mom_c(id)) + wprim(ixc^s,mom_n(id)))&
2083 +csound(ixc^s,id)-&
2084 0.5d0 * (wprim(ixa^s,mom_c(id)) + wprim(ixa^s,mom_n(id)))&
2085 +csound(ixa^s,id)))
2086
2087 end do
2088
2089 do id=1,ndim
2090 if(id==idim) cycle
2091 ixamax^d=jxcmax^d+kr(id,^d);
2092 ixamin^d=jxcmin^d+kr(id,^d);
2093 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(&
2094 0.5d0 * (wprim(ixa^s,mom_c(id)) + wprim(ixa^s,mom_n(id)))&
2095 +csound(ixa^s,id)-&
2096 0.5d0 * (wprim(jxc^s,mom_c(id)) + wprim(jxc^s,mom_n(id)))&
2097 +csound(jxc^s,id)))
2098 ixamax^d=jxcmax^d-kr(id,^d);
2099 ixamin^d=jxcmin^d-kr(id,^d);
2100 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(&
2101 0.5d0 * (wprim(jxc^s,mom_c(id)) + wprim(jxc^s,mom_n(id)))&
2102 +csound(jxc^s,id)-&
2103 0.5d0 * (wprim(ixa^s,mom_c(id)) + wprim(ixa^s,mom_n(id)))&
2104 +csound(ixa^s,id)))
2105 end do
2106
2107 end subroutine twofl_get_h_speed_one
2108
2109 !> get H speed for H-correction to fix the carbuncle problem at grid-aligned shock front
2110 subroutine twofl_get_h_speed_species(wprim,x,ixI^L,ixO^L,idim,Hspeed)
2112
2113 integer, intent(in) :: ixi^l, ixo^l, idim
2114 double precision, intent(in) :: wprim(ixi^s, nw)
2115 double precision, intent(in) :: x(ixi^s,1:ndim)
2116 double precision, intent(out) :: hspeed(ixi^s,1:number_species)
2117
2118 double precision :: csound(ixi^s,ndim),tmp(ixi^s)
2119 integer :: jxc^l, ixc^l, ixa^l, id, ix^d
2120
2121 hspeed=0.d0
2122 ! charges
2123 ixa^l=ixo^l^ladd1;
2124 do id=1,ndim
2125 call twofl_get_csound_prim_c(wprim,x,ixi^l,ixa^l,id,tmp)
2126 csound(ixa^s,id)=tmp(ixa^s)
2127 end do
2128 ixcmax^d=ixomax^d;
2129 ixcmin^d=ixomin^d+kr(idim,^d)-1;
2130 jxcmax^d=ixcmax^d+kr(idim,^d);
2131 jxcmin^d=ixcmin^d+kr(idim,^d);
2132 hspeed(ixc^s,1)=0.5d0*abs(wprim(jxc^s,mom_c(idim))+csound(jxc^s,idim)-wprim(ixc^s,mom_c(idim))+csound(ixc^s,idim))
2133
2134 do id=1,ndim
2135 if(id==idim) cycle
2136 ixamax^d=ixcmax^d+kr(id,^d);
2137 ixamin^d=ixcmin^d+kr(id,^d);
2138 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixa^s,mom_c(id))+csound(ixa^s,id)-wprim(ixc^s,mom_c(id))+csound(ixc^s,id)))
2139 ixamax^d=ixcmax^d-kr(id,^d);
2140 ixamin^d=ixcmin^d-kr(id,^d);
2141 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixc^s,mom_c(id))+csound(ixc^s,id)-wprim(ixa^s,mom_c(id))+csound(ixa^s,id)))
2142 end do
2143
2144 do id=1,ndim
2145 if(id==idim) cycle
2146 ixamax^d=jxcmax^d+kr(id,^d);
2147 ixamin^d=jxcmin^d+kr(id,^d);
2148 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(ixa^s,mom_c(id))+csound(ixa^s,id)-wprim(jxc^s,mom_c(id))+csound(jxc^s,id)))
2149 ixamax^d=jxcmax^d-kr(id,^d);
2150 ixamin^d=jxcmin^d-kr(id,^d);
2151 hspeed(ixc^s,1)=max(hspeed(ixc^s,1),0.5d0*abs(wprim(jxc^s,mom_c(id))+csound(jxc^s,id)-wprim(ixa^s,mom_c(id))+csound(ixa^s,id)))
2152 end do
2153
2154 ! neutrals
2155 ixa^l=ixo^l^ladd1;
2156 do id=1,ndim
2157 call twofl_get_csound_prim_n(wprim,x,ixi^l,ixa^l,id,tmp)
2158 csound(ixa^s,id)=tmp(ixa^s)
2159 end do
2160 ixcmax^d=ixomax^d;
2161 ixcmin^d=ixomin^d+kr(idim,^d)-1;
2162 jxcmax^d=ixcmax^d+kr(idim,^d);
2163 jxcmin^d=ixcmin^d+kr(idim,^d);
2164 hspeed(ixc^s,2)=0.5d0*abs(wprim(jxc^s,mom_n(idim))+csound(jxc^s,idim)-wprim(ixc^s,mom_n(idim))+csound(ixc^s,idim))
2165
2166 do id=1,ndim
2167 if(id==idim) cycle
2168 ixamax^d=ixcmax^d+kr(id,^d);
2169 ixamin^d=ixcmin^d+kr(id,^d);
2170 hspeed(ixc^s,2)=max(hspeed(ixc^s,2),0.5d0*abs(wprim(ixa^s,mom_n(id))+csound(ixa^s,id)-wprim(ixc^s,mom_n(id))+csound(ixc^s,id)))
2171 ixamax^d=ixcmax^d-kr(id,^d);
2172 ixamin^d=ixcmin^d-kr(id,^d);
2173 hspeed(ixc^s,2)=max(hspeed(ixc^s,2),0.5d0*abs(wprim(ixc^s,mom_n(id))+csound(ixc^s,id)-wprim(ixa^s,mom_n(id))+csound(ixa^s,id)))
2174 end do
2175
2176 do id=1,ndim
2177 if(id==idim) cycle
2178 ixamax^d=jxcmax^d+kr(id,^d);
2179 ixamin^d=jxcmin^d+kr(id,^d);
2180 hspeed(ixc^s,2)=max(hspeed(ixc^s,2),0.5d0*abs(wprim(ixa^s,mom_n(id))+csound(ixa^s,id)-wprim(jxc^s,mom_n(id))+csound(jxc^s,id)))
2181 ixamax^d=jxcmax^d-kr(id,^d);
2182 ixamin^d=jxcmin^d-kr(id,^d);
2183 hspeed(ixc^s,2)=max(hspeed(ixc^s,2),0.5d0*abs(wprim(jxc^s,mom_n(id))+csound(jxc^s,id)-wprim(ixa^s,mom_n(id))+csound(ixa^s,id)))
2184 end do
2185
2186 end subroutine twofl_get_h_speed_species
2187
2188 !> Estimating bounds for the minimum and maximum signal velocities
2189 subroutine twofl_get_cbounds_one(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
2192
2193 integer, intent(in) :: ixi^l, ixo^l, idim
2194 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
2195 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
2196 double precision, intent(in) :: x(ixi^s,1:ndim)
2197 double precision, intent(inout) :: cmax(ixi^s,number_species)
2198 double precision, intent(inout), optional :: cmin(ixi^s,number_species)
2199 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
2200
2201 double precision :: wmean(ixi^s,nw)
2202 double precision :: rhon(ixi^s)
2203 double precision :: rhoc(ixi^s)
2204 double precision, dimension(ixI^S) :: umean, dmean, csoundl, csoundr, tmp1,tmp2,tmp3
2205 integer :: ix^d
2206
2207 select case (boundspeed)
2208 case (1)
2209 ! This implements formula (10.52) from "Riemann Solvers and Numerical
2210 ! Methods for Fluid Dynamics" by Toro.
2211 call get_rhoc_tot(wlp,x,ixi^l,ixo^l,rhoc)
2212 call get_rhon_tot(wlp,x,ixi^l,ixo^l,rhon)
2213 tmp1(ixo^s)=sqrt(abs(rhoc(ixo^s) +rhon(ixo^s)))
2214
2215 call get_rhoc_tot(wrp,x,ixi^l,ixo^l,rhoc)
2216 call get_rhon_tot(wrp,x,ixi^l,ixo^l,rhon)
2217 tmp2(ixo^s)=sqrt(abs(rhoc(ixo^s) +rhon(ixo^s)))
2218
2219 tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
2220 umean(ixo^s)=(0.5*(wlp(ixo^s,mom_n(idim))+wlp(ixo^s,mom_c(idim)))*tmp1(ixo^s) + &
2221 0.5*(wrp(ixo^s,mom_n(idim))+wrp(ixo^s,mom_c(idim)))*tmp2(ixo^s))*tmp3(ixo^s)
2222 call twofl_get_csound_prim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2223 call twofl_get_csound_prim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2224
2225 dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)**2+tmp2(ixo^s)*csoundr(ixo^s)**2)*tmp3(ixo^s)+&
2226 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2*(&
2227 0.5*(wrp(ixo^s,mom_n(idim))+wrp(ixo^s,mom_c(idim)))- &
2228 0.5*(wlp(ixo^s,mom_n(idim))+wlp(ixo^s,mom_c(idim))))**2
2229 dmean(ixo^s)=sqrt(dmean(ixo^s))
2230 if(present(cmin)) then
2231 cmin(ixo^s,1)=umean(ixo^s)-dmean(ixo^s)
2232 cmax(ixo^s,1)=umean(ixo^s)+dmean(ixo^s)
2233 if(h_correction) then
2234 {do ix^db=ixomin^db,ixomax^db\}
2235 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2236 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2237 {end do\}
2238 end if
2239 else
2240 cmax(ixo^s,1)=abs(umean(ixo^s))+dmean(ixo^s)
2241 end if
2242 case (2)
2243 ! typeboundspeed=='cmaxmean'
2244 wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
2245 call get_rhon_tot(wmean,x,ixi^l,ixo^l,rhon)
2246 tmp2(ixo^s)=wmean(ixo^s,mom_n(idim))/rhon(ixo^s)
2247 call get_rhoc_tot(wmean,x,ixi^l,ixo^l,rhoc)
2248 tmp1(ixo^s)=wmean(ixo^s,mom_c(idim))/rhoc(ixo^s)
2249 call twofl_get_csound(wmean,x,ixi^l,ixo^l,idim,csoundr)
2250 if(present(cmin)) then
2251 cmax(ixo^s,1)=max(max(abs(tmp2(ixo^s)), abs(tmp1(ixo^s)) ) +csoundr(ixo^s),zero)
2252 cmin(ixo^s,1)=min(min(abs(tmp2(ixo^s)), abs(tmp1(ixo^s)) ) -csoundr(ixo^s),zero)
2253 if(h_correction) then
2254 {do ix^db=ixomin^db,ixomax^db\}
2255 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2256 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2257 {end do\}
2258 end if
2259 else
2260 cmax(ixo^s,1)= max(abs(tmp2(ixo^s)),abs(tmp1(ixo^s)))+csoundr(ixo^s)
2261 end if
2262 case (3)
2263 ! Miyoshi 2005 JCP 208, 315 equation (67)
2264 call twofl_get_csound(wlp,x,ixi^l,ixo^l,idim,csoundl)
2265 call twofl_get_csound(wrp,x,ixi^l,ixo^l,idim,csoundr)
2266 csoundl(ixo^s)=max(csoundl(ixo^s),csoundr(ixo^s))
2267 if(present(cmin)) then
2268 cmin(ixo^s,1)=min(0.5*(wlp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))),&
2269 0.5*(wrp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))))-csoundl(ixo^s)
2270 cmax(ixo^s,1)=max(0.5*(wlp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))),&
2271 0.5*(wrp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))))+csoundl(ixo^s)
2272 if(h_correction) then
2273 {do ix^db=ixomin^db,ixomax^db\}
2274 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2275 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2276 {end do\}
2277 end if
2278 else
2279 cmax(ixo^s,1)=max(0.5*(wlp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))),&
2280 0.5*(wrp(ixo^s,mom_c(idim))+ wrp(ixo^s,mom_n(idim))))+csoundl(ixo^s)
2281 end if
2282 end select
2283
2284 end subroutine twofl_get_cbounds_one
2285
2286 !> Calculate fast magnetosonic wave speed
2287 subroutine twofl_get_csound_prim_c(w,x,ixI^L,ixO^L,idim,csound)
2289
2290 integer, intent(in) :: ixi^l, ixo^l, idim
2291 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2292 double precision, intent(out):: csound(ixi^s)
2293 double precision :: cfast2(ixi^s), avmincs2(ixi^s), b2(ixi^s), kmax
2294 double precision :: inv_rho(ixo^s)
2295 double precision :: rhoc(ixi^s)
2296
2297 integer :: ix1,ix2
2298
2299
2300 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
2301 inv_rho(ixo^s)=1.d0/rhoc(ixo^s)
2302
2303 if(phys_energy) then
2304 call twofl_get_pthermal_c_primitive(w,x,ixi^l,ixo^l,csound)
2305 csound(ixo^s)=twofl_gamma*csound(ixo^s)/rhoc(ixo^s)
2306 else
2307 call twofl_get_csound2_adiab_c(w,x,ixi^l,ixo^l,csound)
2308 endif
2309
2310 ! store |B|^2 in v
2311 b2(ixo^s) = twofl_mag_en_all(w,ixi^l,ixo^l)
2312 cfast2(ixo^s) = b2(ixo^s) * inv_rho(ixo^s)+csound(ixo^s)
2313 avmincs2(ixo^s) = cfast2(ixo^s)**2-4.0d0*csound(ixo^s) &
2314 * twofl_mag_i_all(w,ixi^l,ixo^l,idim)**2 &
2315 * inv_rho(ixo^s)
2316
2317 where(avmincs2(ixo^s)<zero)
2318 avmincs2(ixo^s)=zero
2319 end where
2320
2321 avmincs2(ixo^s)=sqrt(avmincs2(ixo^s))
2322
2323 if (.not. twofl_hall) then
2324 csound(ixo^s) = sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s)))
2325 else
2326 ! take the Hall velocity into account:
2327 ! most simple estimate, high k limit:
2328 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2329 kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2330 csound(ixo^s) = max(sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s))), &
2331 twofl_etah * sqrt(b2(ixo^s))*inv_rho(ixo^s)*kmax)
2332 end if
2333
2334 end subroutine twofl_get_csound_prim_c
2335
2336 !> Calculate fast magnetosonic wave speed
2337 subroutine twofl_get_csound_prim_n(w,x,ixI^L,ixO^L,idim,csound)
2339
2340 integer, intent(in) :: ixi^l, ixo^l, idim
2341 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2342 double precision, intent(out):: csound(ixi^s)
2343 double precision :: rhon(ixi^s)
2344
2345 if(phys_energy) then
2346 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2347 call twofl_get_pthermal_n_primitive(w,x,ixi^l,ixo^l,csound)
2348 csound(ixo^s)=twofl_gamma*csound(ixo^s)/rhon(ixo^s)
2349 else
2350 call twofl_get_csound2_adiab_n(w,x,ixi^l,ixo^l,csound)
2351 endif
2352 csound(ixo^s) = sqrt(csound(ixo^s))
2353
2354 end subroutine twofl_get_csound_prim_n
2355
2356 !> Estimating bounds for the minimum and maximum signal velocities
2357 subroutine twofl_get_cbounds_species(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
2360 use mod_variables
2361
2362 integer, intent(in) :: ixi^l, ixo^l, idim
2363 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s, nw)
2364 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
2365 double precision, intent(in) :: x(ixi^s,1:ndim)
2366 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
2367 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
2368 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
2369
2370 double precision :: wmean(ixi^s,nw)
2371 double precision :: rho(ixi^s)
2372 double precision, dimension(ixI^S) :: umean, dmean, csoundl, csoundr, tmp1,tmp2,tmp3
2373 integer :: ix^d
2374
2375 select case (boundspeed)
2376 case (1)
2377 ! This implements formula (10.52) from "Riemann Solvers and Numerical
2378 ! Methods for Fluid Dynamics" by Toro.
2379 ! charges
2380 call get_rhoc_tot(wlp,x,ixi^l,ixo^l,rho)
2381 tmp1(ixo^s)=sqrt(abs(rho(ixo^s)))
2382
2383 call get_rhoc_tot(wrp,x,ixi^l,ixo^l,rho)
2384 tmp2(ixo^s)=sqrt(abs(rho(ixo^s)))
2385
2386 tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
2387 umean(ixo^s)=(wlp(ixo^s,mom_c(idim))*tmp1(ixo^s)+wrp(ixo^s,mom_c(idim))*tmp2(ixo^s))*tmp3(ixo^s)
2388 call twofl_get_csound_prim_c(wlp,x,ixi^l,ixo^l,idim,csoundl)
2389 call twofl_get_csound_prim_c(wrp,x,ixi^l,ixo^l,idim,csoundr)
2390
2391
2392 dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)**2+tmp2(ixo^s)*csoundr(ixo^s)**2)*tmp3(ixo^s)+&
2393 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2*&
2394 (wrp(ixo^s,mom_c(idim)) - wlp(ixo^s,mom_c(idim)))**2
2395 dmean(ixo^s)=sqrt(dmean(ixo^s))
2396 if(present(cmin)) then
2397 cmin(ixo^s,1)=umean(ixo^s)-dmean(ixo^s)
2398 cmax(ixo^s,1)=umean(ixo^s)+dmean(ixo^s)
2399 if(h_correction) then
2400 {do ix^db=ixomin^db,ixomax^db\}
2401 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2402 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2403 {end do\}
2404 end if
2405 else
2406 cmax(ixo^s,1)=abs(umean(ixo^s))+dmean(ixo^s)
2407 end if
2408
2409 ! neutrals
2410
2411 call get_rhon_tot(wlp,x,ixi^l,ixo^l,rho)
2412 tmp1(ixo^s)=sqrt(abs(rho(ixo^s)))
2413
2414 call get_rhon_tot(wrp,x,ixi^l,ixo^l,rho)
2415 tmp2(ixo^s)=sqrt(abs(rho(ixo^s)))
2416
2417 tmp3(ixo^s)=1.d0/(tmp1(ixo^s)+tmp2(ixo^s))
2418 umean(ixo^s)=(wlp(ixo^s,mom_n(idim))*tmp1(ixo^s)+wrp(ixo^s,mom_n(idim))*tmp2(ixo^s))*tmp3(ixo^s)
2419 call twofl_get_csound_prim_n(wlp,x,ixi^l,ixo^l,idim,csoundl)
2420 call twofl_get_csound_prim_n(wrp,x,ixi^l,ixo^l,idim,csoundr)
2421
2422
2423 dmean(ixo^s)=(tmp1(ixo^s)*csoundl(ixo^s)**2+tmp2(ixo^s)*csoundr(ixo^s)**2)*tmp3(ixo^s)+&
2424 0.5d0*tmp1(ixo^s)*tmp2(ixo^s)*tmp3(ixo^s)**2*&
2425 (wrp(ixo^s,mom_n(idim)) - wlp(ixo^s,mom_n(idim)))**2
2426 dmean(ixo^s)=sqrt(dmean(ixo^s))
2427 if(present(cmin)) then
2428 cmin(ixo^s,2)=umean(ixo^s)-dmean(ixo^s)
2429 cmax(ixo^s,2)=umean(ixo^s)+dmean(ixo^s)
2430 if(h_correction) then
2431 {do ix^db=ixomin^db,ixomax^db\}
2432 cmin(ix^d,2)=sign(one,cmin(ix^d,2))*max(abs(cmin(ix^d,2)),hspeed(ix^d,2))
2433 cmax(ix^d,2)=sign(one,cmax(ix^d,2))*max(abs(cmax(ix^d,2)),hspeed(ix^d,2))
2434 {end do\}
2435 end if
2436 else
2437 cmax(ixo^s,2)=abs(umean(ixo^s))+dmean(ixo^s)
2438 end if
2439
2440 case (2)
2441 ! typeboundspeed=='cmaxmean'
2442 wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
2443 ! charges
2444 tmp1(ixo^s)=wmean(ixo^s,mom_c(idim))
2445 call twofl_get_csound_c_idim(wmean,x,ixi^l,ixo^l,idim,csoundr)
2446 if(present(cmin)) then
2447 cmax(ixo^s,1)=max(abs(tmp1(ixo^s))+csoundr(ixo^s),zero)
2448 cmin(ixo^s,1)=min(abs(tmp1(ixo^s))-csoundr(ixo^s),zero)
2449 if(h_correction) then
2450 {do ix^db=ixomin^db,ixomax^db\}
2451 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2452 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2453 {end do\}
2454 end if
2455 else
2456 cmax(ixo^s,1)=abs(tmp1(ixo^s))+csoundr(ixo^s)
2457 end if
2458 !neutrals
2459
2460 tmp1(ixo^s)=wmean(ixo^s,mom_n(idim))
2461 call twofl_get_csound_n(wmean,x,ixi^l,ixo^l,csoundr)
2462 if(present(cmin)) then
2463 cmax(ixo^s,2)=max(abs(tmp1(ixo^s))+csoundr(ixo^s),zero)
2464 cmin(ixo^s,2)=min(abs(tmp1(ixo^s))-csoundr(ixo^s),zero)
2465 if(h_correction) then
2466 {do ix^db=ixomin^db,ixomax^db\}
2467 cmin(ix^d,2)=sign(one,cmin(ix^d,2))*max(abs(cmin(ix^d,2)),hspeed(ix^d,2))
2468 cmax(ix^d,2)=sign(one,cmax(ix^d,2))*max(abs(cmax(ix^d,2)),hspeed(ix^d,2))
2469 {end do\}
2470 end if
2471 else
2472 cmax(ixo^s,2)= abs(tmp1(ixo^s))+csoundr(ixo^s)
2473 end if
2474 case (3)
2475 ! Miyoshi 2005 JCP 208, 315 equation (67)
2476 call twofl_get_csound_c_idim(wlp,x,ixi^l,ixo^l,idim,csoundl)
2477 call twofl_get_csound_c_idim(wrp,x,ixi^l,ixo^l,idim,csoundr)
2478 csoundl(ixo^s)=max(csoundl(ixo^s),csoundr(ixo^s))
2479 if(present(cmin)) then
2480 cmin(ixo^s,1)=min(wlp(ixo^s,mom_c(idim)),wrp(ixo^s,mom_c(idim)))-csoundl(ixo^s)
2481 cmax(ixo^s,1)=max(wlp(ixo^s,mom_c(idim)),wrp(ixo^s,mom_c(idim)))+csoundl(ixo^s)
2482 if(h_correction) then
2483 {do ix^db=ixomin^db,ixomax^db\}
2484 cmin(ix^d,1)=sign(one,cmin(ix^d,1))*max(abs(cmin(ix^d,1)),hspeed(ix^d,1))
2485 cmax(ix^d,1)=sign(one,cmax(ix^d,1))*max(abs(cmax(ix^d,1)),hspeed(ix^d,1))
2486 {end do\}
2487 end if
2488 else
2489 cmax(ixo^s,1)=max(wlp(ixo^s,mom_c(idim)),wrp(ixo^s,mom_c(idim)))+csoundl(ixo^s)
2490 end if
2491 call twofl_get_csound_n(wlp,x,ixi^l,ixo^l,csoundl)
2492 call twofl_get_csound_n(wrp,x,ixi^l,ixo^l,csoundr)
2493 csoundl(ixo^s)=max(csoundl(ixo^s),csoundr(ixo^s))
2494 if(present(cmin)) then
2495 cmin(ixo^s,2)=min(wlp(ixo^s,mom_n(idim)),wrp(ixo^s,mom_n(idim)))-csoundl(ixo^s)
2496 cmax(ixo^s,2)=max(wlp(ixo^s,mom_n(idim)),wrp(ixo^s,mom_n(idim)))+csoundl(ixo^s)
2497 if(h_correction) then
2498 {do ix^db=ixomin^db,ixomax^db\}
2499 cmin(ix^d,2)=sign(one,cmin(ix^d,2))*max(abs(cmin(ix^d,1)),hspeed(ix^d,2))
2500 cmax(ix^d,2)=sign(one,cmax(ix^d,2))*max(abs(cmax(ix^d,1)),hspeed(ix^d,2))
2501 {end do\}
2502 end if
2503 else
2504 cmax(ixo^s,2)=max(wlp(ixo^s,mom_n(idim)),wrp(ixo^s,mom_n(idim)))+csoundl(ixo^s)
2505 end if
2506
2507 end select
2508
2509 end subroutine twofl_get_cbounds_species
2510
2511 !> prepare velocities for ct methods
2512 subroutine twofl_get_ct_velocity_average(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
2514
2515 integer, intent(in) :: ixi^l, ixo^l, idim
2516 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
2517 double precision, intent(in) :: cmax(ixi^s)
2518 double precision, intent(in), optional :: cmin(ixi^s)
2519 type(ct_velocity), intent(inout):: vcts
2520
2521 end subroutine twofl_get_ct_velocity_average
2522
2523 subroutine twofl_get_ct_velocity_contact(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
2525
2526 integer, intent(in) :: ixi^l, ixo^l, idim
2527 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
2528 double precision, intent(in) :: cmax(ixi^s)
2529 double precision, intent(in), optional :: cmin(ixi^s)
2530 type(ct_velocity), intent(inout):: vcts
2531
2532 if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
2533 ! get average normal velocity at cell faces
2534 vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom_c(idim))+wrp(ixo^s,mom_c(idim)))
2535
2536 end subroutine twofl_get_ct_velocity_contact
2537
2538 subroutine twofl_get_ct_velocity_hll(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
2540
2541 integer, intent(in) :: ixi^l, ixo^l, idim
2542 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s, nw)
2543 double precision, intent(in) :: cmax(ixi^s)
2544 double precision, intent(in), optional :: cmin(ixi^s)
2545 type(ct_velocity), intent(inout):: vcts
2546
2547 integer :: idime,idimn
2548
2549 if(.not.allocated(vcts%vbarC)) then
2550 allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
2551 allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
2552 end if
2553 ! Store magnitude of characteristics
2554 if(present(cmin)) then
2555 vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
2556 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
2557 else
2558 vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
2559 vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
2560 end if
2561
2562 idimn=mod(idim,ndir)+1 ! 'Next' direction
2563 idime=mod(idim+1,ndir)+1 ! Electric field direction
2564 ! Store velocities
2565 vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom_c(idimn))
2566 vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom_c(idimn))
2567 vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
2568 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
2569 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
2570
2571 vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom_c(idime))
2572 vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom_c(idime))
2573 vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
2574 +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
2575 /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
2576
2577 end subroutine twofl_get_ct_velocity_hll
2578
2579 subroutine twofl_get_csound_c_idim(w,x,ixI^L,ixO^L,idim,csound)
2581
2582 integer, intent(in) :: ixi^l, ixo^l, idim
2583 ! w in primitive form
2584 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2585 double precision, intent(out):: csound(ixi^s)
2586 double precision :: cfast2(ixi^s), avmincs2(ixi^s), b2(ixi^s), kmax
2587 double precision :: inv_rho(ixo^s)
2588 double precision :: tmp(ixi^s)
2589#if (!defined(ONE_FLUID) || ONE_FLUID==0) && (defined(A_TOT) && A_TOT == 1)
2590 double precision :: rhon(ixi^s)
2591#endif
2592 call get_rhoc_tot(w,x,ixi^l,ixo^l,tmp)
2593#if (!defined(ONE_FLUID) || ONE_FLUID==0) && (defined(A_TOT) && A_TOT == 1)
2594 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2595 inv_rho(ixo^s) = 1d0/(rhon(ixo^s)+tmp(ixo^s))
2596#else
2597 inv_rho(ixo^s)=1.d0/tmp(ixo^s)
2598#endif
2599
2600 if(phys_energy) then
2601 csound(ixo^s)=twofl_gamma*w(ixo^s,e_c_)*inv_rho(ixo^s)
2602 else
2603 csound(ixo^s)=twofl_gamma*twofl_adiab*tmp(ixo^s)**gamma_1
2604 end if
2605
2606 ! store |B|^2 in v
2607 b2(ixo^s) = twofl_mag_en_all(w,ixi^l,ixo^l)
2608
2609 cfast2(ixo^s) = b2(ixo^s) * inv_rho(ixo^s)+csound(ixo^s)
2610 avmincs2(ixo^s) = cfast2(ixo^s)**2-4.0d0*csound(ixo^s) &
2611 * twofl_mag_i_all(w,ixi^l,ixo^l,idim)**2 &
2612 * inv_rho(ixo^s)
2613
2614 where(avmincs2(ixo^s)<zero)
2615 avmincs2(ixo^s)=zero
2616 end where
2617
2618 avmincs2(ixo^s)=sqrt(avmincs2(ixo^s))
2619
2620 if (.not. twofl_hall) then
2621 csound(ixo^s) = sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s)))
2622 else
2623 ! take the Hall velocity into account:
2624 ! most simple estimate, high k limit:
2625 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2626 kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2627 csound(ixo^s) = max(sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s))), &
2628 twofl_etah * sqrt(b2(ixo^s))*inv_rho(ixo^s)*kmax)
2629 end if
2630
2631 end subroutine twofl_get_csound_c_idim
2632
2633 !> Calculate fast magnetosonic wave speed when cbounds_species=false
2634 subroutine twofl_get_csound_prim(w,x,ixI^L,ixO^L,idim,csound)
2636
2637 integer, intent(in) :: ixi^l, ixo^l, idim
2638 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s,1:ndim)
2639 double precision, intent(out):: csound(ixi^s)
2640 double precision :: cfast2(ixi^s), avmincs2(ixi^s), b2(ixi^s), kmax
2641 double precision :: inv_rho(ixo^s)
2642 double precision :: rhoc(ixi^s)
2643#if (defined(A_TOT) && A_TOT == 1)
2644 double precision :: rhon(ixi^s)
2645#endif
2646 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
2647#if (defined(A_TOT) && A_TOT == 1)
2648 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2649 inv_rho(ixo^s) = 1d0/(rhon(ixo^s)+rhoc(ixo^s))
2650#else
2651 inv_rho(ixo^s)=1.d0/rhoc(ixo^s)
2652#endif
2653
2654 call twofl_get_csound2_primitive(w,x,ixi^l,ixo^l,csound)
2655
2656 ! store |B|^2 in v
2657 b2(ixo^s) = twofl_mag_en_all(w,ixi^l,ixo^l)
2658 cfast2(ixo^s) = b2(ixo^s) * inv_rho(ixo^s)+csound(ixo^s)
2659 avmincs2(ixo^s) = cfast2(ixo^s)**2-4.0d0*csound(ixo^s) &
2660 * twofl_mag_i_all(w,ixi^l,ixo^l,idim)**2 &
2661 * inv_rho(ixo^s)
2662
2663 where(avmincs2(ixo^s)<zero)
2664 avmincs2(ixo^s)=zero
2665 end where
2666
2667 avmincs2(ixo^s)=sqrt(avmincs2(ixo^s))
2668
2669 if (.not. twofl_hall) then
2670 csound(ixo^s) = sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s)))
2671 else
2672 ! take the Hall velocity into account:
2673 ! most simple estimate, high k limit:
2674 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2675 kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2676 csound(ixo^s) = max(sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s))), &
2677 twofl_etah * sqrt(b2(ixo^s))*inv_rho(ixo^s)*kmax)
2678 end if
2679
2680 contains
2681 !TODO copy it inside
2682 subroutine twofl_get_csound2_primitive(w,x,ixI^L,ixO^L,csound2)
2684 integer, intent(in) :: ixI^L, ixO^L
2685 double precision, intent(in) :: w(ixI^S,nw)
2686 double precision, intent(in) :: x(ixI^S,1:ndim)
2687 double precision, intent(out) :: csound2(ixI^S)
2688 double precision :: pth_c(ixI^S)
2689 double precision :: pth_n(ixI^S)
2690
2691 if(phys_energy) then
2692 call twofl_get_pthermal_c_primitive(w,x,ixi^l,ixo^l,pth_c)
2693 call twofl_get_pthermal_n_primitive(w,x,ixi^l,ixo^l,pth_n)
2694 call twofl_get_csound2_from_pthermal(w,x,ixi^l,ixo^l,pth_c,pth_n,csound2)
2695 else
2696 call twofl_get_csound2_adiab(w,x,ixi^l,ixo^l,csound2)
2697 endif
2698 end subroutine twofl_get_csound2_primitive
2699
2700 end subroutine twofl_get_csound_prim
2701
2702 subroutine twofl_get_csound2(w,x,ixI^L,ixO^L,csound2)
2704 integer, intent(in) :: ixI^L, ixO^L
2705 double precision, intent(in) :: w(ixI^S,nw)
2706 double precision, intent(in) :: x(ixI^S,1:ndim)
2707 double precision, intent(out) :: csound2(ixI^S)
2708 double precision :: pth_c(ixI^S)
2709 double precision :: pth_n(ixI^S)
2710
2711 if(phys_energy) then
2712 call twofl_get_pthermal_c(w,x,ixi^l,ixo^l,pth_c)
2713 call twofl_get_pthermal_n(w,x,ixi^l,ixo^l,pth_n)
2714 call twofl_get_csound2_from_pthermal(w,x,ixi^l,ixo^l,pth_c,pth_n,csound2)
2715 else
2716 call twofl_get_csound2_adiab(w,x,ixi^l,ixo^l,csound2)
2717 endif
2718 end subroutine twofl_get_csound2
2719
2720 subroutine twofl_get_csound2_adiab(w,x,ixI^L,ixO^L,csound2)
2722 integer, intent(in) :: ixI^L, ixO^L
2723 double precision, intent(in) :: w(ixI^S,nw)
2724 double precision, intent(in) :: x(ixI^S,1:ndim)
2725 double precision, intent(out) :: csound2(ixI^S)
2726 double precision :: rhoc(ixI^S)
2727 double precision :: rhon(ixI^S)
2728
2729 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
2730 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2731 csound2(ixo^s)=twofl_gamma*twofl_adiab*&
2732 max((rhoc(ixo^s)**twofl_gamma + rhon(ixo^s)**twofl_gamma)/(rhoc(ixo^s)+ rhon(ixo^s)),&
2733 rhon(ixo^s)**gamma_1,rhoc(ixo^s)**gamma_1)
2734 end subroutine twofl_get_csound2_adiab
2735
2736 subroutine twofl_get_csound(w,x,ixI^L,ixO^L,idim,csound)
2738
2739 integer, intent(in) :: ixI^L, ixO^L, idim
2740 double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2741 double precision, intent(out):: csound(ixI^S)
2742 double precision :: cfast2(ixI^S), AvMinCs2(ixI^S), b2(ixI^S), kmax
2743 double precision :: inv_rho(ixO^S)
2744 double precision :: rhoc(ixI^S)
2745#if (defined(A_TOT) && A_TOT == 1)
2746 double precision :: rhon(ixI^S)
2747#endif
2748 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
2749#if (defined(A_TOT) && A_TOT == 1)
2750 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2751 inv_rho(ixo^s) = 1d0/(rhon(ixo^s)+rhoc(ixo^s))
2752#else
2753 inv_rho(ixo^s)=1.d0/rhoc(ixo^s)
2754#endif
2755
2756 call twofl_get_csound2(w,x,ixi^l,ixo^l,csound)
2757
2758 ! store |B|^2 in v
2759 b2(ixo^s) = twofl_mag_en_all(w,ixi^l,ixo^l)
2760
2761 cfast2(ixo^s) = b2(ixo^s) * inv_rho(ixo^s)+csound(ixo^s)
2762 avmincs2(ixo^s) = cfast2(ixo^s)**2-4.0d0*csound(ixo^s) &
2763 * twofl_mag_i_all(w,ixi^l,ixo^l,idim)**2 &
2764 * inv_rho(ixo^s)
2765
2766 where(avmincs2(ixo^s)<zero)
2767 avmincs2(ixo^s)=zero
2768 end where
2769
2770 avmincs2(ixo^s)=sqrt(avmincs2(ixo^s))
2771
2772 if (.not. twofl_hall) then
2773 csound(ixo^s) = sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s)))
2774 else
2775 ! take the Hall velocity into account:
2776 ! most simple estimate, high k limit:
2777 ! largest wavenumber supported by grid: Nyquist (in practise can reduce by some factor)
2778 kmax = dpi/min({dxlevel(^d)},bigdouble)*half
2779 csound(ixo^s) = max(sqrt(half*(cfast2(ixo^s)+avmincs2(ixo^s))), &
2780 twofl_etah * sqrt(b2(ixo^s))*inv_rho(ixo^s)*kmax)
2781 end if
2782
2783 end subroutine twofl_get_csound
2784
2785 subroutine twofl_get_csound2_from_pthermal(w,x,ixI^L,ixO^L,pth_c,pth_n,csound2)
2787 integer, intent(in) :: ixI^L, ixO^L
2788 double precision, intent(in) :: w(ixI^S,nw)
2789 double precision, intent(in) :: x(ixI^S,1:ndim)
2790 double precision, intent(in) :: pth_c(ixI^S)
2791 double precision, intent(in) :: pth_n(ixI^S)
2792 double precision, intent(out) :: csound2(ixI^S)
2793 double precision :: csound1(ixI^S),rhon(ixI^S),rhoc(ixI^S)
2794
2795 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
2796 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
2797#if !defined(C_TOT) || C_TOT == 0
2798 csound2(ixo^s)=twofl_gamma*max((pth_c(ixo^s) + pth_n(ixo^s))/(rhoc(ixo^s) + rhon(ixo^s)),&
2799 pth_n(ixo^s)/rhon(ixo^s), pth_c(ixo^s)/rhoc(ixo^s))
2800#else
2801 csound2(ixo^s)=twofl_gamma*(csound2(ixo^s) + csound1(ixo^s))/(rhoc(ixo^s) + rhon(ixo^s))
2802
2803#endif
2804 end subroutine twofl_get_csound2_from_pthermal
2805
2806! end cbounds_species=false
2807
2808 subroutine twofl_get_csound_n(w,x,ixI^L,ixO^L,csound)
2810
2811 integer, intent(in) :: ixI^L, ixO^L
2812 double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
2813 double precision, intent(out):: csound(ixI^S)
2814 double precision :: pe_n1(ixI^S)
2815 call twofl_get_csound2_n_from_conserved(w,x,ixi^l,ixo^l,csound)
2816 csound(ixo^s) = sqrt(csound(ixo^s))
2817 end subroutine twofl_get_csound_n
2818
2819 !> separate routines so that it is faster
2820 !> Calculate temperature=p/rho when in e_ the internal energy is stored
2821 subroutine twofl_get_temperature_from_eint_n(w, x, ixI^L, ixO^L, res)
2823 integer, intent(in) :: ixI^L, ixO^L
2824 double precision, intent(in) :: w(ixI^S, 1:nw)
2825 double precision, intent(in) :: x(ixI^S, 1:ndim)
2826 double precision, intent(out):: res(ixI^S)
2827
2828 res(ixo^s) = 1d0/rn * gamma_1 * w(ixo^s, e_n_) /w(ixo^s,rho_n_)
2829
2830 end subroutine twofl_get_temperature_from_eint_n
2831
2832 subroutine twofl_get_temperature_from_eint_n_with_equi(w, x, ixI^L, ixO^L, res)
2834 integer, intent(in) :: ixI^L, ixO^L
2835 double precision, intent(in) :: w(ixI^S, 1:nw)
2836 double precision, intent(in) :: x(ixI^S, 1:ndim)
2837 double precision, intent(out):: res(ixI^S)
2838
2839 res(ixo^s) = 1d0/rn * (gamma_1 * w(ixo^s, e_n_) + block%equi_vars(ixo^s,equi_pe_n0_,b0i)) /&
2840 (w(ixo^s,rho_n_) +block%equi_vars(ixo^s,equi_rho_n0_,b0i))
2841 end subroutine twofl_get_temperature_from_eint_n_with_equi
2842
2843! subroutine twofl_get_temperature_n_pert_from_tot(Te, ixI^L, ixO^L, res)
2844! use mod_global_parameters
2845! integer, intent(in) :: ixI^L, ixO^L
2846! double precision, intent(in) :: Te(ixI^S)
2847! double precision, intent(out):: res(ixI^S)
2848! res(ixO^S) = Te(ixO^S) -1d0/Rn * &
2849! block%equi_vars(ixO^S,equi_pe_n0_,0)/block%equi_vars(ixO^S,equi_rho_n0_,0)
2850! end subroutine twofl_get_temperature_n_pert_from_tot
2851
2852 subroutine twofl_get_temperature_n_equi(w,x, ixI^L, ixO^L, res)
2854 integer, intent(in) :: ixI^L, ixO^L
2855 double precision, intent(in) :: w(ixI^S, 1:nw)
2856 double precision, intent(in) :: x(ixI^S, 1:ndim)
2857 double precision, intent(out):: res(ixI^S)
2858 res(ixo^s) = 1d0/rn * &
2859 block%equi_vars(ixo^s,equi_pe_n0_,b0i)/block%equi_vars(ixo^s,equi_rho_n0_,b0i)
2860 end subroutine twofl_get_temperature_n_equi
2861
2862 subroutine twofl_get_rho_n_equi(w, x,ixI^L, ixO^L, res)
2864 integer, intent(in) :: ixI^L, ixO^L
2865 double precision, intent(in) :: w(ixI^S, 1:nw)
2866 double precision, intent(in) :: x(ixI^S, 1:ndim)
2867 double precision, intent(out):: res(ixI^S)
2868 res(ixo^s) = block%equi_vars(ixo^s,equi_rho_n0_,b0i)
2869 end subroutine twofl_get_rho_n_equi
2870
2871 subroutine twofl_get_pe_n_equi(w, x, ixI^L, ixO^L, res)
2873 integer, intent(in) :: ixI^L, ixO^L
2874 double precision, intent(in) :: w(ixI^S, 1:nw)
2875 double precision, intent(in) :: x(ixI^S, 1:ndim)
2876 double precision, intent(out):: res(ixI^S)
2877 res(ixo^s) = block%equi_vars(ixo^s,equi_pe_n0_,b0i)
2878 end subroutine twofl_get_pe_n_equi
2879
2880 !> Calculate temperature=p/rho when in e_ the total energy is stored
2881 !> this does not check the values of twofl_energy and twofl_internal_e,
2882 !> twofl_energy = .true. and twofl_internal_e = .false.
2883 !> also check small_values is avoided
2884 subroutine twofl_get_temperature_from_etot_n(w, x, ixI^L, ixO^L, res)
2886 integer, intent(in) :: ixI^L, ixO^L
2887 double precision, intent(in) :: w(ixI^S, 1:nw)
2888 double precision, intent(in) :: x(ixI^S, 1:ndim)
2889 double precision, intent(out):: res(ixI^S)
2890 res(ixo^s)=1d0/rn * (gamma_1*(w(ixo^s,e_n_)&
2891 - twofl_kin_en_n(w,ixi^l,ixo^l)))/w(ixo^s,rho_n_)
2892 end subroutine twofl_get_temperature_from_etot_n
2893
2894 subroutine twofl_get_temperature_from_etot_n_with_equi(w, x, ixI^L, ixO^L, res)
2896 integer, intent(in) :: ixI^L, ixO^L
2897 double precision, intent(in) :: w(ixI^S, 1:nw)
2898 double precision, intent(in) :: x(ixI^S, 1:ndim)
2899 double precision, intent(out):: res(ixI^S)
2900 res(ixo^s)=1d0/rn * (gamma_1*(w(ixo^s,e_n_)&
2901 - twofl_kin_en_n(w,ixi^l,ixo^l)) + block%equi_vars(ixo^s,equi_pe_n0_,b0i))&
2902 /(w(ixo^s,rho_n_) +block%equi_vars(ixo^s,equi_rho_n0_,b0i))
2903
2904 end subroutine twofl_get_temperature_from_etot_n_with_equi
2905
2906 !> separate routines so that it is faster
2907 !> Calculate temperature=p/rho when in e_ the internal energy is stored
2908 subroutine twofl_get_temperature_from_eint_c(w, x, ixI^L, ixO^L, res)
2910 integer, intent(in) :: ixI^L, ixO^L
2911 double precision, intent(in) :: w(ixI^S, 1:nw)
2912 double precision, intent(in) :: x(ixI^S, 1:ndim)
2913 double precision, intent(out):: res(ixI^S)
2914
2915 res(ixo^s) = 1d0/rc * gamma_1 * w(ixo^s, e_c_) /w(ixo^s,rho_c_)
2916
2917 end subroutine twofl_get_temperature_from_eint_c
2918
2919 subroutine twofl_get_temperature_from_eint_c_with_equi(w, x, ixI^L, ixO^L, res)
2921 integer, intent(in) :: ixI^L, ixO^L
2922 double precision, intent(in) :: w(ixI^S, 1:nw)
2923 double precision, intent(in) :: x(ixI^S, 1:ndim)
2924 double precision, intent(out):: res(ixI^S)
2925 res(ixo^s) = 1d0/rc * (gamma_1 * w(ixo^s, e_c_) + block%equi_vars(ixo^s,equi_pe_c0_,b0i)) /&
2926 (w(ixo^s,rho_c_) +block%equi_vars(ixo^s,equi_rho_c0_,b0i))
2927 end subroutine twofl_get_temperature_from_eint_c_with_equi
2928
2929! subroutine twofl_get_temperature_c_pert_from_tot(Te, ixI^L, ixO^L, res)
2930! use mod_global_parameters
2931! integer, intent(in) :: ixI^L, ixO^L
2932! double precision, intent(in) :: Te(ixI^S)
2933! double precision, intent(out):: res(ixI^S)
2934! res(ixO^S) = Te(ixO^S) -1d0/Rc * &
2935! block%equi_vars(ixO^S,equi_pe_c0_,0)/block%equi_vars(ixO^S,equi_rho_c0_,0)
2936! end subroutine twofl_get_temperature_c_pert_from_tot
2937
2938 subroutine twofl_get_temperature_c_equi(w,x, ixI^L, ixO^L, res)
2940 integer, intent(in) :: ixI^L, ixO^L
2941 double precision, intent(in) :: w(ixI^S, 1:nw)
2942 double precision, intent(in) :: x(ixI^S, 1:ndim)
2943 double precision, intent(out):: res(ixI^S)
2944 res(ixo^s) = 1d0/rc * &
2945 block%equi_vars(ixo^s,equi_pe_c0_,b0i)/block%equi_vars(ixo^s,equi_rho_c0_,b0i)
2946 end subroutine twofl_get_temperature_c_equi
2947
2948 subroutine twofl_get_rho_c_equi(w, x, ixI^L, ixO^L, res)
2950 integer, intent(in) :: ixI^L, ixO^L
2951 double precision, intent(in) :: w(ixI^S, 1:nw)
2952 double precision, intent(in) :: x(ixI^S, 1:ndim)
2953 double precision, intent(out):: res(ixI^S)
2954 res(ixo^s) = block%equi_vars(ixo^s,equi_rho_c0_,b0i)
2955 end subroutine twofl_get_rho_c_equi
2956
2957 subroutine twofl_get_pe_c_equi(w,x, ixI^L, ixO^L, res)
2959 integer, intent(in) :: ixI^L, ixO^L
2960 double precision, intent(in) :: w(ixI^S, 1:nw)
2961 double precision, intent(in) :: x(ixI^S, 1:ndim)
2962 double precision, intent(out):: res(ixI^S)
2963 res(ixo^s) = block%equi_vars(ixo^s,equi_pe_c0_,b0i)
2964 end subroutine twofl_get_pe_c_equi
2965
2966 !> Calculate temperature=p/rho when in e_ the total energy is stored
2967 !> this does not check the values of twofl_energy and twofl_internal_e,
2968 !> twofl_energy = .true. and twofl_internal_e = .false.
2969 !> also check small_values is avoided
2970 subroutine twofl_get_temperature_from_etot_c(w, x, ixI^L, ixO^L, res)
2972 integer, intent(in) :: ixI^L, ixO^L
2973 double precision, intent(in) :: w(ixI^S, 1:nw)
2974 double precision, intent(in) :: x(ixI^S, 1:ndim)
2975 double precision, intent(out):: res(ixI^S)
2976 res(ixo^s)=1d0/rc * (gamma_1*(w(ixo^s,e_c_)&
2977 - twofl_kin_en_c(w,ixi^l,ixo^l)&
2978 - twofl_mag_en(w,ixi^l,ixo^l)))/w(ixo^s,rho_c_)
2979 end subroutine twofl_get_temperature_from_etot_c
2980 subroutine twofl_get_temperature_from_eki_c(w, x, ixI^L, ixO^L, res)
2982 integer, intent(in) :: ixI^L, ixO^L
2983 double precision, intent(in) :: w(ixI^S, 1:nw)
2984 double precision, intent(in) :: x(ixI^S, 1:ndim)
2985 double precision, intent(out):: res(ixI^S)
2986 res(ixo^s)=1d0/rc * (gamma_1*(w(ixo^s,e_c_)&
2987 - twofl_kin_en_c(w,ixi^l,ixo^l)))/w(ixo^s,rho_c_)
2988 end subroutine twofl_get_temperature_from_eki_c
2989
2990 subroutine twofl_get_temperature_from_etot_c_with_equi(w, x, ixI^L, ixO^L, res)
2992 integer, intent(in) :: ixI^L, ixO^L
2993 double precision, intent(in) :: w(ixI^S, 1:nw)
2994 double precision, intent(in) :: x(ixI^S, 1:ndim)
2995 double precision, intent(out):: res(ixI^S)
2996 res(ixo^s)=1d0/rc * (gamma_1*(w(ixo^s,e_c_)&
2997 - twofl_kin_en_c(w,ixi^l,ixo^l)&
2998 - twofl_mag_en(w,ixi^l,ixo^l)) + block%equi_vars(ixo^s,equi_pe_c0_,b0i))&
2999 /(w(ixo^s,rho_c_) +block%equi_vars(ixo^s,equi_rho_c0_,b0i))
3000
3001 end subroutine twofl_get_temperature_from_etot_c_with_equi
3002
3003 subroutine twofl_get_temperature_from_eki_c_with_equi(w, x, ixI^L, ixO^L, res)
3005 integer, intent(in) :: ixI^L, ixO^L
3006 double precision, intent(in) :: w(ixI^S, 1:nw)
3007 double precision, intent(in) :: x(ixI^S, 1:ndim)
3008 double precision, intent(out):: res(ixI^S)
3009 res(ixo^s)=1d0/rc * (gamma_1*(w(ixo^s,e_c_)&
3010 - twofl_kin_en_c(w,ixi^l,ixo^l)) + block%equi_vars(ixo^s,equi_pe_c0_,b0i))&
3011 /(w(ixo^s,rho_c_) +block%equi_vars(ixo^s,equi_rho_c0_,b0i))
3012
3013 end subroutine twofl_get_temperature_from_eki_c_with_equi
3014
3015 subroutine twofl_get_csound2_adiab_n(w,x,ixI^L,ixO^L,csound2)
3017 integer, intent(in) :: ixI^L, ixO^L
3018 double precision, intent(in) :: w(ixI^S,nw)
3019 double precision, intent(in) :: x(ixI^S,1:ndim)
3020 double precision, intent(out) :: csound2(ixI^S)
3021 double precision :: rhon(ixI^S)
3022
3023 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3024 csound2(ixo^s)=twofl_gamma*twofl_adiab*rhon(ixo^s)**gamma_1
3025
3026 end subroutine twofl_get_csound2_adiab_n
3027
3028 subroutine twofl_get_csound2_n_from_conserved(w,x,ixI^L,ixO^L,csound2)
3030 integer, intent(in) :: ixI^L, ixO^L
3031 double precision, intent(in) :: w(ixI^S,nw)
3032 double precision, intent(in) :: x(ixI^S,1:ndim)
3033 double precision, intent(out) :: csound2(ixI^S)
3034 double precision :: rhon(ixI^S)
3035
3036 if(phys_energy) then
3037 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3038 call twofl_get_pthermal_n(w,x,ixi^l,ixo^l,csound2)
3039 csound2(ixo^s)=twofl_gamma*csound2(ixo^s)/rhon(ixo^s)
3040 else
3041 call twofl_get_csound2_adiab_n(w,x,ixi^l,ixo^l,csound2)
3042 endif
3043 end subroutine twofl_get_csound2_n_from_conserved
3044
3045 !! TO DELETE
3046 subroutine twofl_get_csound2_n_from_primitive(w,x,ixI^L,ixO^L,csound2)
3048 integer, intent(in) :: ixI^L, ixO^L
3049 double precision, intent(in) :: w(ixI^S,nw)
3050 double precision, intent(in) :: x(ixI^S,1:ndim)
3051 double precision, intent(out) :: csound2(ixI^S)
3052 double precision :: rhon(ixI^S)
3053
3054 if(phys_energy) then
3055 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3056 call twofl_get_pthermal_n_primitive(w,x,ixi^l,ixo^l,csound2)
3057 csound2(ixo^s)=twofl_gamma*csound2(ixo^s)/rhon(ixo^s)
3058 else
3059 call twofl_get_csound2_adiab_n(w,x,ixi^l,ixo^l,csound2)
3060 endif
3061 end subroutine twofl_get_csound2_n_from_primitive
3062
3063 subroutine twofl_get_csound2_adiab_c(w,x,ixI^L,ixO^L,csound2)
3065 integer, intent(in) :: ixI^L, ixO^L
3066 double precision, intent(in) :: w(ixI^S,nw)
3067 double precision, intent(in) :: x(ixI^S,1:ndim)
3068 double precision, intent(out) :: csound2(ixI^S)
3069 double precision :: rhoc(ixI^S)
3070
3071 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3072 csound2(ixo^s)=twofl_gamma*twofl_adiab* rhoc(ixo^s)**gamma_1
3073
3074 end subroutine twofl_get_csound2_adiab_c
3075
3076 subroutine twofl_get_csound2_c_from_conserved(w,x,ixI^L,ixO^L,csound2)
3078 integer, intent(in) :: ixi^l, ixo^l
3079 double precision, intent(in) :: w(ixi^s,nw)
3080 double precision, intent(in) :: x(ixi^s,1:ndim)
3081 double precision, intent(out) :: csound2(ixi^s)
3082 double precision :: rhoc(ixi^s)
3083
3084 if(phys_energy) then
3085 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3086 call twofl_get_pthermal_c(w,x,ixi^l,ixo^l,csound2)
3087 csound2(ixo^s)=twofl_gamma*csound2(ixo^s)/rhoc(ixo^s)
3088 else
3089 call twofl_get_csound2_adiab_c(w,x,ixi^l,ixo^l,csound2)
3090 endif
3092
3093 !> Calculate fluxes within ixO^L.
3094 subroutine twofl_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
3096 use mod_geometry
3097
3098 integer, intent(in) :: ixi^l, ixo^l, idim
3099 ! conservative w
3100 double precision, intent(in) :: wc(ixi^s,nw)
3101 ! primitive w
3102 double precision, intent(in) :: w(ixi^s,nw)
3103 double precision, intent(in) :: x(ixi^s,1:ndim)
3104 double precision,intent(out) :: f(ixi^s,nwflux)
3105
3106 double precision :: pgas(ixo^s), ptotal(ixo^s),tmp(ixi^s)
3107 double precision, allocatable:: vhall(:^d&,:)
3108 integer :: idirmin, iw, idir, jdir, kdir
3109
3110 ! value at the interfaces, idim = block%iw0 --> b0i
3111 ! reuse tmp, used afterwards
3112 ! value at the interface so we can't put momentum
3113 call get_rhoc_tot(w,x,ixi^l,ixo^l,tmp)
3114 ! Get flux of density
3115 f(ixo^s,rho_c_)=w(ixo^s,mom_c(idim))*tmp(ixo^s)
3116 ! pgas is time dependent only
3117 if(phys_energy) then
3118 pgas(ixo^s)=w(ixo^s,e_c_)
3119 else
3120 pgas(ixo^s)=twofl_adiab*tmp(ixo^s)**twofl_gamma
3121 if(has_equi_pe_c0) then
3122 pgas(ixo^s)=pgas(ixo^s)-block%equi_vars(ixo^s,equi_pe_c0_,b0i)
3123 end if
3124 end if
3125
3126 if (twofl_hall) then
3127 allocate(vhall(ixi^s,1:ndir))
3128 call twofl_getv_hall(w,x,ixi^l,ixo^l,vhall)
3129 end if
3130
3131 if(b0field) tmp(ixo^s)=sum(block%B0(ixo^s,:,idim)*w(ixo^s,mag(:)),dim=ndim+1)
3132
3133 ptotal(ixo^s) = pgas(ixo^s) + 0.5d0*sum(w(ixo^s, mag(:))**2, dim=ndim+1)
3134
3135 ! Get flux of momentum
3136 ! f_i[m_k]=v_i*m_k-b_k*b_i [+ptotal if i==k]
3137 do idir=1,ndir
3138 if(idim==idir) then
3139 f(ixo^s,mom_c(idir))=ptotal(ixo^s)-w(ixo^s,mag(idim))*w(ixo^s,mag(idir))
3140 if(b0field) f(ixo^s,mom_c(idir))=f(ixo^s,mom_c(idir))+tmp(ixo^s)
3141 else
3142 f(ixo^s,mom_c(idir))= -w(ixo^s,mag(idir))*w(ixo^s,mag(idim))
3143 end if
3144 if (b0field) then
3145 f(ixo^s,mom_c(idir))=f(ixo^s,mom_c(idir))&
3146 -w(ixo^s,mag(idir))*block%B0(ixo^s,idim,idim)&
3147 -w(ixo^s,mag(idim))*block%B0(ixo^s,idir,idim)
3148 end if
3149 f(ixo^s,mom_c(idir))=f(ixo^s,mom_c(idir))+w(ixo^s,mom_c(idim))*wc(ixo^s,mom_c(idir))
3150 end do
3151
3152 ! Get flux of energy
3153 ! f_i[e]=v_i*e+v_i*ptotal-b_i*(b_k*v_k)
3154 if(phys_energy) then
3155 if (phys_internal_e) then
3156 f(ixo^s,e_c_)=w(ixo^s,mom_c(idim))*wc(ixo^s,e_c_)
3157 else if(twofl_eq_energy == eq_energy_ki) then
3158
3159 f(ixo^s,e_c_)=w(ixo^s,mom_c(idim))*(wc(ixo^s,e_c_)+pgas(ixo^s))
3160 else
3161 f(ixo^s,e_c_)=w(ixo^s,mom_c(idim))*(wc(ixo^s,e_c_)+ptotal(ixo^s))&
3162 -w(ixo^s,mag(idim))*sum(w(ixo^s,mag(:))*w(ixo^s,mom_c(:)),dim=ndim+1)
3163
3164 if (b0field) then
3165 f(ixo^s,e_c_) = f(ixo^s,e_c_) &
3166 + w(ixo^s,mom_c(idim)) * tmp(ixo^s) &
3167 - sum(w(ixo^s,mom_c(:))*w(ixo^s,mag(:)),dim=ndim+1) * block%B0(ixo^s,idim,idim)
3168 end if
3169
3170 if (twofl_hall) then
3171 ! f_i[e]= f_i[e] + vHall_i*(b_k*b_k) - b_i*(vHall_k*b_k)
3172 if (twofl_etah>zero) then
3173 f(ixo^s,e_c_) = f(ixo^s,e_c_) + vhall(ixo^s,idim) * &
3174 sum(w(ixo^s, mag(:))**2,dim=ndim+1) &
3175 - w(ixo^s,mag(idim)) * sum(vhall(ixo^s,:)*w(ixo^s,mag(:)),dim=ndim+1)
3176 if (b0field) then
3177 f(ixo^s,e_c_) = f(ixo^s,e_c_) &
3178 + vhall(ixo^s,idim) * tmp(ixo^s) &
3179 - sum(vhall(ixo^s,:)*w(ixo^s,mag(:)),dim=ndim+1) * block%B0(ixo^s,idim,idim)
3180 end if
3181 end if
3182 end if
3183 end if !total_energy
3184 ! add flux of equilibrium internal energy corresponding to pe_c0
3185 if(has_equi_pe_c0) then
3186#if !defined(E_RM_W0) || E_RM_W0 == 1
3187 f(ixo^s,e_c_)= f(ixo^s,e_c_) &
3188 + w(ixo^s,mom_c(idim)) * block%equi_vars(ixo^s,equi_pe_c0_,idim) * inv_gamma_1
3189#else
3190 if(phys_internal_e) then
3191 f(ixo^s,e_c_)= f(ixo^s,e_c_) &
3192 + w(ixo^s,mom_c(idim)) * block%equi_vars(ixo^s,equi_pe_c0_,idim) * inv_gamma_1
3193 else
3194 f(ixo^s,e_c_)= f(ixo^s,e_c_) &
3195 + w(ixo^s,mom_c(idim)) * block%equi_vars(ixo^s,equi_pe_c0_,idim) * twofl_gamma * inv_gamma_1
3196 end if
3197#endif
3198 end if
3199 end if !phys_energy
3200
3201 ! compute flux of magnetic field
3202 ! f_i[b_k]=v_i*b_k-v_k*b_i
3203 do idir=1,ndir
3204 if (idim==idir) then
3205 ! f_i[b_i] should be exactly 0, so we do not use the transport flux
3206 if (twofl_glm) then
3207 f(ixo^s,mag(idir))=w(ixo^s,psi_)
3208 else
3209 f(ixo^s,mag(idir))=zero
3210 end if
3211 else
3212 f(ixo^s,mag(idir))=w(ixo^s,mom_c(idim))*w(ixo^s,mag(idir))-w(ixo^s,mag(idim))*w(ixo^s,mom_c(idir))
3213
3214 if (b0field) then
3215 f(ixo^s,mag(idir))=f(ixo^s,mag(idir))&
3216 +w(ixo^s,mom_c(idim))*block%B0(ixo^s,idir,idim)&
3217 -w(ixo^s,mom_c(idir))*block%B0(ixo^s,idim,idim)
3218 end if
3219
3220 if (twofl_hall) then
3221 ! f_i[b_k] = f_i[b_k] + vHall_i*b_k - vHall_k*b_i
3222 if (twofl_etah>zero) then
3223 if (b0field) then
3224 f(ixo^s,mag(idir)) = f(ixo^s,mag(idir)) &
3225 - vhall(ixo^s,idir)*(w(ixo^s,mag(idim))+block%B0(ixo^s,idim,idim)) &
3226 + vhall(ixo^s,idim)*(w(ixo^s,mag(idir))+block%B0(ixo^s,idir,idim))
3227 else
3228 f(ixo^s,mag(idir)) = f(ixo^s,mag(idir)) &
3229 - vhall(ixo^s,idir)*w(ixo^s,mag(idim)) &
3230 + vhall(ixo^s,idim)*w(ixo^s,mag(idir))
3231 end if
3232 end if
3233 end if
3234
3235 end if
3236 end do
3237
3238 if (twofl_glm) then
3239 !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
3240 f(ixo^s,psi_) = cmax_global**2*w(ixo^s,mag(idim))
3241 end if
3242
3243 if (twofl_hall) then
3244 deallocate(vhall)
3245 end if
3246
3247 !!neutrals
3248 call get_rhon_tot(w,x,ixi^l,ixo^l,tmp)
3249 f(ixo^s,rho_n_)=w(ixo^s,mom_n(idim))*tmp(ixo^s)
3250 if(phys_energy) then
3251 pgas(ixo^s) = w(ixo^s, e_n_)
3252 else
3253 pgas(ixo^s)=twofl_adiab*tmp(ixo^s)**twofl_gamma
3254 if(has_equi_pe_n0) then
3255 pgas(ixo^s)=pgas(ixo^s)-block%equi_vars(ixo^s,equi_pe_n0_,b0i)
3256 end if
3257 end if
3258 ! Momentum flux is v_i*m_i, +p in direction idim
3259 do idir = 1, ndir
3260 !if(idim==idir) then
3261 ! f(ixO^S,mom_c(idir)) = pgas(ixO^S)
3262 !else
3263 ! f(ixO^S,mom_c(idir)) = 0.0d0
3264 !end if
3265 !f(ixO^S,mom_c(idir))=f(ixO^S,mom_c(idir))+w(ixO^S,mom_c(idim))*wC(ixO^S,mom_c(idir))
3266 f(ixo^s, mom_n(idir)) = w(ixo^s,mom_n(idim)) * wc(ixo^s, mom_n(idir))
3267 end do
3268
3269 f(ixo^s, mom_n(idim)) = f(ixo^s, mom_n(idim)) + pgas(ixo^s)
3270
3271 if(phys_energy) then
3272 !reuse pgas for storing a in the term: div (u_n * a) and make multiplication at the end
3273 pgas(ixo^s) = wc(ixo^s,e_n_)
3274 if(.not. phys_internal_e) then
3275 ! add pressure perturbation
3276 pgas(ixo^s) = pgas(ixo^s) + w(ixo^s,e_n_)
3277 end if
3278 ! add flux of equilibrium internal energy corresponding to pe_n0
3279 if(has_equi_pe_n0) then
3280#if !defined(E_RM_W0) || E_RM_W0 == 1
3281 pgas(ixo^s) = pgas(ixo^s) + block%equi_vars(ixo^s,equi_pe_n0_,idim) * inv_gamma_1
3282#else
3283 pgas(ixo^s) = pgas(ixo^s) + block%equi_vars(ixo^s,equi_pe_n0_,idim) * twofl_gamma * inv_gamma_1
3284#endif
3285 end if
3286 ! add u_n * a in the flux
3287 f(ixo^s, e_n_) = w(ixo^s,mom_n(idim)) * pgas(ixo^s)
3288 end if
3289
3290 end subroutine twofl_get_flux
3291
3292 !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
3293 subroutine twofl_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
3297 !use mod_gravity, only: gravity_add_source
3298
3299 integer, intent(in) :: ixi^l, ixo^l
3300 double precision, intent(in) :: qdt,dtfactor
3301 double precision, intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw),x(ixi^s,1:ndim)
3302 double precision, intent(inout) :: w(ixi^s,1:nw)
3303 logical, intent(in) :: qsourcesplit
3304 logical, intent(inout) :: active
3305
3306 if (.not. qsourcesplit) then
3307 ! Source for solving internal energy
3308 if(phys_internal_e) then
3309 active = .true.
3310 call internal_energy_add_source_n(qdt,ixi^l,ixo^l,wct,w,x)
3311 call internal_energy_add_source_c(qdt,ixi^l,ixo^l,wct,w,x,e_c_)
3312 else
3313#if !defined(E_RM_W0) || E_RM_W0==1
3314 ! add -p0 div v source terms when equi are present
3315 if(has_equi_pe_n0) then
3316 active = .true.
3317 call add_pe_n0_divv(qdt,ixi^l,ixo^l,wct,w,x)
3318 endif
3319 if(has_equi_pe_c0) then
3320 active = .true.
3321 call add_pe_c0_divv(qdt,ixi^l,ixo^l,wct,w,x)
3322 endif
3323#endif
3324 if(twofl_eq_energy == eq_energy_ki) then
3325 active = .true.
3326 call add_source_lorentz_work(qdt,ixi^l,ixo^l,w,wct,x)
3327 endif
3328 endif
3329
3330 ! Source for B0 splitting
3331 if (b0field) then
3332 active = .true.
3333 call add_source_b0split(qdt,ixi^l,ixo^l,wct,w,x)
3334 end if
3335
3336 ! Sources for resistivity in eqs. for e, B1, B2 and B3
3337 if (abs(twofl_eta)>smalldouble)then
3338 active = .true.
3339 call add_source_res2(qdt,ixi^l,ixo^l,wct,w,x)
3340 end if
3341
3342 if (twofl_eta_hyper>0.d0)then
3343 active = .true.
3344 call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
3345 end if
3346 !it is not added in a split manner
3347 if(.not. use_imex_scheme .and. has_collisions()) then
3348 active = .true.
3349 call twofl_explicit_coll_terms_update(qdt,ixi^l,ixo^l,w,wct,x)
3350 endif
3351
3352 if(twofl_hyperdiffusivity) then
3353 active = .true.
3354 call add_source_hyperdiffusive(qdt,ixi^l,ixo^l,w,wct,x)
3355 endif
3356
3357 end if
3358
3359 {^nooned
3360 if(source_split_divb .eqv. qsourcesplit) then
3361 ! Sources related to div B
3362 select case (type_divb)
3363 case (divb_none)
3364 ! Do nothing
3365 case (divb_glm)
3366 active = .true.
3367 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
3368 case (divb_powel)
3369 active = .true.
3370 call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
3371 case (divb_janhunen)
3372 active = .true.
3373 call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
3374 case (divb_linde)
3375 active = .true.
3376 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
3377 case (divb_lindejanhunen)
3378 active = .true.
3379 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
3380 call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
3381 case (divb_lindepowel)
3382 active = .true.
3383 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
3384 call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
3385 case (divb_lindeglm)
3386 active = .true.
3387 call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
3388 call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
3389 case (divb_ct)
3390 continue ! Do nothing
3391 case (divb_multigrid)
3392 continue ! Do nothing
3393 case default
3394 call mpistop('Unknown divB fix')
3395 end select
3396 end if
3397 }
3398
3400 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
3401 w,x,qsourcesplit,active,rc_fl_c)
3402 end if
3404 call radiative_cooling_add_source(qdt,ixi^l,ixo^l,wct,wctprim,&
3405 w,x,qsourcesplit,active,rc_fl_n)
3406 end if
3407!
3408! if(twofl_viscosity) then
3409! call viscosity_add_source(qdt,ixI^L,ixO^L,wCT,wCTprim,&
3410! w,x,phys_energy,qsourcesplit,active)
3411! end if
3412!
3413 if(twofl_gravity) then
3414 call gravity_add_source(qdt,ixi^l,ixo^l,wct,&
3415 w,x,twofl_eq_energy .eq. eq_energy_ki .or. phys_total_energy,qsourcesplit,active)
3416 end if
3417
3418 end subroutine twofl_add_source
3419
3420 subroutine add_pe_n0_divv(qdt,ixI^L,ixO^L,wCT,w,x)
3422 use mod_geometry
3423
3424 integer, intent(in) :: ixi^l, ixo^l
3425 double precision, intent(in) :: qdt
3426 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3427 double precision, intent(inout) :: w(ixi^s,1:nw)
3428 double precision :: v(ixi^s,1:ndir)
3429
3430 call twofl_get_v_n(wct,x,ixi^l,ixi^l,v)
3431 call add_geom_pdivv(qdt,ixi^l,ixo^l,v,-block%equi_vars(ixi^s,equi_pe_n0_,0),w,x,e_n_)
3432
3433 end subroutine add_pe_n0_divv
3434
3435 subroutine add_pe_c0_divv(qdt,ixI^L,ixO^L,wCT,w,x)
3437 use mod_geometry
3438
3439 integer, intent(in) :: ixi^l, ixo^l
3440 double precision, intent(in) :: qdt
3441 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3442 double precision, intent(inout) :: w(ixi^s,1:nw)
3443 double precision :: v(ixi^s,1:ndir)
3444
3445 call twofl_get_v_c(wct,x,ixi^l,ixi^l,v)
3446 call add_geom_pdivv(qdt,ixi^l,ixo^l,v,-block%equi_vars(ixi^s,equi_pe_c0_,0),w,x,e_c_)
3447
3448 end subroutine add_pe_c0_divv
3449
3450 subroutine add_geom_pdivv(qdt,ixI^L,ixO^L,v,p,w,x,ind)
3452 use mod_geometry
3453 integer, intent(in) :: ixi^l, ixo^l,ind
3454 double precision, intent(in) :: qdt
3455 double precision, intent(in) :: p(ixi^s), v(ixi^s,1:ndir), x(ixi^s,1:ndim)
3456 double precision, intent(inout) :: w(ixi^s,1:nw)
3457 double precision :: divv(ixi^s)
3458
3459 if(slab_uniform) then
3460 if(nghostcells .gt. 2) then
3461 call divvector(v,ixi^l,ixo^l,divv,3)
3462 else
3463 call divvector(v,ixi^l,ixo^l,divv,2)
3464 end if
3465 else
3466 call divvector(v,ixi^l,ixo^l,divv)
3467 end if
3468 w(ixo^s,ind)=w(ixo^s,ind)+qdt*p(ixo^s)*divv(ixo^s)
3469 end subroutine add_geom_pdivv
3470
3471 !> Compute the Lorentz force (JxB)
3472 subroutine get_lorentz(ixI^L,ixO^L,w,JxB)
3474 integer, intent(in) :: ixi^l, ixo^l
3475 double precision, intent(in) :: w(ixi^s,1:nw)
3476 double precision, intent(inout) :: jxb(ixi^s,3)
3477 double precision :: a(ixi^s,3), b(ixi^s,3), tmp(ixi^s,3)
3478 integer :: idir, idirmin
3479 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
3480 double precision :: current(ixi^s,7-2*ndir:3)
3481
3482 b=0.0d0
3483 do idir = 1, ndir
3484 b(ixo^s, idir) = twofl_mag_i_all(w, ixi^l, ixo^l,idir)
3485 end do
3486
3487 ! store J current in a
3488 call get_current(w,ixi^l,ixo^l,idirmin,current)
3489
3490 a=0.0d0
3491 do idir=7-2*ndir,3
3492 a(ixo^s,idir)=current(ixo^s,idir)
3493 end do
3494
3495 call cross_product(ixi^l,ixo^l,a,b,jxb)
3496 end subroutine get_lorentz
3497
3498 subroutine add_source_lorentz_work(qdt,ixI^L,ixO^L,w,wCT,x)
3500 integer, intent(in) :: ixi^l, ixo^l
3501 double precision, intent(in) :: qdt
3502 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3503 double precision, intent(inout) :: w(ixi^s,1:nw)
3504 double precision :: a(ixi^s,3), b(ixi^s,1:ndir)
3505
3506 call get_lorentz(ixi^l, ixo^l,wct,a)
3507 call twofl_get_v_c(wct,x,ixi^l,ixo^l,b)
3508 w(ixo^s,e_c_)=w(ixo^s,e_c_)+qdt*sum(a(ixo^s,1:ndir)*b(ixo^s,1:ndir),dim=ndim+1)
3509
3510 end subroutine add_source_lorentz_work
3511
3512 !> Calculate v_n vector
3513 subroutine twofl_get_v_n(w,x,ixI^L,ixO^L,v)
3515
3516 integer, intent(in) :: ixi^l, ixo^l
3517 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
3518 double precision, intent(out) :: v(ixi^s,ndir)
3519 double precision :: rhon(ixi^s)
3520 integer :: idir
3521
3522 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3523
3524 do idir=1,ndir
3525 v(ixo^s,idir) = w(ixo^s, mom_n(idir)) / rhon(ixo^s)
3526 end do
3527
3528 end subroutine twofl_get_v_n
3529
3530 subroutine get_rhon_tot(w,x,ixI^L,ixO^L,rhon)
3532 integer, intent(in) :: ixi^l, ixo^l
3533 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
3534 double precision, intent(out) :: rhon(ixi^s)
3535 if(has_equi_rho_n0) then
3536 rhon(ixo^s) = w(ixo^s,rho_n_) + block%equi_vars(ixo^s,equi_rho_n0_,b0i)
3537 else
3538 rhon(ixo^s) = w(ixo^s,rho_n_)
3539 endif
3540
3541 end subroutine get_rhon_tot
3542
3543 subroutine twofl_get_pthermal_n(w,x,ixI^L,ixO^L,pth)
3546 integer, intent(in) :: ixi^l, ixo^l
3547 double precision, intent(in) :: w(ixi^s,1:nw)
3548 double precision, intent(in) :: x(ixi^s,1:ndim)
3549 double precision, intent(out) :: pth(ixi^s)
3550
3551 integer :: ix^d, iw
3552
3553 if(phys_energy) then
3554 if(phys_internal_e) then
3555 pth(ixo^s)=gamma_1*w(ixo^s,e_n_)
3556 else
3557 pth(ixo^s)=gamma_1*(w(ixo^s,e_n_)&
3558 - twofl_kin_en_n(w,ixi^l,ixo^l))
3559 end if
3560 if(has_equi_pe_n0) then
3561 pth(ixo^s) = pth(ixo^s) + block%equi_vars(ixo^s,equi_pe_n0_,b0i)
3562 endif
3563 else
3564 call get_rhon_tot(w,x,ixi^l,ixo^l,pth)
3565 pth(ixo^s)=twofl_adiab*pth(ixo^s)**twofl_gamma
3566 end if
3567
3568 if (fix_small_values) then
3569 {do ix^db= ixo^lim^db\}
3570 if(pth(ix^d)<small_pressure) then
3571 pth(ix^d)=small_pressure
3572 end if
3573 {enddo^d&\}
3574 else if (check_small_values) then
3575 {do ix^db= ixo^lim^db\}
3576 if(pth(ix^d)<small_pressure) then
3577 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3578 " encountered when call twofl_get_pthermal_n"
3579 write(*,*) "Iteration: ", it, " Time: ", global_time
3580 write(*,*) "Location: ", x(ix^d,:)
3581 write(*,*) "Cell number: ", ix^d
3582 do iw=1,nw
3583 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3584 end do
3585 ! use erroneous arithmetic operation to crash the run
3586 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3587 write(*,*) "Saving status at the previous time step"
3588 crash=.true.
3589 end if
3590 {enddo^d&\}
3591 end if
3592
3593 end subroutine twofl_get_pthermal_n
3594
3595 subroutine twofl_get_pthermal_n_primitive(w,x,ixI^L,ixO^L,pth)
3597 integer, intent(in) :: ixi^l, ixo^l
3598 double precision, intent(in) :: w(ixi^s,1:nw)
3599 double precision, intent(in) :: x(ixi^s,1:ndim)
3600 double precision, intent(out) :: pth(ixi^s)
3601
3602 if(phys_energy) then
3603 if(has_equi_pe_n0) then
3604 pth(ixo^s) = w(ixo^s,e_n_) + block%equi_vars(ixo^s,equi_pe_n0_,b0i)
3605 else
3606 pth(ixo^s) = w(ixo^s,e_n_)
3607 endif
3608 else
3609 call get_rhon_tot(w,x,ixi^l,ixo^l,pth)
3610 pth(ixo^s)=twofl_adiab*pth(ixo^s)**twofl_gamma
3611 end if
3612 end subroutine twofl_get_pthermal_n_primitive
3613
3614 !> Calculate v component
3615 subroutine twofl_get_v_n_idim(w,x,ixI^L,ixO^L,idim,v)
3617
3618 integer, intent(in) :: ixi^l, ixo^l, idim
3619 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
3620 double precision, intent(out) :: v(ixi^s)
3621 double precision :: rhon(ixi^s)
3622
3623 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3624 v(ixo^s) = w(ixo^s, mom_n(idim)) / rhon(ixo^s)
3625
3626 end subroutine twofl_get_v_n_idim
3627
3628 subroutine internal_energy_add_source_n(qdt,ixI^L,ixO^L,wCT,w,x)
3630 use mod_geometry
3631
3632 integer, intent(in) :: ixi^l, ixo^l
3633 double precision, intent(in) :: qdt
3634 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3635 double precision, intent(inout) :: w(ixi^s,1:nw)
3636 double precision :: pth(ixi^s),v(ixi^s,1:ndir),divv(ixi^s)
3637
3638 call twofl_get_pthermal_n(wct,x,ixi^l,ixo^l,pth)
3639 call twofl_get_v_n(wct,x,ixi^l,ixi^l,v)
3640 call add_geom_pdivv(qdt,ixi^l,ixo^l,v,-pth,w,x,e_n_)
3641
3642 if(fix_small_values .and. .not. has_equi_pe_n0) then
3643 call twofl_handle_small_ei_n(w,x,ixi^l,ixo^l,e_n_,'internal_energy_add_source')
3644 end if
3645 end subroutine internal_energy_add_source_n
3646
3647 !> Calculate v_c vector
3648 subroutine twofl_get_v_c(w,x,ixI^L,ixO^L,v)
3650
3651 integer, intent(in) :: ixi^l, ixo^l
3652 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
3653 double precision, intent(out) :: v(ixi^s,ndir)
3654 double precision :: rhoc(ixi^s)
3655 integer :: idir
3656
3657 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3658 do idir=1,ndir
3659 v(ixo^s,idir) = w(ixo^s, mom_c(idir)) / rhoc(ixo^s)
3660 end do
3661
3662 end subroutine twofl_get_v_c
3663
3664 subroutine get_rhoc_tot(w,x,ixI^L,ixO^L,rhoc)
3666 integer, intent(in) :: ixi^l, ixo^l
3667 double precision, intent(in) :: w(ixi^s,1:nw), x(ixi^s,1:ndim)
3668 double precision, intent(out) :: rhoc(ixi^s)
3669 if(has_equi_rho_c0) then
3670 rhoc(ixo^s) = w(ixo^s,rho_c_) + block%equi_vars(ixo^s,equi_rho_c0_,b0i)
3671 else
3672 rhoc(ixo^s) = w(ixo^s,rho_c_)
3673 endif
3674
3675 end subroutine get_rhoc_tot
3676
3677 subroutine twofl_get_pthermal_c(w,x,ixI^L,ixO^L,pth)
3680 integer, intent(in) :: ixi^l, ixo^l
3681 double precision, intent(in) :: w(ixi^s,1:nw)
3682 double precision, intent(in) :: x(ixi^s,1:ndim)
3683 double precision, intent(out) :: pth(ixi^s)
3684 integer :: ix^d, iw
3685
3686 if(phys_energy) then
3687 if(phys_internal_e) then
3688 pth(ixo^s)=gamma_1*w(ixo^s,e_c_)
3689 elseif(phys_total_energy) then
3690 pth(ixo^s)=gamma_1*(w(ixo^s,e_c_)&
3691 - twofl_kin_en_c(w,ixi^l,ixo^l)&
3692 - twofl_mag_en(w,ixi^l,ixo^l))
3693 else
3694 pth(ixo^s)=gamma_1*(w(ixo^s,e_c_)&
3695 - twofl_kin_en_c(w,ixi^l,ixo^l))
3696 end if
3697 if(has_equi_pe_c0) then
3698 pth(ixo^s) = pth(ixo^s) + block%equi_vars(ixo^s,equi_pe_c0_,b0i)
3699 endif
3700 else
3701 call get_rhoc_tot(w,x,ixi^l,ixo^l,pth)
3702 pth(ixo^s)=twofl_adiab*pth(ixo^s)**twofl_gamma
3703 end if
3704
3705 if (fix_small_values) then
3706 {do ix^db= ixo^lim^db\}
3707 if(pth(ix^d)<small_pressure) then
3708 pth(ix^d)=small_pressure
3709 end if
3710 {enddo^d&\}
3711 else if (check_small_values) then
3712 {do ix^db= ixo^lim^db\}
3713 if(pth(ix^d)<small_pressure) then
3714 write(*,*) "Error: small value of gas pressure",pth(ix^d),&
3715 " encountered when call twofl_get_pe_c1"
3716 write(*,*) "Iteration: ", it, " Time: ", global_time
3717 write(*,*) "Location: ", x(ix^d,:)
3718 write(*,*) "Cell number: ", ix^d
3719 do iw=1,nw
3720 write(*,*) trim(cons_wnames(iw)),": ",w(ix^d,iw)
3721 end do
3722 ! use erroneous arithmetic operation to crash the run
3723 if(trace_small_values) write(*,*) sqrt(pth(ix^d)-bigdouble)
3724 write(*,*) "Saving status at the previous time step"
3725 crash=.true.
3726 end if
3727 {enddo^d&\}
3728 end if
3729
3730 end subroutine twofl_get_pthermal_c
3731
3732 subroutine twofl_get_pthermal_c_primitive(w,x,ixI^L,ixO^L,pth)
3734 integer, intent(in) :: ixi^l, ixo^l
3735 double precision, intent(in) :: w(ixi^s,1:nw)
3736 double precision, intent(in) :: x(ixi^s,1:ndim)
3737 double precision, intent(out) :: pth(ixi^s)
3738
3739 if(phys_energy) then
3740 if(has_equi_pe_c0) then
3741 pth(ixo^s) = w(ixo^s,e_c_) + block%equi_vars(ixo^s,equi_pe_c0_,b0i)
3742 else
3743 pth(ixo^s) = w(ixo^s,e_c_)
3744 endif
3745 else
3746 call get_rhoc_tot(w,x,ixi^l,ixo^l,pth)
3747 pth(ixo^s)=twofl_adiab*pth(ixo^s)**twofl_gamma
3748 end if
3749 end subroutine twofl_get_pthermal_c_primitive
3750
3751 !> Calculate v_c component
3752 subroutine twofl_get_v_c_idim(w,x,ixI^L,ixO^L,idim,v)
3754
3755 integer, intent(in) :: ixi^l, ixo^l, idim
3756 double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
3757 double precision, intent(out) :: v(ixi^s)
3758 double precision :: rhoc(ixi^s)
3759
3760 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3761 v(ixo^s) = w(ixo^s, mom_c(idim)) / rhoc(ixo^s)
3762
3763 end subroutine twofl_get_v_c_idim
3764
3765 subroutine internal_energy_add_source_c(qdt,ixI^L,ixO^L,wCT,w,x,ie)
3767 use mod_geometry
3768
3769 integer, intent(in) :: ixi^l, ixo^l,ie
3770 double precision, intent(in) :: qdt
3771 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3772 double precision, intent(inout) :: w(ixi^s,1:nw)
3773 double precision :: pth(ixi^s),v(ixi^s,1:ndir),divv(ixi^s)
3774
3775 call twofl_get_pthermal_c(wct,x,ixi^l,ixo^l,pth)
3776 call twofl_get_v_c(wct,x,ixi^l,ixi^l,v)
3777 call add_geom_pdivv(qdt,ixi^l,ixo^l,v,-pth,w,x,ie)
3778 if(fix_small_values .and. .not. has_equi_pe_c0) then
3779 call twofl_handle_small_ei_c(w,x,ixi^l,ixo^l,ie,'internal_energy_add_source')
3780 end if
3781 end subroutine internal_energy_add_source_c
3782
3783 !> handle small or negative internal energy
3784 subroutine twofl_handle_small_ei_c(w, x, ixI^L, ixO^L, ie, subname)
3787 integer, intent(in) :: ixi^l,ixo^l, ie
3788 double precision, intent(inout) :: w(ixi^s,1:nw)
3789 double precision, intent(in) :: x(ixi^s,1:ndim)
3790 character(len=*), intent(in) :: subname
3791
3792 integer :: idir
3793 logical :: flag(ixi^s,1:nw)
3794 double precision :: rhoc(ixi^s)
3795 double precision :: rhon(ixi^s)
3796
3797 flag=.false.
3798 if(has_equi_pe_c0) then
3799 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1<small_e)&
3800 flag(ixo^s,ie)=.true.
3801 else
3802 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
3803 endif
3804 if(any(flag(ixo^s,ie))) then
3805 select case (small_values_method)
3806 case ("replace")
3807 if(has_equi_pe_c0) then
3808 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
3809 block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
3810 else
3811 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
3812 endif
3813 case ("average")
3814 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
3815 case default
3816 ! small values error shows primitive variables
3817 ! to_primitive subroutine cannot be used as this error handling
3818 ! is also used in TC where e_to_ei is explicitly called
3819 w(ixo^s,e_n_)=w(ixo^s,e_n_)*gamma_1
3820 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3821 w(ixo^s,e_c_)=w(ixo^s,e_c_)*gamma_1
3822 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3823 do idir = 1, ndir
3824 w(ixo^s, mom_n(idir)) = w(ixo^s, mom_n(idir))/rhon(ixo^s)
3825 w(ixo^s, mom_c(idir)) = w(ixo^s, mom_c(idir))/rhoc(ixo^s)
3826 end do
3827 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
3828 end select
3829 end if
3830
3831 end subroutine twofl_handle_small_ei_c
3832
3833 !> handle small or negative internal energy
3834 subroutine twofl_handle_small_ei_n(w, x, ixI^L, ixO^L, ie, subname)
3837 integer, intent(in) :: ixi^l,ixo^l, ie
3838 double precision, intent(inout) :: w(ixi^s,1:nw)
3839 double precision, intent(in) :: x(ixi^s,1:ndim)
3840 character(len=*), intent(in) :: subname
3841
3842 integer :: idir
3843 logical :: flag(ixi^s,1:nw)
3844 double precision :: rhoc(ixi^s)
3845 double precision :: rhon(ixi^s)
3846
3847 flag=.false.
3848 if(has_equi_pe_n0) then
3849 where(w(ixo^s,ie)+block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1<small_e)&
3850 flag(ixo^s,ie)=.true.
3851 else
3852 where(w(ixo^s,ie)<small_e) flag(ixo^s,ie)=.true.
3853 endif
3854 if(any(flag(ixo^s,ie))) then
3855 select case (small_values_method)
3856 case ("replace")
3857 if(has_equi_pe_n0) then
3858 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e - &
3859 block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
3860 else
3861 where(flag(ixo^s,ie)) w(ixo^s,ie)=small_e
3862 endif
3863 case ("average")
3864 call small_values_average(ixi^l, ixo^l, w, x, flag, ie)
3865 case default
3866 ! small values error shows primitive variables
3867 w(ixo^s,e_n_)=w(ixo^s,e_n_)*gamma_1
3868 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
3869 w(ixo^s,e_c_)=w(ixo^s,e_c_)*gamma_1
3870 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
3871 do idir = 1, ndir
3872 w(ixo^s, mom_n(idir)) = w(ixo^s, mom_n(idir))/rhon(ixo^s)
3873 w(ixo^s, mom_c(idir)) = w(ixo^s, mom_c(idir))/rhoc(ixo^s)
3874 end do
3875 call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
3876 end select
3877 end if
3878
3879 end subroutine twofl_handle_small_ei_n
3880
3881 !> Source terms after split off time-independent magnetic field
3882 subroutine add_source_b0split(qdt,ixI^L,ixO^L,wCT,w,x)
3884
3885 integer, intent(in) :: ixi^l, ixo^l
3886 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3887 double precision, intent(inout) :: w(ixi^s,1:nw)
3888
3889 double precision :: a(ixi^s,3), b(ixi^s,3), axb(ixi^s,3)
3890 integer :: idir
3891
3892 a=0.d0
3893 b=0.d0
3894 ! for force-free field J0xB0 =0
3895 if(.not.b0field_forcefree) then
3896 ! store B0 magnetic field in b
3897 b(ixo^s,1:ndir)=block%B0(ixo^s,1:ndir,0)
3898
3899 ! store J0 current in a
3900 do idir=7-2*ndir,3
3901 a(ixo^s,idir)=block%J0(ixo^s,idir)
3902 end do
3903 call cross_product(ixi^l,ixo^l,a,b,axb)
3904 axb(ixo^s,:)=axb(ixo^s,:)*qdt
3905 ! add J0xB0 source term in momentum equations
3906 w(ixo^s,mom_c(1:ndir))=w(ixo^s,mom_c(1:ndir))+axb(ixo^s,1:ndir)
3907 end if
3908
3909 if(phys_total_energy) then
3910 a=0.d0
3911 ! for free-free field -(vxB0) dot J0 =0
3912 b(ixo^s,:)=wct(ixo^s,mag(:))
3913 ! store full magnetic field B0+B1 in b
3914 if(.not.b0field_forcefree) b(ixo^s,:)=b(ixo^s,:)+block%B0(ixo^s,:,0)
3915 ! store velocity in a
3916 do idir=1,ndir
3917 call twofl_get_v_c_idim(wct,x,ixi^l,ixo^l,idir,a(ixi^s,idir))
3918 end do
3919 call cross_product(ixi^l,ixo^l,a,b,axb)
3920 axb(ixo^s,:)=axb(ixo^s,:)*qdt
3921 ! add -(vxB) dot J0 source term in energy equation
3922 do idir=7-2*ndir,3
3923 w(ixo^s,e_c_)=w(ixo^s,e_c_)-axb(ixo^s,idir)*block%J0(ixo^s,idir)
3924 end do
3925 end if
3926
3927 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_B0')
3928
3929 end subroutine add_source_b0split
3930
3931 !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
3932 !> each direction, non-conservative. If the fourthorder precompiler flag is
3933 !> set, uses fourth order central difference for the laplacian. Then the
3934 !> stencil is 5 (2 neighbours).
3935 subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
3937 use mod_usr_methods
3938 use mod_geometry
3939
3940 integer, intent(in) :: ixi^l, ixo^l
3941 double precision, intent(in) :: qdt
3942 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
3943 double precision, intent(inout) :: w(ixi^s,1:nw)
3944 integer :: ixa^l,idir,jdir,kdir,idirmin,idim,jxo^l,hxo^l,ix
3945 integer :: lxo^l, kxo^l
3946
3947 double precision :: tmp(ixi^s),tmp2(ixi^s)
3948
3949 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
3950 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
3951 double precision :: gradeta(ixi^s,1:ndim), bf(ixi^s,1:ndir)
3952
3953 ! Calculating resistive sources involve one extra layer
3954 ixa^l=ixo^l^ladd2;
3955
3956 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
3957 call mpistop("Error in add_source_res1: Non-conforming input limits")
3958
3959 ! Calculate current density and idirmin
3960 call get_current(wct,ixi^l,ixo^l,idirmin,current)
3961
3962 if (twofl_eta>zero)then
3963 eta(ixa^s)=twofl_eta
3964 gradeta(ixo^s,1:ndim)=zero
3965 else
3966 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
3967 ! assumes that eta is not function of current?
3968 do idim=1,ndim
3969 call gradient(eta,ixi^l,ixo^l,idim,tmp)
3970 gradeta(ixo^s,idim)=tmp(ixo^s)
3971 end do
3972 end if
3973
3974 if(b0field) then
3975 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))+block%B0(ixi^s,1:ndir,0)
3976 else
3977 bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
3978 end if
3979
3980 do idir=1,ndir
3981 ! Put B_idir into tmp2 and eta*Laplace B_idir into tmp
3982 tmp(ixo^s)=zero
3983 tmp2(ixi^s)=bf(ixi^s,idir)
3984 do idim=1,ndim
3985 lxo^l=ixo^l+2*kr(idim,^d);
3986 jxo^l=ixo^l+kr(idim,^d);
3987 hxo^l=ixo^l-kr(idim,^d);
3988 kxo^l=ixo^l-2*kr(idim,^d);
3989 tmp(ixo^s)=tmp(ixo^s)+&
3990 (-tmp2(lxo^s)+16.0d0*tmp2(jxo^s)-30.0d0*tmp2(ixo^s)+16.0d0*tmp2(hxo^s)-tmp2(kxo^s)) &
3991 /(12.0d0 * dxlevel(idim)**2)
3992 end do
3993
3994 ! Multiply by eta
3995 tmp(ixo^s)=tmp(ixo^s)*eta(ixo^s)
3996
3997 ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
3998 if (twofl_eta<zero)then
3999 do jdir=1,ndim; do kdir=idirmin,3
4000 if (lvc(idir,jdir,kdir)/=0)then
4001 if (lvc(idir,jdir,kdir)==1)then
4002 tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
4003 else
4004 tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
4005 end if
4006 end if
4007 end do; end do
4008 end if
4009
4010 ! Add sources related to eta*laplB-grad(eta) x J to B and e
4011 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
4012 if (phys_total_energy) then
4013 w(ixo^s,e_c_)=w(ixo^s,e_c_)+qdt*tmp(ixo^s)*bf(ixo^s,idir)
4014 end if
4015 end do ! idir
4016
4017 if (phys_energy) then
4018 ! de/dt+=eta*J**2
4019 w(ixo^s,e_c_)=w(ixo^s,e_c_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
4020 end if
4021
4022 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res1')
4023
4024 end subroutine add_source_res1
4025
4026 !> Add resistive source to w within ixO
4027 !> Uses 5 point stencil (2 neighbours) in each direction, conservative
4028 subroutine add_source_res2(qdt,ixI^L,ixO^L,wCT,w,x)
4030 use mod_usr_methods
4031 use mod_geometry
4032
4033 integer, intent(in) :: ixi^l, ixo^l
4034 double precision, intent(in) :: qdt
4035 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4036 double precision, intent(inout) :: w(ixi^s,1:nw)
4037
4038 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
4039 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s),curlj(ixi^s,1:3)
4040 double precision :: tmpvec(ixi^s,1:3),tmp(ixo^s)
4041 integer :: ixa^l,idir,idirmin,idirmin1
4042
4043 ixa^l=ixo^l^ladd2;
4044
4045 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
4046 call mpistop("Error in add_source_res2: Non-conforming input limits")
4047
4048 ixa^l=ixo^l^ladd1;
4049 ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
4050 ! Determine exact value of idirmin while doing the loop.
4051 call get_current(wct,ixi^l,ixa^l,idirmin,current)
4052
4053 if (twofl_eta>zero)then
4054 eta(ixa^s)=twofl_eta
4055 else
4056 call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
4057 end if
4058
4059 ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
4060 tmpvec(ixa^s,1:ndir)=zero
4061 do idir=idirmin,3
4062 tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
4063 end do
4064 curlj=0.d0
4065 call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
4066 if(stagger_grid.and.ndim==2.and.ndir==3) then
4067 ! if 2.5D
4068 w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
4069 else
4070 w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
4071 end if
4072
4073 if(phys_energy) then
4074 if(phys_total_energy) then
4075 ! de/dt= +div(B x Jeta) = eta J^2 - B dot curl(eta J)
4076 ! de1/dt= eta J^2 - B1 dot curl(eta J)
4077 w(ixo^s,e_c_)=w(ixo^s,e_c_)+qdt*(eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)-&
4078 sum(wct(ixo^s,mag(1:ndir))*curlj(ixo^s,1:ndir),dim=ndim+1))
4079 else
4080 ! add eta*J**2 source term in the internal energy equation
4081 w(ixo^s,e_c_)=w(ixo^s,e_c_)+qdt*eta(ixo^s)*sum(current(ixo^s,:)**2,dim=ndim+1)
4082 end if
4083
4084 end if
4085
4086 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_res2')
4087 end subroutine add_source_res2
4088
4089 !> Add Hyper-resistive source to w within ixO
4090 !> Uses 9 point stencil (4 neighbours) in each direction.
4091 subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
4093 use mod_geometry
4094
4095 integer, intent(in) :: ixi^l, ixo^l
4096 double precision, intent(in) :: qdt
4097 double precision, intent(in) :: wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4098 double precision, intent(inout) :: w(ixi^s,1:nw)
4099 !.. local ..
4100 double precision :: current(ixi^s,7-2*ndir:3)
4101 double precision :: tmpvec(ixi^s,1:3),tmpvec2(ixi^s,1:3),tmp(ixi^s),ehyper(ixi^s,1:3)
4102 integer :: ixa^l,idir,jdir,kdir,idirmin,idirmin1
4103
4104 ixa^l=ixo^l^ladd3;
4105 if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
4106 call mpistop("Error in add_source_hyperres: Non-conforming input limits")
4107
4108 call get_current(wct,ixi^l,ixa^l,idirmin,current)
4109 tmpvec(ixa^s,1:ndir)=zero
4110 do jdir=idirmin,3
4111 tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
4112 end do
4113
4114 ixa^l=ixo^l^ladd2;
4115 call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
4116
4117 ixa^l=ixo^l^ladd1;
4118 tmpvec(ixa^s,1:ndir)=zero
4119 call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
4120 ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*twofl_eta_hyper
4121
4122 ixa^l=ixo^l;
4123 tmpvec2(ixa^s,1:ndir)=zero
4124 call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
4125
4126 do idir=1,ndir
4127 w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
4128 end do
4129
4130 if (phys_energy) then
4131 ! de/dt= +div(B x Ehyper)
4132 ixa^l=ixo^l^ladd1;
4133 tmpvec2(ixa^s,1:ndir)=zero
4134 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
4135 tmpvec2(ixa^s,idir) = tmpvec(ixa^s,idir)&
4136 + lvc(idir,jdir,kdir)*wct(ixa^s,mag(jdir))*ehyper(ixa^s,kdir)
4137 end do; end do; end do
4138 tmp(ixo^s)=zero
4139 call divvector(tmpvec2,ixi^l,ixo^l,tmp)
4140 w(ixo^s,e_c_)=w(ixo^s,e_c_)+tmp(ixo^s)*qdt
4141 end if
4142
4143 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_hyperres')
4144
4145 end subroutine add_source_hyperres
4146
4147 subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
4148 ! Add divB related sources to w within ixO
4149 ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
4150 ! giving the EGLM-MHD scheme
4152 use mod_geometry
4153
4154 integer, intent(in) :: ixi^l, ixo^l
4155 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4156 double precision, intent(inout) :: w(ixi^s,1:nw)
4157 double precision:: divb(ixi^s)
4158 integer :: idim,idir
4159 double precision :: gradpsi(ixi^s)
4160
4161 ! We calculate now div B
4162 call get_divb(wct,ixi^l,ixo^l,divb, twofl_divb_nth)
4163
4164 ! dPsi/dt = - Ch^2/Cp^2 Psi
4165 if (twofl_glm_alpha < zero) then
4166 w(ixo^s,psi_) = abs(twofl_glm_alpha)*wct(ixo^s,psi_)
4167 else
4168 ! implicit update of Psi variable
4169 ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
4170 if(slab_uniform) then
4171 w(ixo^s,psi_) = dexp(-qdt*cmax_global*twofl_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
4172 else
4173 w(ixo^s,psi_) = dexp(-qdt*cmax_global*twofl_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
4174 end if
4175 end if
4176
4177 ! gradient of Psi
4178 do idim=1,ndim
4179 select case(typegrad)
4180 case("central")
4181 call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
4182 case("limited")
4183 call gradientl(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
4184 end select
4185 if (phys_total_energy) then
4186 ! e = e -qdt (b . grad(Psi))
4187 w(ixo^s,e_c_) = w(ixo^s,e_c_)-qdt*wct(ixo^s,mag(idim))*gradpsi(ixo^s)
4188 end if
4189 end do
4190
4191 ! m = m - qdt b div b
4192 do idir=1,ndir
4193 w(ixo^s,mom_c(idir))=w(ixo^s,mom_c(idir))-qdt*twofl_mag_i_all(w,ixi^l,ixo^l,idir)*divb(ixo^s)
4194 end do
4195
4196 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_glm')
4197
4198 end subroutine add_source_glm
4199
4200 !> Add divB related sources to w within ixO corresponding to Powel
4201 subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
4203
4204 integer, intent(in) :: ixi^l, ixo^l
4205 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4206 double precision, intent(inout) :: w(ixi^s,1:nw)
4207 double precision :: divb(ixi^s),v(ixi^s,1:ndir)
4208 integer :: idir
4209
4210 ! We calculate now div B
4211 call get_divb(wct,ixi^l,ixo^l,divb, twofl_divb_nth)
4212
4213 ! calculate velocity
4214 call twofl_get_v_c(wct,x,ixi^l,ixo^l,v)
4215
4216 if (phys_total_energy) then
4217 ! e = e - qdt (v . b) * div b
4218 w(ixo^s,e_c_)=w(ixo^s,e_c_)-&
4219 qdt*sum(v(ixo^s,:)*wct(ixo^s,mag(:)),dim=ndim+1)*divb(ixo^s)
4220 end if
4221
4222 ! b = b - qdt v * div b
4223 do idir=1,ndir
4224 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*v(ixo^s,idir)*divb(ixo^s)
4225 end do
4226
4227 ! m = m - qdt b div b
4228 do idir=1,ndir
4229 w(ixo^s,mom_c(idir))=w(ixo^s,mom_c(idir))-qdt*twofl_mag_i_all(w,ixi^l,ixo^l,idir)*divb(ixo^s)
4230 end do
4231
4232 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_powel')
4233
4234 end subroutine add_source_powel
4235
4236 subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
4237 ! Add divB related sources to w within ixO
4238 ! corresponding to Janhunen, just the term in the induction equation.
4240
4241 integer, intent(in) :: ixi^l, ixo^l
4242 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4243 double precision, intent(inout) :: w(ixi^s,1:nw)
4244 double precision :: divb(ixi^s),vel(ixi^s)
4245 integer :: idir
4246
4247 ! We calculate now div B
4248 call get_divb(wct,ixi^l,ixo^l,divb, twofl_divb_nth)
4249
4250 ! b = b - qdt v * div b
4251 do idir=1,ndir
4252 call twofl_get_v_c_idim(wct,x,ixi^l,ixo^l,idir,vel)
4253 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*vel(ixo^s)*divb(ixo^s)
4254 end do
4255
4256 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_janhunen')
4257
4258 end subroutine add_source_janhunen
4259
4260 subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
4261 ! Add Linde's divB related sources to wnew within ixO
4263 use mod_geometry
4264
4265 integer, intent(in) :: ixi^l, ixo^l
4266 double precision, intent(in) :: qdt, wct(ixi^s,1:nw), x(ixi^s,1:ndim)
4267 double precision, intent(inout) :: w(ixi^s,1:nw)
4268 integer :: idim, idir, ixp^l, i^d, iside
4269 double precision :: divb(ixi^s),graddivb(ixi^s)
4270 logical, dimension(-1:1^D&) :: leveljump
4271
4272 ! Calculate div B
4273 ixp^l=ixo^l^ladd1;
4274 call get_divb(wct,ixi^l,ixp^l,divb, twofl_divb_nth)
4275
4276 ! for AMR stability, retreat one cell layer from the boarders of level jump
4277 {do i^db=-1,1\}
4278 if(i^d==0|.and.) cycle
4279 if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
4280 leveljump(i^d)=.true.
4281 else
4282 leveljump(i^d)=.false.
4283 end if
4284 {end do\}
4285
4286 ixp^l=ixo^l;
4287 do idim=1,ndim
4288 select case(idim)
4289 {case(^d)
4290 do iside=1,2
4291 i^dd=kr(^dd,^d)*(2*iside-3);
4292 if (leveljump(i^dd)) then
4293 if (iside==1) then
4294 ixpmin^d=ixomin^d-i^d
4295 else
4296 ixpmax^d=ixomax^d-i^d
4297 end if
4298 end if
4299 end do
4300 \}
4301 end select
4302 end do
4303
4304 ! Add Linde's diffusive terms
4305 do idim=1,ndim
4306 ! Calculate grad_idim(divb)
4307 select case(typegrad)
4308 case("central")
4309 call gradient(divb,ixi^l,ixp^l,idim,graddivb)
4310 case("limited")
4311 call gradientl(divb,ixi^l,ixp^l,idim,graddivb)
4312 end select
4313
4314 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
4315 if (slab_uniform) then
4316 graddivb(ixp^s)=graddivb(ixp^s)*divbdiff/(^d&1.0d0/dxlevel(^d)**2+)
4317 else
4318 graddivb(ixp^s)=graddivb(ixp^s)*divbdiff &
4319 /(^d&1.0d0/block%ds(ixp^s,^d)**2+)
4320 end if
4321
4322 w(ixp^s,mag(idim))=w(ixp^s,mag(idim))+graddivb(ixp^s)
4323
4324 if (typedivbdiff=='all' .and. phys_total_energy) then
4325 ! e += B_idim*eta*grad_idim(divb)
4326 w(ixp^s,e_c_)=w(ixp^s,e_c_)+wct(ixp^s,mag(idim))*graddivb(ixp^s)
4327 end if
4328 end do
4329
4330 if (fix_small_values) call twofl_handle_small_values(.false.,w,x,ixi^l,ixo^l,'add_source_linde')
4331
4332 end subroutine add_source_linde
4333
4334
4335 !> get dimensionless div B = |divB| * volume / area / |B|
4336 subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
4337
4339
4340 integer, intent(in) :: ixi^l, ixo^l
4341 double precision, intent(in) :: w(ixi^s,1:nw)
4342 double precision :: divb(ixi^s), dsurface(ixi^s)
4343
4344 double precision :: invb(ixo^s)
4345 integer :: ixa^l,idims
4346
4347 call get_divb(w,ixi^l,ixo^l,divb)
4348 invb(ixo^s)=sqrt(twofl_mag_en_all(w,ixi^l,ixo^l))
4349 where(invb(ixo^s)/=0.d0)
4350 invb(ixo^s)=1.d0/invb(ixo^s)
4351 end where
4352 if(slab_uniform) then
4353 divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
4354 else
4355 ixamin^d=ixomin^d-1;
4356 ixamax^d=ixomax^d-1;
4357 dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
4358 do idims=1,ndim
4359 ixa^l=ixo^l-kr(idims,^d);
4360 dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
4361 end do
4362 divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
4363 block%dvolume(ixo^s)/dsurface(ixo^s)
4364 end if
4365
4366 end subroutine get_normalized_divb
4367
4368 !> Calculate idirmin and the idirmin:3 components of the common current array
4369 !> make sure that dxlevel(^D) is set correctly.
4370 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
4372 use mod_geometry
4373
4374 integer, intent(in) :: ixo^l, ixi^l
4375 double precision, intent(in) :: w(ixi^s,1:nw)
4376 integer, intent(out) :: idirmin
4377 integer :: idir, idirmin0
4378
4379 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
4380 double precision :: current(ixi^s,7-2*ndir:3),bvec(ixi^s,1:ndir)
4381
4382 idirmin0 = 7-2*ndir
4383
4384 bvec(ixi^s,1:ndir)=w(ixi^s,mag(1:ndir))
4385
4386 call curlvector(bvec,ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
4387
4388 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
4389 block%J0(ixo^s,idirmin0:3)
4390
4391 end subroutine get_current
4392
4393 ! copied from gravity
4394 !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
4395 subroutine gravity_add_source(qdt,ixI^L,ixO^L,wCT,w,x,&
4396 energy,qsourcesplit,active)
4398 use mod_usr_methods
4399
4400 integer, intent(in) :: ixi^l, ixo^l
4401 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
4402 double precision, intent(in) :: wct(ixi^s,1:nw)
4403 double precision, intent(inout) :: w(ixi^s,1:nw)
4404 logical, intent(in) :: energy,qsourcesplit
4405 logical, intent(inout) :: active
4406 double precision :: vel(ixi^s)
4407 integer :: idim
4408
4409 double precision :: gravity_field(ixi^s,ndim)
4410
4411 if(qsourcesplit .eqv. grav_split) then
4412 active = .true.
4413
4414 if (.not. associated(usr_gravity)) then
4415 write(*,*) "mod_usr.t: please point usr_gravity to a subroutine"
4416 write(*,*) "like the phys_gravity in mod_usr_methods.t"
4417 call mpistop("gravity_add_source: usr_gravity not defined")
4418 else
4419 call usr_gravity(ixi^l,ixo^l,wct,x,gravity_field)
4420 end if
4421
4422 do idim = 1, ndim
4423 w(ixo^s,mom_n(idim)) = w(ixo^s,mom_n(idim)) &
4424 + qdt * gravity_field(ixo^s,idim) * wct(ixo^s,rho_n_)
4425 w(ixo^s,mom_c(idim)) = w(ixo^s,mom_c(idim)) &
4426 + qdt * gravity_field(ixo^s,idim) * wct(ixo^s,rho_c_)
4427 if(energy) then
4428#if !defined(E_RM_W0) || E_RM_W0 == 1
4429 call twofl_get_v_n_idim(wct,x,ixi^l,ixo^l,idim,vel)
4430 w(ixo^s,e_n_)=w(ixo^s,e_n_) &
4431 + qdt * gravity_field(ixo^s,idim) * vel(ixo^s) * wct(ixo^s,rho_n_)
4432 call twofl_get_v_c_idim(wct,x,ixi^l,ixo^l,idim,vel)
4433 w(ixo^s,e_c_)=w(ixo^s,e_c_) &
4434 + qdt * gravity_field(ixo^s,idim) * vel(ixo^s) * wct(ixo^s,rho_c_)
4435#else
4436 w(ixo^s,e_n_)=w(ixo^s,e_n_) &
4437 + qdt * gravity_field(ixo^s,idim) * wct(ixo^s,mom_n(idim))
4438 w(ixo^s,e_c_)=w(ixo^s,e_c_) &
4439 + qdt * gravity_field(ixo^s,idim) * wct(ixo^s,mom_c(idim))
4440#endif
4441
4442
4443 end if
4444 end do
4445 end if
4446
4447 end subroutine gravity_add_source
4448
4449 subroutine gravity_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
4451 use mod_usr_methods
4452
4453 integer, intent(in) :: ixi^l, ixo^l
4454 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim), w(ixi^s,1:nw)
4455 double precision, intent(inout) :: dtnew
4456
4457 double precision :: dxinv(1:ndim), max_grav
4458 integer :: idim
4459
4460 double precision :: gravity_field(ixi^s,ndim)
4461
4462 ^d&dxinv(^d)=one/dx^d;
4463
4464 if(.not. associated(usr_gravity)) then
4465 write(*,*) "mod_usr.t: please point usr_gravity to a subroutine"
4466 write(*,*) "like the phys_gravity in mod_usr_methods.t"
4467 call mpistop("gravity_get_dt: usr_gravity not defined")
4468 else
4469 call usr_gravity(ixi^l,ixo^l,w,x,gravity_field)
4470 end if
4471
4472 do idim = 1, ndim
4473 max_grav = maxval(abs(gravity_field(ixo^s,idim)))
4474 max_grav = max(max_grav, epsilon(1.0d0))
4475 dtnew = min(dtnew, 1.0d0 / sqrt(max_grav * dxinv(idim)))
4476 end do
4477
4478 end subroutine gravity_get_dt
4479
4480 !> If resistivity is not zero, check diffusion time limit for dt
4481 subroutine twofl_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
4483 use mod_usr_methods
4484 !use mod_viscosity, only: viscosity_get_dt
4485 !use mod_gravity, only: gravity_get_dt
4486
4487 integer, intent(in) :: ixi^l, ixo^l
4488 double precision, intent(inout) :: dtnew
4489 double precision, intent(in) :: dx^d
4490 double precision, intent(in) :: w(ixi^s,1:nw)
4491 double precision, intent(in) :: x(ixi^s,1:ndim)
4492
4493 integer :: idirmin,idim
4494 double precision :: dxarr(ndim)
4495 double precision :: current(ixi^s,7-2*ndir:3),eta(ixi^s)
4496
4497 dtnew = bigdouble
4498
4499 ^d&dxarr(^d)=dx^d;
4500 if (twofl_eta>zero)then
4501 dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/twofl_eta
4502 else if (twofl_eta<zero)then
4503 call get_current(w,ixi^l,ixo^l,idirmin,current)
4504 call usr_special_resistivity(w,ixi^l,ixo^l,idirmin,x,current,eta)
4505 dtnew=bigdouble
4506 do idim=1,ndim
4507 if(slab_uniform) then
4508 dtnew=min(dtnew,&
4509 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
4510 else
4511 dtnew=min(dtnew,&
4512 dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
4513 end if
4514 end do
4515 end if
4516
4517 if(twofl_eta_hyper>zero) then
4518 if(slab_uniform) then
4519 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/twofl_eta_hyper,dtnew)
4520 else
4521 dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/twofl_eta_hyper,dtnew)
4522 end if
4523 end if
4524
4525 ! the timestep related to coll terms: 1/(rho_n rho_c alpha)
4526 if(dtcollpar>0d0 .and. has_collisions()) then
4527 call coll_get_dt(w,x,ixi^l,ixo^l,dtnew)
4528 endif
4529
4530! if(twofl_viscosity) then
4531! call viscosity_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
4532! end if
4533!
4534 if(twofl_gravity) then
4535 call gravity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
4536 end if
4537 if(twofl_hyperdiffusivity) then
4538 call hyperdiffusivity_get_dt(w,ixi^l,ixo^l,dtnew,dx^d,x)
4539 end if
4540
4541
4542 end subroutine twofl_get_dt
4543
4544 pure function has_collisions() result(res)
4545 logical :: res
4546 res = .not. twofl_alpha_coll_constant .or. twofl_alpha_coll >0d0
4547 end function has_collisions
4548
4549 subroutine coll_get_dt(w,x,ixI^L,ixO^L,dtnew)
4551 integer, intent(in) :: ixi^l, ixo^l
4552 double precision, intent(in) :: w(ixi^s,1:nw)
4553 double precision, intent(in) :: x(ixi^s,1:ndim)
4554 double precision, intent(inout) :: dtnew
4555
4556 double precision :: rhon(ixi^s), rhoc(ixi^s), alpha(ixi^s)
4557 double precision, allocatable :: gamma_rec(:^d&), gamma_ion(:^D&)
4558 double precision :: max_coll_rate
4559
4560 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
4561 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
4562
4563 call get_alpha_coll(ixi^l, ixo^l, w, x, alpha)
4564 max_coll_rate = maxval(alpha(ixo^s) * max(rhon(ixo^s), rhoc(ixo^s)))
4565
4566 if(twofl_coll_inc_ionrec) then
4567 allocate(gamma_ion(ixi^s), gamma_rec(ixi^s))
4568 call get_gamma_ion_rec(ixi^l, ixo^l, w, x, gamma_rec, gamma_ion)
4569 max_coll_rate=max(max_coll_rate, maxval(gamma_ion(ixo^s)), maxval(gamma_rec(ixo^s)))
4570 deallocate(gamma_ion, gamma_rec)
4571 endif
4572 dtnew = min(dtcollpar/max_coll_rate, dtnew)
4573
4574 end subroutine coll_get_dt
4575
4576 ! Add geometrical source terms to w
4577 subroutine twofl_add_source_geom(qdt,dtfactor,ixI^L,ixO^L,wCT,wprim,w,x)
4579 use mod_geometry
4580
4581 integer, intent(in) :: ixi^l, ixo^l
4582 double precision, intent(in) :: qdt, dtfactor,x(ixi^s,1:ndim)
4583 double precision, intent(inout) :: wct(ixi^s,1:nw), wprim(ixi^s,1:nw), w(ixi^s,1:nw)
4584
4585 integer :: iw,idir, h1x^l{^nooned, h2x^l}
4586 double precision :: tmp(ixi^s),tmp1(ixi^s),tmp2(ixi^s),rho(ixi^s)
4587
4588 integer :: mr_,mphi_ ! Polar var. names
4589 integer :: br_,bphi_
4590
4591 ! charges
4592
4593 mr_=mom_c(1); mphi_=mom_c(1)-1+phi_ ! Polar var. names
4594 br_=mag(1); bphi_=mag(1)-1+phi_
4595 call get_rhoc_tot(wct,x,ixi^l,ixo^l,rho)
4596
4597 select case (coordinate)
4598 case (cylindrical)
4599 call twofl_get_p_c_total(wct,x,ixi^l,ixo^l,tmp)
4600
4601 if(phi_>0) then
4602 w(ixo^s,mr_)=w(ixo^s,mr_)+qdt/x(ixo^s,1)*(tmp(ixo^s)-&
4603 wct(ixo^s,bphi_)**2+wct(ixo^s,mphi_)**2/rho(ixo^s))
4604 w(ixo^s,mphi_)=w(ixo^s,mphi_)+qdt/x(ixo^s,1)*(&
4605 -wct(ixo^s,mphi_)*wct(ixo^s,mr_)/rho(ixo^s) &
4606 +wct(ixo^s,bphi_)*wct(ixo^s,br_))
4607 if(.not.stagger_grid) then
4608 w(ixo^s,bphi_)=w(ixo^s,bphi_)+qdt/x(ixo^s,1)*&
4609 (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
4610 -wct(ixo^s,br_)*wct(ixo^s,mphi_)) &
4611 /rho(ixo^s)
4612 end if
4613 else
4614 w(ixo^s,mr_)=w(ixo^s,mr_)+qdt/x(ixo^s,1)*tmp(ixo^s)
4615 end if
4616 if(twofl_glm) w(ixo^s,br_)=w(ixo^s,br_)+qdt*wct(ixo^s,psi_)/x(ixo^s,1)
4617 case (spherical)
4618 h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
4619 call twofl_get_p_c_total(wct,x,ixi^l,ixo^l,tmp1)
4620 tmp(ixo^s)=tmp1(ixo^s)
4621 if(b0field) then
4622 tmp2(ixo^s)=sum(block%B0(ixo^s,:,0)*wct(ixo^s,mag(:)),dim=ndim+1)
4623 tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
4624 end if
4625 ! m1
4626 tmp(ixo^s)=tmp(ixo^s)*x(ixo^s,1) &
4627 *(block%surfaceC(ixo^s,1)-block%surfaceC(h1x^s,1))/block%dvolume(ixo^s)
4628 if(ndir>1) then
4629 do idir=2,ndir
4630 tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom_c(idir))**2/rho(ixo^s)-wct(ixo^s,mag(idir))**2
4631 if(b0field) tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,idir,0)*wct(ixo^s,mag(idir))
4632 end do
4633 end if
4634 w(ixo^s,mom_c(1))=w(ixo^s,mom_c(1))+qdt*tmp(ixo^s)/x(ixo^s,1)
4635 ! b1
4636 if(twofl_glm) then
4637 w(ixo^s,mag(1))=w(ixo^s,mag(1))+qdt/x(ixo^s,1)*2.0d0*wct(ixo^s,psi_)
4638 end if
4639
4640 {^nooned
4641 ! m2
4642 tmp(ixo^s)=tmp1(ixo^s)
4643 if(b0field) then
4644 tmp(ixo^s)=tmp(ixo^s)+tmp2(ixo^s)
4645 end if
4646 ! This will make hydrostatic p=const an exact solution
4647 w(ixo^s,mom_c(2))=w(ixo^s,mom_c(2))+qdt*tmp(ixo^s) &
4648 *(block%surfaceC(ixo^s,2)-block%surfaceC(h2x^s,2)) &
4649 /block%dvolume(ixo^s)
4650 tmp(ixo^s)=-(wct(ixo^s,mom_c(1))*wct(ixo^s,mom_c(2))/rho(ixo^s) &
4651 -wct(ixo^s,mag(1))*wct(ixo^s,mag(2)))
4652 if (b0field) then
4653 tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(2)) &
4654 +wct(ixo^s,mag(1))*block%B0(ixo^s,2,0)
4655 end if
4656 if(ndir==3) then
4657 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom_c(3))**2/rho(ixo^s) &
4658 -wct(ixo^s,mag(3))**2)*dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
4659 if (b0field) then
4660 tmp(ixo^s)=tmp(ixo^s)-2.0d0*block%B0(ixo^s,3,0)*wct(ixo^s,mag(3))&
4661 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2))
4662 end if
4663 end if
4664 w(ixo^s,mom_c(2))=w(ixo^s,mom_c(2))+qdt*tmp(ixo^s)/x(ixo^s,1)
4665 ! b2
4666 if(.not.stagger_grid) then
4667 tmp(ixo^s)=(wct(ixo^s,mom_c(1))*wct(ixo^s,mag(2)) &
4668 -wct(ixo^s,mom_c(2))*wct(ixo^s,mag(1)))/rho(ixo^s)
4669 if(b0field) then
4670 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom_c(1))*block%B0(ixo^s,2,0) &
4671 -wct(ixo^s,mom_c(2))*block%B0(ixo^s,1,0))/rho(ixo^s)
4672 end if
4673 if(twofl_glm) then
4674 tmp(ixo^s)=tmp(ixo^s) &
4675 + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
4676 end if
4677 w(ixo^s,mag(2))=w(ixo^s,mag(2))+qdt*tmp(ixo^s)/x(ixo^s,1)
4678 end if
4679 }
4680
4681 if(ndir==3) then
4682 ! m3
4683 tmp(ixo^s)=-(wct(ixo^s,mom_c(3))*wct(ixo^s,mom_c(1))/rho(ixo^s) &
4684 -wct(ixo^s,mag(3))*wct(ixo^s,mag(1))) {^nooned &
4685 -(wct(ixo^s,mom_c(2))*wct(ixo^s,mom_c(3))/rho(ixo^s) &
4686 -wct(ixo^s,mag(2))*wct(ixo^s,mag(3))) &
4687 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
4688 if (b0field) then
4689 tmp(ixo^s)=tmp(ixo^s)+block%B0(ixo^s,1,0)*wct(ixo^s,mag(3)) &
4690 +wct(ixo^s,mag(1))*block%B0(ixo^s,3,0) {^nooned &
4691 +(block%B0(ixo^s,2,0)*wct(ixo^s,mag(3)) &
4692 +wct(ixo^s,mag(2))*block%B0(ixo^s,3,0)) &
4693 *dcos(x(ixo^s,2))/dsin(x(ixo^s,2)) }
4694 end if
4695 w(ixo^s,mom_c(3))=w(ixo^s,mom_c(3))+qdt*tmp(ixo^s)/x(ixo^s,1)
4696 ! b3
4697 if(.not.stagger_grid) then
4698 tmp(ixo^s)=(wct(ixo^s,mom_c(1))*wct(ixo^s,mag(3)) &
4699 -wct(ixo^s,mom_c(3))*wct(ixo^s,mag(1)))/rho(ixo^s) {^nooned &
4700 -(wct(ixo^s,mom_c(3))*wct(ixo^s,mag(2)) &
4701 -wct(ixo^s,mom_c(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
4702 /(rho(ixo^s)*dsin(x(ixo^s,2))) }
4703 if (b0field) then
4704 tmp(ixo^s)=tmp(ixo^s)+(wct(ixo^s,mom_c(1))*block%B0(ixo^s,3,0) &
4705 -wct(ixo^s,mom_c(3))*block%B0(ixo^s,1,0))/rho(ixo^s){^nooned &
4706 -(wct(ixo^s,mom_c(3))*block%B0(ixo^s,2,0) &
4707 -wct(ixo^s,mom_c(2))*block%B0(ixo^s,3,0))*dcos(x(ixo^s,2)) &
4708 /(rho(ixo^s)*dsin(x(ixo^s,2))) }
4709 end if
4710 w(ixo^s,mag(3))=w(ixo^s,mag(3))+qdt*tmp(ixo^s)/x(ixo^s,1)
4711 end if
4712 end if
4713 end select
4714
4715 ! neutrals
4716 !TODO no dust: see and implement them from hd/mod_hd_phys !
4717 !uncomment cartesian expansion
4718 call get_rhon_tot(wct,x,ixi^l,ixo^l,rho)
4719 call twofl_get_pthermal_n(wct, x, ixi^l, ixo^l, tmp1)
4720
4721 select case (coordinate)
4722! case(Cartesian_expansion)
4723! !the user provides the functions of exp_factor and del_exp_factor
4724! if(associated(usr_set_surface)) call usr_set_surface(ixI^L,x,block%dx,exp_factor,del_exp_factor,exp_factor_primitive)
4725! tmp(ixO^S) = tmp1(ixO^S)*del_exp_factor(ixO^S)/exp_factor(ixO^S)
4726! w(ixO^S,mom(1)) = w(ixO^S,mom(1)) + qdt*tmp(ixO^S)
4727
4728 case (cylindrical)
4729 mr_ = mom_n(r_)
4730 if (phi_ > 0) then
4731 where (rho(ixo^s) > 0d0)
4732 tmp(ixo^s) = tmp1(ixo^s) + wct(ixo^s, mphi_)**2 / rho(ixo^s)
4733 w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * tmp(ixo^s) / x(ixo^s, r_)
4734 end where
4735 ! s[mphi]=(-mphi*mr/rho)/radius
4736 where (rho(ixo^s) > 0d0)
4737 tmp(ixo^s) = -wct(ixo^s, mphi_) * wct(ixo^s, mr_) / rho(ixo^s)
4738 w(ixo^s, mphi_) = w(ixo^s, mphi_) + qdt * tmp(ixo^s) / x(ixo^s, r_)
4739 end where
4740 else
4741 ! s[mr]=2pthermal/radius
4742 w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * tmp1(ixo^s) / x(ixo^s, r_)
4743 end if
4744 case (spherical)
4745 if(phi_>0) mphi_ = mom_n(phi_)
4746 h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
4747 ! s[mr]=((mtheta**2+mphi**2)/rho+2*p)/r
4748 tmp(ixo^s) = tmp1(ixo^s) * x(ixo^s, 1) &
4749 *(block%surfaceC(ixo^s, 1) - block%surfaceC(h1x^s, 1)) &
4750 /block%dvolume(ixo^s)
4751 if (ndir > 1) then
4752 do idir = 2, ndir
4753 tmp(ixo^s) = tmp(ixo^s) + wct(ixo^s, mom_n(idir))**2 / rho(ixo^s)
4754 end do
4755 end if
4756 w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * tmp(ixo^s) / x(ixo^s, 1)
4757
4758 {^nooned
4759 ! s[mtheta]=-(mr*mtheta/rho)/r+cot(theta)*(mphi**2/rho+p)/r
4760 tmp(ixo^s) = tmp1(ixo^s) * x(ixo^s, 1) &
4761 * (block%surfaceC(ixo^s, 2) - block%surfaceC(h2x^s, 2)) &
4762 / block%dvolume(ixo^s)
4763 if (ndir == 3) then
4764 tmp(ixo^s) = tmp(ixo^s) + (wct(ixo^s, mom_n(3))**2 / rho(ixo^s)) / tan(x(ixo^s, 2))
4765 end if
4766 tmp(ixo^s) = tmp(ixo^s) - (wct(ixo^s, mom_n(2)) * wct(ixo^s, mr_)) / rho(ixo^s)
4767 w(ixo^s, mom_n(2)) = w(ixo^s, mom_n(2)) + qdt * tmp(ixo^s) / x(ixo^s, 1)
4768
4769 if (ndir == 3) then
4770 ! s[mphi]=-(mphi*mr/rho)/r-cot(theta)*(mtheta*mphi/rho)/r
4771 tmp(ixo^s) = -(wct(ixo^s, mom_n(3)) * wct(ixo^s, mr_)) / rho(ixo^s)&
4772 - (wct(ixo^s, mom_n(2)) * wct(ixo^s, mom_n(3))) / rho(ixo^s) / tan(x(ixo^s, 2))
4773 w(ixo^s, mom_n(3)) = w(ixo^s, mom_n(3)) + qdt * tmp(ixo^s) / x(ixo^s, 1)
4774 end if
4775 }
4776 end select
4777
4778 contains
4779 subroutine twofl_get_p_c_total(w,x,ixI^L,ixO^L,p)
4781
4782 integer, intent(in) :: ixI^L, ixO^L
4783 double precision, intent(in) :: w(ixI^S,nw)
4784 double precision, intent(in) :: x(ixI^S,1:ndim)
4785 double precision, intent(out) :: p(ixI^S)
4786
4787 call twofl_get_pthermal_c(w,x,ixi^l,ixo^l,p)
4788
4789 p(ixo^s) = p(ixo^s) + 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
4790
4791 end subroutine twofl_get_p_c_total
4792
4793 end subroutine twofl_add_source_geom
4794
4795 subroutine twofl_get_temp_c_pert_from_etot(w, x, ixI^L, ixO^L, res)
4797 integer, intent(in) :: ixI^L, ixO^L
4798 double precision, intent(in) :: w(ixI^S, 1:nw)
4799 double precision, intent(in) :: x(ixI^S, 1:ndim)
4800 double precision, intent(out):: res(ixI^S)
4801
4802 ! store pe1 in res
4803 res(ixo^s)=(gamma_1*(w(ixo^s,e_c_)&
4804 - twofl_kin_en_c(w,ixi^l,ixo^l)&
4805 - twofl_mag_en(w,ixi^l,ixo^l)))
4806 if(has_equi_pe_c0) then
4807 res(ixo^s) = res(ixo^s) + block%equi_vars(ixo^s,equi_pe_c0_,b0i)
4808 if(has_equi_rho_c0) then
4809 res(ixo^s) = res(ixo^s)/(rc * (w(ixo^s,rho_c_)+ block%equi_vars(ixo^s,equi_rho_c0_,b0i))) - &
4810 block%equi_vars(ixo^s,equi_pe_c0_,b0i)/(rc * block%equi_vars(ixo^s,equi_rho_c0_,b0i))
4811 else
4812 ! infinite equi temperature with p0 and 0 density
4813 res(ixo^s) = 0d0
4814 endif
4815 else
4816 res(ixo^s) = res(ixo^s)/(rc * w(ixo^s,rho_c_))
4817 endif
4818
4819 end subroutine twofl_get_temp_c_pert_from_etot
4820
4821 !> Compute 2 times total magnetic energy
4822 function twofl_mag_en_all(w, ixI^L, ixO^L) result(mge)
4824 integer, intent(in) :: ixI^L, ixO^L
4825 double precision, intent(in) :: w(ixI^S, nw)
4826 double precision :: mge(ixO^S)
4827
4828 if (b0field) then
4829 mge(ixo^s) = sum((w(ixo^s, mag(:))+block%B0(ixo^s,:,b0i))**2, dim=ndim+1)
4830 else
4831 mge(ixo^s) = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
4832 end if
4833 end function twofl_mag_en_all
4834
4835 !> Compute full magnetic field by direction
4836 function twofl_mag_i_all(w, ixI^L, ixO^L,idir) result(mgf)
4838 integer, intent(in) :: ixI^L, ixO^L, idir
4839 double precision, intent(in) :: w(ixI^S, nw)
4840 double precision :: mgf(ixO^S)
4841
4842 if (b0field) then
4843 mgf(ixo^s) = w(ixo^s, mag(idir))+block%B0(ixo^s,idir,b0i)
4844 else
4845 mgf(ixo^s) = w(ixo^s, mag(idir))
4846 end if
4847 end function twofl_mag_i_all
4848
4849 !> Compute evolving magnetic energy
4850 function twofl_mag_en(w, ixI^L, ixO^L) result(mge)
4851 use mod_global_parameters, only: nw, ndim
4852 integer, intent(in) :: ixI^L, ixO^L
4853 double precision, intent(in) :: w(ixI^S, nw)
4854 double precision :: mge(ixO^S)
4855
4856 mge(ixo^s) = 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
4857 end function twofl_mag_en
4858
4859 !> compute kinetic energy of neutrals
4860 function twofl_kin_en_n(w, ixI^L, ixO^L) result(ke)
4861 use mod_global_parameters, only: nw, ndim,block
4862 integer, intent(in) :: ixI^L, ixO^L
4863 double precision, intent(in) :: w(ixI^S, nw)
4864 double precision :: ke(ixO^S)
4865
4866 if(has_equi_rho_n0) then
4867 ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom_n(:))**2, dim=ndim+1) / (w(ixo^s, rho_n_) + block%equi_vars(ixo^s,equi_rho_n0_,0))
4868 else
4869 ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom_n(:))**2, dim=ndim+1) / w(ixo^s, rho_n_)
4870 endif
4871
4872 end function twofl_kin_en_n
4873
4874 subroutine twofl_get_temp_n_pert_from_etot(w, x, ixI^L, ixO^L, res)
4876 integer, intent(in) :: ixI^L, ixO^L
4877 double precision, intent(in) :: w(ixI^S, 1:nw)
4878 double precision, intent(in) :: x(ixI^S, 1:ndim)
4879 double precision, intent(out):: res(ixI^S)
4880
4881 ! store pe1 in res
4882 res(ixo^s)=(gamma_1*(w(ixo^s,e_c_)- twofl_kin_en_c(w,ixi^l,ixo^l)))
4883 if(has_equi_pe_n0) then
4884 res(ixo^s) = res(ixo^s) + block%equi_vars(ixo^s,equi_pe_n0_,b0i)
4885 if(has_equi_rho_n0) then
4886 res(ixo^s) = res(ixo^s)/(rn * (w(ixo^s,rho_n_)+ block%equi_vars(ixo^s,equi_rho_n0_,b0i))) - &
4887 block%equi_vars(ixo^s,equi_pe_n0_,b0i)/(rn * block%equi_vars(ixo^s,equi_rho_n0_,b0i))
4888 else
4889 ! infinite equi temperature with p0 and 0 density
4890 res(ixo^s) = 0d0
4891 endif
4892 else
4893 res(ixo^s) = res(ixo^s)/(rn * w(ixo^s,rho_n_))
4894 endif
4895
4896 end subroutine twofl_get_temp_n_pert_from_etot
4897
4898 !> compute kinetic energy of charges
4899 !> w are conserved variables
4900 function twofl_kin_en_c(w, ixI^L, ixO^L) result(ke)
4901 use mod_global_parameters, only: nw, ndim,block
4902 integer, intent(in) :: ixI^L, ixO^L
4903 double precision, intent(in) :: w(ixI^S, nw)
4904 double precision :: ke(ixO^S)
4905
4906 if(has_equi_rho_c0) then
4907 ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom_c(:))**2, dim=ndim+1) / (w(ixo^s, rho_c_) + block%equi_vars(ixo^s,equi_rho_c0_,0))
4908 else
4909 ke(ixo^s) = 0.5d0 * sum(w(ixo^s, mom_c(:))**2, dim=ndim+1) / w(ixo^s, rho_c_)
4910 endif
4911 end function twofl_kin_en_c
4912
4913 subroutine twofl_getv_hall(w,x,ixI^L,ixO^L,vHall)
4915
4916 integer, intent(in) :: ixI^L, ixO^L
4917 double precision, intent(in) :: w(ixI^S,nw)
4918 double precision, intent(in) :: x(ixI^S,1:ndim)
4919 double precision, intent(inout) :: vHall(ixI^S,1:3)
4920
4921 integer :: idir, idirmin
4922 double precision :: current(ixI^S,7-2*ndir:3)
4923 double precision :: rho(ixI^S)
4924
4925 call get_rhoc_tot(w,x,ixi^l,ixo^l,rho)
4926 ! Calculate current density and idirmin
4927 call get_current(w,ixi^l,ixo^l,idirmin,current)
4928 vhall(ixo^s,1:3) = zero
4929 vhall(ixo^s,idirmin:3) = - twofl_etah*current(ixo^s,idirmin:3)
4930 do idir = idirmin, 3
4931 vhall(ixo^s,idir) = vhall(ixo^s,idir)/rho(ixo^s)
4932 end do
4933
4934 end subroutine twofl_getv_hall
4935
4936! the following not used
4937! subroutine twofl_getdt_Hall(w,x,ixI^L,ixO^L,dx^D,dthall)
4938! use mod_global_parameters
4939!
4940! integer, intent(in) :: ixI^L, ixO^L
4941! double precision, intent(in) :: dx^D
4942! double precision, intent(in) :: w(ixI^S,1:nw)
4943! double precision, intent(in) :: x(ixI^S,1:ndim)
4944! double precision, intent(out) :: dthall
4945! !.. local ..
4946! double precision :: dxarr(ndim)
4947! double precision :: bmag(ixI^S)
4948!
4949! dthall=bigdouble
4950!
4951! ! because we have that in cmax now:
4952! return
4953!
4954! ^D&dxarr(^D)=dx^D;
4955!
4956! if (.not. B0field) then
4957! bmag(ixO^S)=sqrt(sum(w(ixO^S,mag(:))**2, dim=ndim+1))
4958! bmag(ixO^S)=sqrt(sum((w(ixO^S,mag(:)) + block%B0(ixO^S,1:ndir,b0i))**2))
4959! end if
4960!
4961! if(slab_uniform) then
4962! dthall=dtdiffpar*minval(dxarr(1:ndim))**2.0d0/(twofl_etah*maxval(bmag(ixO^S)/w(ixO^S,rho_c_)))
4963! else
4964! dthall=dtdiffpar*minval(block%ds(ixO^S,1:ndim))**2.0d0/(twofl_etah*maxval(bmag(ixO^S)/w(ixO^S,rho_c_)))
4965! end if
4966!
4967! end subroutine twofl_getdt_Hall
4968
4969 subroutine twofl_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
4971 use mod_usr_methods
4972 integer, intent(in) :: ixI^L, ixO^L, idir
4973 double precision, intent(in) :: qt
4974 double precision, intent(inout) :: wLC(ixI^S,1:nw), wRC(ixI^S,1:nw)
4975 double precision, intent(inout) :: wLp(ixI^S,1:nw), wRp(ixI^S,1:nw)
4976 type(state) :: s
4977 double precision :: dB(ixI^S), dPsi(ixI^S)
4978
4979 if(stagger_grid) then
4980 wlc(ixo^s,mag(idir))=s%ws(ixo^s,idir)
4981 wrc(ixo^s,mag(idir))=s%ws(ixo^s,idir)
4982 wlp(ixo^s,mag(idir))=s%ws(ixo^s,idir)
4983 wrp(ixo^s,mag(idir))=s%ws(ixo^s,idir)
4984 else
4985 ! Solve the Riemann problem for the linear 2x2 system for normal
4986 ! B-field and GLM_Psi according to Dedner 2002:
4987 ! This implements eq. (42) in Dedner et al. 2002 JcP 175
4988 ! Gives the Riemann solution on the interface
4989 ! for the normal B component and Psi in the GLM-MHD system.
4990 ! 23/04/2013 Oliver Porth
4991 db(ixo^s) = wrp(ixo^s,mag(idir)) - wlp(ixo^s,mag(idir))
4992 dpsi(ixo^s) = wrp(ixo^s,psi_) - wlp(ixo^s,psi_)
4993
4994 wlp(ixo^s,mag(idir)) = 0.5d0 * (wrp(ixo^s,mag(idir)) + wlp(ixo^s,mag(idir))) &
4995 - 0.5d0/cmax_global * dpsi(ixo^s)
4996 wlp(ixo^s,psi_) = 0.5d0 * (wrp(ixo^s,psi_) + wlp(ixo^s,psi_)) &
4997 - 0.5d0*cmax_global * db(ixo^s)
4998
4999 wrp(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5000 wrp(ixo^s,psi_) = wlp(ixo^s,psi_)
5001
5002 if(phys_total_energy) then
5003 wrc(ixo^s,e_c_)=wrc(ixo^s,e_c_)-half*wrc(ixo^s,mag(idir))**2
5004 wlc(ixo^s,e_c_)=wlc(ixo^s,e_c_)-half*wlc(ixo^s,mag(idir))**2
5005 end if
5006 wrc(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5007 wrc(ixo^s,psi_) = wlp(ixo^s,psi_)
5008 wlc(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
5009 wlc(ixo^s,psi_) = wlp(ixo^s,psi_)
5010 ! modify total energy according to the change of magnetic field
5011 if(phys_total_energy) then
5012 wrc(ixo^s,e_c_)=wrc(ixo^s,e_c_)+half*wrc(ixo^s,mag(idir))**2
5013 wlc(ixo^s,e_c_)=wlc(ixo^s,e_c_)+half*wlc(ixo^s,mag(idir))**2
5014 end if
5015 end if
5016
5017 if(associated(usr_set_wlr)) call usr_set_wlr(ixi^l,ixo^l,qt,wlc,wrc,wlp,wrp,s,idir)
5018
5019 end subroutine twofl_modify_wlr
5020
5021 subroutine twofl_boundary_adjust(igrid,psb)
5023 integer, intent(in) :: igrid
5024 type(state), target :: psb(max_blocks)
5025
5026 integer :: iB, idims, iside, ixO^L, i^D
5027
5028 block=>ps(igrid)
5029 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
5030 do idims=1,ndim
5031 ! to avoid using as yet unknown corner info in more than 1D, we
5032 ! fill only interior mesh ranges of the ghost cell ranges at first,
5033 ! and progressively enlarge the ranges to include corners later
5034 do iside=1,2
5035 i^d=kr(^d,idims)*(2*iside-3);
5036 if (neighbor_type(i^d,igrid)/=1) cycle
5037 ib=(idims-1)*2+iside
5038 if(.not.boundary_divbfix(ib)) cycle
5039 if(any(typeboundary(:,ib)==bc_special)) then
5040 ! MF nonlinear force-free B field extrapolation and data driven
5041 ! require normal B of the first ghost cell layer to be untouched by
5042 ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
5043 select case (idims)
5044 {case (^d)
5045 if (iside==2) then
5046 ! maximal boundary
5047 ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
5048 ixomax^dd=ixghi^dd;
5049 else
5050 ! minimal boundary
5051 ixomin^dd=ixglo^dd;
5052 ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
5053 end if \}
5054 end select
5055 call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
5056 end if
5057 end do
5058 end do
5059
5060 end subroutine twofl_boundary_adjust
5061
5062 subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
5064
5065 integer, intent(in) :: ixG^L,ixO^L,iB
5066 double precision, intent(inout) :: w(ixG^S,1:nw)
5067 double precision, intent(in) :: x(ixG^S,1:ndim)
5068
5069 double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
5070 integer :: ix^D,ixF^L
5071
5072 select case(ib)
5073 case(1)
5074 ! 2nd order CD for divB=0 to set normal B component better
5075 {^iftwod
5076 ixfmin1=ixomin1+1
5077 ixfmax1=ixomax1+1
5078 ixfmin2=ixomin2+1
5079 ixfmax2=ixomax2-1
5080 if(slab_uniform) then
5081 dx1x2=dxlevel(1)/dxlevel(2)
5082 do ix1=ixfmax1,ixfmin1,-1
5083 w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
5084 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
5085 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
5086 enddo
5087 else
5088 do ix1=ixfmax1,ixfmin1,-1
5089 w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
5090 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
5091 +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
5092 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
5093 -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
5094 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
5095 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
5096 end do
5097 end if
5098 }
5099 {^ifthreed
5100 ixfmin1=ixomin1+1
5101 ixfmax1=ixomax1+1
5102 ixfmin2=ixomin2+1
5103 ixfmax2=ixomax2-1
5104 ixfmin3=ixomin3+1
5105 ixfmax3=ixomax3-1
5106 if(slab_uniform) then
5107 dx1x2=dxlevel(1)/dxlevel(2)
5108 dx1x3=dxlevel(1)/dxlevel(3)
5109 do ix1=ixfmax1,ixfmin1,-1
5110 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5111 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
5112 +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
5113 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
5114 +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
5115 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
5116 end do
5117 else
5118 do ix1=ixfmax1,ixfmin1,-1
5119 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5120 ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
5121 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
5122 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
5123 +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
5124 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
5125 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
5126 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
5127 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
5128 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
5129 +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
5130 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
5131 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
5132 -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
5133 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5134 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
5135 /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
5136 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
5137 end do
5138 end if
5139 }
5140 case(2)
5141 {^iftwod
5142 ixfmin1=ixomin1-1
5143 ixfmax1=ixomax1-1
5144 ixfmin2=ixomin2+1
5145 ixfmax2=ixomax2-1
5146 if(slab_uniform) then
5147 dx1x2=dxlevel(1)/dxlevel(2)
5148 do ix1=ixfmin1,ixfmax1
5149 w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
5150 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
5151 w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
5152 enddo
5153 else
5154 do ix1=ixfmin1,ixfmax1
5155 w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
5156 w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
5157 -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
5158 block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
5159 +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
5160 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
5161 /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
5162 end do
5163 end if
5164 }
5165 {^ifthreed
5166 ixfmin1=ixomin1-1
5167 ixfmax1=ixomax1-1
5168 ixfmin2=ixomin2+1
5169 ixfmax2=ixomax2-1
5170 ixfmin3=ixomin3+1
5171 ixfmax3=ixomax3-1
5172 if(slab_uniform) then
5173 dx1x2=dxlevel(1)/dxlevel(2)
5174 dx1x3=dxlevel(1)/dxlevel(3)
5175 do ix1=ixfmin1,ixfmax1
5176 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5177 w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
5178 -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
5179 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
5180 -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
5181 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
5182 end do
5183 else
5184 do ix1=ixfmin1,ixfmax1
5185 w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
5186 ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
5187 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
5188 block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
5189 -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
5190 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
5191 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
5192 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
5193 w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
5194 block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
5195 -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
5196 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
5197 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
5198 +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
5199 w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5200 block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
5201 /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
5202 w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
5203 end do
5204 end if
5205 }
5206 case(3)
5207 {^iftwod
5208 ixfmin1=ixomin1+1
5209 ixfmax1=ixomax1-1
5210 ixfmin2=ixomin2+1
5211 ixfmax2=ixomax2+1
5212 if(slab_uniform) then
5213 dx2x1=dxlevel(2)/dxlevel(1)
5214 do ix2=ixfmax2,ixfmin2,-1
5215 w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
5216 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
5217 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
5218 enddo
5219 else
5220 do ix2=ixfmax2,ixfmin2,-1
5221 w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
5222 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
5223 +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
5224 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
5225 -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
5226 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
5227 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
5228 end do
5229 end if
5230 }
5231 {^ifthreed
5232 ixfmin1=ixomin1+1
5233 ixfmax1=ixomax1-1
5234 ixfmin3=ixomin3+1
5235 ixfmax3=ixomax3-1
5236 ixfmin2=ixomin2+1
5237 ixfmax2=ixomax2+1
5238 if(slab_uniform) then
5239 dx2x1=dxlevel(2)/dxlevel(1)
5240 dx2x3=dxlevel(2)/dxlevel(3)
5241 do ix2=ixfmax2,ixfmin2,-1
5242 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
5243 ix2+1,ixfmin3:ixfmax3,mag(2)) &
5244 +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
5245 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
5246 +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
5247 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
5248 end do
5249 else
5250 do ix2=ixfmax2,ixfmin2,-1
5251 w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
5252 ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
5253 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
5254 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
5255 +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
5256 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5257 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
5258 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
5259 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5260 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
5261 +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
5262 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
5263 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
5264 -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
5265 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5266 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
5267 /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
5268 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
5269 end do
5270 end if
5271 }
5272 case(4)
5273 {^iftwod
5274 ixfmin1=ixomin1+1
5275 ixfmax1=ixomax1-1
5276 ixfmin2=ixomin2-1
5277 ixfmax2=ixomax2-1
5278 if(slab_uniform) then
5279 dx2x1=dxlevel(2)/dxlevel(1)
5280 do ix2=ixfmin2,ixfmax2
5281 w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
5282 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
5283 w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
5284 end do
5285 else
5286 do ix2=ixfmin2,ixfmax2
5287 w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
5288 w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
5289 -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
5290 block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
5291 +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
5292 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
5293 /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
5294 end do
5295 end if
5296 }
5297 {^ifthreed
5298 ixfmin1=ixomin1+1
5299 ixfmax1=ixomax1-1
5300 ixfmin3=ixomin3+1
5301 ixfmax3=ixomax3-1
5302 ixfmin2=ixomin2-1
5303 ixfmax2=ixomax2-1
5304 if(slab_uniform) then
5305 dx2x1=dxlevel(2)/dxlevel(1)
5306 dx2x3=dxlevel(2)/dxlevel(3)
5307 do ix2=ixfmin2,ixfmax2
5308 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
5309 ix2-1,ixfmin3:ixfmax3,mag(2)) &
5310 -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
5311 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
5312 -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
5313 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
5314 end do
5315 else
5316 do ix2=ixfmin2,ixfmax2
5317 w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
5318 ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
5319 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
5320 block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
5321 -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
5322 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5323 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
5324 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
5325 w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
5326 block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
5327 -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
5328 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
5329 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
5330 +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
5331 w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
5332 block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
5333 /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
5334 w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
5335 end do
5336 end if
5337 }
5338 {^ifthreed
5339 case(5)
5340 ixfmin1=ixomin1+1
5341 ixfmax1=ixomax1-1
5342 ixfmin2=ixomin2+1
5343 ixfmax2=ixomax2-1
5344 ixfmin3=ixomin3+1
5345 ixfmax3=ixomax3+1
5346 if(slab_uniform) then
5347 dx3x1=dxlevel(3)/dxlevel(1)
5348 dx3x2=dxlevel(3)/dxlevel(2)
5349 do ix3=ixfmax3,ixfmin3,-1
5350 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
5351 ixfmin2:ixfmax2,ix3+1,mag(3)) &
5352 +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
5353 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
5354 +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
5355 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
5356 end do
5357 else
5358 do ix3=ixfmax3,ixfmin3,-1
5359 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
5360 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
5361 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
5362 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
5363 +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
5364 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
5365 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
5366 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
5367 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
5368 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
5369 +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
5370 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
5371 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
5372 -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
5373 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
5374 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
5375 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
5376 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
5377 end do
5378 end if
5379 case(6)
5380 ixfmin1=ixomin1+1
5381 ixfmax1=ixomax1-1
5382 ixfmin2=ixomin2+1
5383 ixfmax2=ixomax2-1
5384 ixfmin3=ixomin3-1
5385 ixfmax3=ixomax3-1
5386 if(slab_uniform) then
5387 dx3x1=dxlevel(3)/dxlevel(1)
5388 dx3x2=dxlevel(3)/dxlevel(2)
5389 do ix3=ixfmin3,ixfmax3
5390 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
5391 ixfmin2:ixfmax2,ix3-1,mag(3)) &
5392 -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
5393 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
5394 -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
5395 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
5396 end do
5397 else
5398 do ix3=ixfmin3,ixfmax3
5399 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
5400 ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
5401 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
5402 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
5403 -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
5404 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
5405 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
5406 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
5407 w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
5408 block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
5409 -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
5410 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
5411 block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
5412 +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
5413 w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
5414 block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
5415 /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
5416 w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
5417 end do
5418 end if
5419 }
5420 case default
5421 call mpistop("Special boundary is not defined for this region")
5422 end select
5423
5424 end subroutine fixdivb_boundary
5425
5426 {^nooned
5427 subroutine twofl_clean_divb_multigrid(qdt, qt, active)
5428 use mod_forest
5431 use mod_geometry
5432
5433 double precision, intent(in) :: qdt !< Current time step
5434 double precision, intent(in) :: qt !< Current time
5435 logical, intent(inout) :: active !< Output if the source is active
5436 integer :: iigrid, igrid, id
5437 integer :: n, nc, lvl, ix^l, ixc^l, idim
5438 type(tree_node), pointer :: pnode
5439 double precision :: tmp(ixg^t), grad(ixg^t, ndim)
5440 double precision :: res
5441 double precision, parameter :: max_residual = 1d-3
5442 double precision, parameter :: residual_reduction = 1d-10
5443 integer, parameter :: max_its = 50
5444 double precision :: residual_it(max_its), max_divb
5445
5446 mg%operator_type = mg_laplacian
5447
5448 ! Set boundary conditions
5449 do n = 1, 2*ndim
5450 idim = (n+1)/2
5451 select case (typeboundary(mag(idim), n))
5452 case (bc_symm)
5453 ! d/dx B = 0, take phi = 0
5454 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
5455 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
5456 case (bc_asymm)
5457 ! B = 0, so grad(phi) = 0
5458 mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
5459 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
5460 case (bc_cont)
5461 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
5462 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
5463 case (bc_special)
5464 ! Assume Dirichlet boundary conditions, derivative zero
5465 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
5466 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
5467 case (bc_periodic)
5468 ! Nothing to do here
5469 case default
5470 print *, "divb_multigrid warning: unknown b.c.: ", &
5471 typeboundary(mag(idim), n)
5472 mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
5473 mg%bc(n, mg_iphi)%bc_value = 0.0_dp
5474 end select
5475 end do
5476
5477 ix^l=ixm^ll^ladd1;
5478 max_divb = 0.0d0
5479
5480 ! Store divergence of B as right-hand side
5481 do iigrid = 1, igridstail
5482 igrid = igrids(iigrid);
5483 pnode => igrid_to_node(igrid, mype)%node
5484 id = pnode%id
5485 lvl = mg%boxes(id)%lvl
5486 nc = mg%box_size_lvl(lvl)
5487
5488 ! Geometry subroutines expect this to be set
5489 block => ps(igrid)
5490 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
5491
5492 call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
5494 mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
5495 max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
5496 end do
5497
5498 ! Solve laplacian(phi) = divB
5499 if(stagger_grid) then
5500 call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
5501 mpi_max, icomm, ierrmpi)
5502
5503 if (mype == 0) print *, "Performing multigrid divB cleaning"
5504 if (mype == 0) print *, "iteration vs residual"
5505 ! Solve laplacian(phi) = divB
5506 do n = 1, max_its
5507 call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
5508 if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
5509 if (residual_it(n) < residual_reduction * max_divb) exit
5510 end do
5511 if (mype == 0 .and. n > max_its) then
5512 print *, "divb_multigrid warning: not fully converged"
5513 print *, "current amplitude of divb: ", residual_it(max_its)
5514 print *, "multigrid smallest grid: ", &
5515 mg%domain_size_lvl(:, mg%lowest_lvl)
5516 print *, "note: smallest grid ideally has <= 8 cells"
5517 print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
5518 print *, "note: dx/dy/dz should be similar"
5519 end if
5520 else
5521 do n = 1, max_its
5522 call mg_fas_vcycle(mg, max_res=res)
5523 if (res < max_residual) exit
5524 end do
5525 if (res > max_residual) call mpistop("divb_multigrid: no convergence")
5526 end if
5527
5528
5529 ! Correct the magnetic field
5530 do iigrid = 1, igridstail
5531 igrid = igrids(iigrid);
5532 pnode => igrid_to_node(igrid, mype)%node
5533 id = pnode%id
5534
5535 ! Geometry subroutines expect this to be set
5536 block => ps(igrid)
5537 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
5538
5539 ! Compute the gradient of phi
5540 tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
5541
5542 if(stagger_grid) then
5543 do idim =1, ndim
5544 ixcmin^d=ixmlo^d-kr(idim,^d);
5545 ixcmax^d=ixmhi^d;
5546 call gradientf(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim))
5547 ! Apply the correction B* = B - gradient(phi)
5548 ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
5549 end do
5550 ! store cell-center magnetic energy
5551 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
5552 ! change cell-center magnetic field
5553 call twofl_face_to_center(ixm^ll,ps(igrid))
5554 else
5555 do idim = 1, ndim
5556 call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
5557 end do
5558 ! store cell-center magnetic energy
5559 tmp(ixm^t) = sum(ps(igrid)%w(ixm^t, mag(1:ndim))**2, dim=ndim+1)
5560 ! Apply the correction B* = B - gradient(phi)
5561 ps(igrid)%w(ixm^t, mag(1:ndim)) = &
5562 ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
5563 end if
5564
5565 if(phys_total_energy) then
5566 ! Determine magnetic energy difference
5567 tmp(ixm^t) = 0.5_dp * (sum(ps(igrid)%w(ixm^t, &
5568 mag(1:ndim))**2, dim=ndim+1) - tmp(ixm^t))
5569 ! Keep thermal pressure the same
5570 ps(igrid)%w(ixm^t, e_c_) = ps(igrid)%w(ixm^t, e_c_) + tmp(ixm^t)
5571 end if
5572 end do
5573
5574 active = .true.
5575
5576 end subroutine twofl_clean_divb_multigrid
5577 }
5578 !> get electric field though averaging neighors to update faces in CT
5579 subroutine twofl_update_faces_average(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
5581 use mod_usr_methods
5582
5583 integer, intent(in) :: ixi^l, ixo^l
5584 double precision, intent(in) :: qt,qdt
5585 ! cell-center primitive variables
5586 double precision, intent(in) :: wp(ixi^s,1:nw)
5587 type(state) :: sct, s
5588 type(ct_velocity) :: vcts
5589 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
5590 double precision, intent(inout) :: fe(ixi^s,sdim:3)
5591
5592 double precision :: circ(ixi^s,1:ndim)
5593 ! non-ideal electric field on cell edges
5594 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
5595 integer :: ix^d,ixc^l,ixa^l,i1kr^d,i2kr^d
5596 integer :: idim1,idim2,idir,iwdim1,iwdim2
5597
5598 associate(bfaces=>s%ws,x=>s%x)
5599
5600 ! Calculate contribution to FEM of each edge,
5601 ! that is, estimate value of line integral of
5602 ! electric field in the positive idir direction.
5603
5604 ! if there is resistivity, get eta J
5605 if(twofl_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
5606
5607 do idim1=1,ndim
5608 iwdim1 = mag(idim1)
5609 i1kr^d=kr(idim1,^d);
5610 do idim2=1,ndim
5611 iwdim2 = mag(idim2)
5612 i2kr^d=kr(idim2,^d);
5613 do idir=sdim,3! Direction of line integral
5614 ! Allow only even permutations
5615 if (lvc(idim1,idim2,idir)==1) then
5616 ixcmax^d=ixomax^d;
5617 ixcmin^d=ixomin^d+kr(idir,^d)-1;
5618 ! average cell-face electric field to cell edges
5619 {do ix^db=ixcmin^db,ixcmax^db\}
5620 fe(ix^d,idir)=quarter*&
5621 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
5622 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
5623 ! add resistive electric field at cell edges E=-vxB+eta J
5624 if(twofl_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
5625 ! times time step and edge length
5626 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
5627 {end do\}
5628 end if
5629 end do
5630 end do
5631 end do
5632
5633 ! allow user to change inductive electric field, especially for boundary driven applications
5634 if(associated(usr_set_electric_field)) &
5635 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
5636
5637 circ(ixi^s,1:ndim)=zero
5638
5639 ! Calculate circulation on each face
5640 do idim1=1,ndim ! Coordinate perpendicular to face
5641 ixcmax^d=ixomax^d;
5642 ixcmin^d=ixomin^d-kr(idim1,^d);
5643 do idim2=1,ndim
5644 ixa^l=ixc^l-kr(idim2,^d);
5645 do idir=sdim,3 ! Direction of line integral
5646 ! Assemble indices
5647 if(lvc(idim1,idim2,idir)==1) then
5648 ! Add line integrals in direction idir
5649 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5650 +(fe(ixc^s,idir)&
5651 -fe(ixa^s,idir))
5652 else if(lvc(idim1,idim2,idir)==-1) then
5653 ! Add line integrals in direction idir
5654 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5655 -(fe(ixc^s,idir)&
5656 -fe(ixa^s,idir))
5657 end if
5658 end do
5659 end do
5660 {do ix^db=ixcmin^db,ixcmax^db\}
5661 ! Divide by the area of the face to get dB/dt
5662 if(s%surfaceC(ix^d,idim1) > smalldouble) then
5663 ! Time update cell-face magnetic field component
5664 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
5665 end if
5666 {end do\}
5667 end do
5668
5669 end associate
5670
5671 end subroutine twofl_update_faces_average
5672
5673 !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
5674 subroutine twofl_update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
5676 use mod_usr_methods
5677 use mod_geometry
5678
5679 integer, intent(in) :: ixi^l, ixo^l
5680 double precision, intent(in) :: qt, qdt
5681 ! cell-center primitive variables
5682 double precision, intent(in) :: wp(ixi^s,1:nw)
5683 type(state) :: sct, s
5684 type(ct_velocity) :: vcts
5685 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
5686 double precision, intent(inout) :: fe(ixi^s,sdim:3)
5687
5688 double precision :: circ(ixi^s,1:ndim)
5689 ! electric field at cell centers
5690 double precision :: ecc(ixi^s,sdim:3)
5691 double precision :: ein(ixi^s,sdim:3)
5692 ! gradient of E at left and right side of a cell face
5693 double precision :: el(ixi^s),er(ixi^s)
5694 ! gradient of E at left and right side of a cell corner
5695 double precision :: elc,erc
5696 ! non-ideal electric field on cell edges
5697 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
5698 ! current on cell edges
5699 double precision :: jce(ixi^s,sdim:3)
5700 ! location at cell faces
5701 double precision :: xs(ixgs^t,1:ndim)
5702 double precision :: gradi(ixgs^t)
5703 integer :: ixc^l,ixa^l
5704 integer :: idim1,idim2,idir,iwdim1,iwdim2,ix^d,i1kr^d,i2kr^d
5705
5706 associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm,wcts=>sct%ws)
5707
5708 ! if there is resistivity, get eta J
5709 if(twofl_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
5710
5711 if(b0field) then
5712 {do ix^db=iximin^db,iximax^db\}
5713 ! Calculate electric field at cell centers
5714 {^ifthreed
5715 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_)
5716 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_)
5717 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_)
5718 }
5719 {^iftwod
5720 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
5721 }
5722 {^ifoned
5723 ecc(ix^d,3)=0.d0
5724 }
5725 {end do\}
5726 else
5727 {do ix^db=iximin^db,iximax^db\}
5728 ! Calculate electric field at cell centers
5729 {^ifthreed
5730 ecc(ix^d,1)=wp(ix^d,b2_)*wp(ix^d,m3_)-wp(ix^d,b3_)*wp(ix^d,m2_)
5731 ecc(ix^d,2)=wp(ix^d,b3_)*wp(ix^d,m1_)-wp(ix^d,b1_)*wp(ix^d,m3_)
5732 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
5733 }
5734 {^iftwod
5735 ecc(ix^d,3)=wp(ix^d,b1_)*wp(ix^d,m2_)-wp(ix^d,b2_)*wp(ix^d,m1_)
5736 }
5737 {^ifoned
5738 ecc(ix^d,3)=0.d0
5739 }
5740 {end do\}
5741 end if
5742
5743 ! Calculate contribution to FEM of each edge,
5744 ! that is, estimate value of line integral of
5745 ! electric field in the positive idir direction.
5746 ! evaluate electric field along cell edges according to equation (41)
5747 do idim1=1,ndim
5748 iwdim1 = mag(idim1)
5749 i1kr^d=kr(idim1,^d);
5750 do idim2=1,ndim
5751 iwdim2 = mag(idim2)
5752 i2kr^d=kr(idim2,^d);
5753 do idir=sdim,3 ! Direction of line integral
5754 ! Allow only even permutations
5755 if (lvc(idim1,idim2,idir)==1) then
5756 ixcmax^d=ixomax^d;
5757 ixcmin^d=ixomin^d+kr(idir,^d)-1;
5758 ! Assemble indices
5759 ! average cell-face electric field to cell edges
5760 {do ix^db=ixcmin^db,ixcmax^db\}
5761 fe(ix^d,idir)=quarter*&
5762 (fc(ix^d,iwdim1,idim2)+fc({ix^d+i1kr^d},iwdim1,idim2)&
5763 -fc(ix^d,iwdim2,idim1)-fc({ix^d+i2kr^d},iwdim2,idim1))
5764 {end do\}
5765 ! add slope in idim2 direction from equation (50)
5766 ixamin^d=ixcmin^d;
5767 ixamax^d=ixcmax^d+i1kr^d;
5768 {do ix^db=ixamin^db,ixamax^db\}
5769 el(ix^d)=fc(ix^d,iwdim1,idim2)-ecc(ix^d,idir)
5770 er(ix^d)=fc(ix^d,iwdim1,idim2)-ecc({ix^d+i2kr^d},idir)
5771 {end do\}
5772 {!dir$ ivdep
5773 do ix^db=ixcmin^db,ixcmax^db\}
5774 if(vnorm(ix^d,idim1)>0.d0) then
5775 elc=el(ix^d)
5776 else if(vnorm(ix^d,idim1)<0.d0) then
5777 elc=el({ix^d+i1kr^d})
5778 else
5779 elc=0.5d0*(el(ix^d)+el({ix^d+i1kr^d}))
5780 end if
5781 if(vnorm({ix^d+i2kr^d},idim1)>0.d0) then
5782 erc=er(ix^d)
5783 else if(vnorm({ix^d+i2kr^d},idim1)<0.d0) then
5784 erc=er({ix^d+i1kr^d})
5785 else
5786 erc=0.5d0*(er(ix^d)+er({ix^d+i1kr^d}))
5787 end if
5788 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
5789 {end do\}
5790
5791 ! add slope in idim1 direction from equation (50)
5792 ixamin^d=ixcmin^d;
5793 ixamax^d=ixcmax^d+i2kr^d;
5794 {do ix^db=ixamin^db,ixamax^db\}
5795 el(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc(ix^d,idir)
5796 er(ix^d)=-fc(ix^d,iwdim2,idim1)-ecc({ix^d+i1kr^d},idir)
5797 {end do\}
5798 {!dir$ ivdep
5799 do ix^db=ixcmin^db,ixcmax^db\}
5800 if(vnorm(ix^d,idim2)>0.d0) then
5801 elc=el(ix^d)
5802 else if(vnorm(ix^d,idim2)<0.d0) then
5803 elc=el({ix^d+i2kr^d})
5804 else
5805 elc=0.5d0*(el(ix^d)+el({ix^d+i2kr^d}))
5806 end if
5807 if(vnorm({ix^d+i1kr^d},idim2)>0.d0) then
5808 erc=er(ix^d)
5809 else if(vnorm({ix^d+i1kr^d},idim2)<0.d0) then
5810 erc=er({ix^d+i2kr^d})
5811 else
5812 erc=0.5d0*(er(ix^d)+er({ix^d+i2kr^d}))
5813 end if
5814 fe(ix^d,idir)=fe(ix^d,idir)+0.25d0*(elc+erc)
5815 ! add resistive electric field at cell edges E=-vxB+eta J
5816 if(twofl_eta/=zero) fe(ix^d,idir)=fe(ix^d,idir)+e_resi(ix^d,idir)
5817 ! times time step and edge length
5818 fe(ix^d,idir)=fe(ix^d,idir)*qdt*s%dsC(ix^d,idir)
5819 {end do\}
5820 end if
5821 end do
5822 end do
5823 end do
5824
5825 ! allow user to change inductive electric field, especially for boundary driven applications
5826 if(associated(usr_set_electric_field)) &
5827 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
5828
5829 circ(ixi^s,1:ndim)=zero
5830
5831 ! Calculate circulation on each face
5832 do idim1=1,ndim ! Coordinate perpendicular to face
5833 ixcmax^d=ixomax^d;
5834 ixcmin^d=ixomin^d-kr(idim1,^d);
5835 do idim2=1,ndim
5836 ixa^l=ixc^l-kr(idim2,^d);
5837 do idir=sdim,3 ! Direction of line integral
5838 ! Assemble indices
5839 if(lvc(idim1,idim2,idir)==1) then
5840 ! Add line integrals in direction idir
5841 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5842 +(fe(ixc^s,idir)&
5843 -fe(ixa^s,idir))
5844 else if(lvc(idim1,idim2,idir)==-1) then
5845 ! Add line integrals in direction idir
5846 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
5847 -(fe(ixc^s,idir)&
5848 -fe(ixa^s,idir))
5849 end if
5850 end do
5851 end do
5852 {do ix^db=ixcmin^db,ixcmax^db\}
5853 ! Divide by the area of the face to get dB/dt
5854 if(s%surfaceC(ix^d,idim1) > smalldouble) then
5855 ! Time update cell-face magnetic field component
5856 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
5857 end if
5858 {end do\}
5859 end do
5860
5861 end associate
5862
5863 end subroutine twofl_update_faces_contact
5864
5865 !> update faces
5866 subroutine twofl_update_faces_hll(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
5868 use mod_usr_methods
5870
5871 integer, intent(in) :: ixi^l, ixo^l
5872 double precision, intent(in) :: qt, qdt
5873 ! cell-center primitive variables
5874 double precision, intent(in) :: wp(ixi^s,1:nw)
5875 type(state) :: sct, s
5876 type(ct_velocity) :: vcts
5877 double precision, intent(in) :: fc(ixi^s,1:nwflux,1:ndim)
5878 double precision, intent(inout) :: fe(ixi^s,sdim:3)
5879
5880 double precision :: vtill(ixi^s,2)
5881 double precision :: vtilr(ixi^s,2)
5882 double precision :: bfacetot(ixi^s,ndim)
5883 double precision :: btill(ixi^s,ndim)
5884 double precision :: btilr(ixi^s,ndim)
5885 double precision :: cp(ixi^s,2)
5886 double precision :: cm(ixi^s,2)
5887 double precision :: circ(ixi^s,1:ndim)
5888 ! non-ideal electric field on cell edges
5889 double precision, dimension(ixI^S,sdim:3) :: e_resi, e_ambi
5890 integer :: hxc^l,ixc^l,ixcp^l,jxc^l,ixcm^l
5891 integer :: idim1,idim2,idir,ix^d
5892
5893 associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
5894 cbarmax=>vcts%cbarmax)
5895
5896 ! Calculate contribution to FEM of each edge,
5897 ! that is, estimate value of line integral of
5898 ! electric field in the positive idir direction.
5899
5900 ! Loop over components of electric field
5901
5902 ! idir: electric field component we need to calculate
5903 ! idim1: directions in which we already performed the reconstruction
5904 ! idim2: directions in which we perform the reconstruction
5905
5906 ! if there is resistivity, get eta J
5907 if(twofl_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,wp,sct,s,e_resi)
5908
5909 do idir=sdim,3
5910 ! Indices
5911 ! idir: electric field component
5912 ! idim1: one surface
5913 ! idim2: the other surface
5914 ! cyclic permutation: idim1,idim2,idir=1,2,3
5915 ! Velocity components on the surface
5916 ! follow cyclic premutations:
5917 ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
5918
5919 ixcmax^d=ixomax^d;
5920 ixcmin^d=ixomin^d-1+kr(idir,^d);
5921
5922 ! Set indices and directions
5923 idim1=mod(idir,3)+1
5924 idim2=mod(idir+1,3)+1
5925
5926 jxc^l=ixc^l+kr(idim1,^d);
5927 ixcp^l=ixc^l+kr(idim2,^d);
5928
5929 ! Reconstruct transverse transport velocities
5930 call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
5931 vtill(ixi^s,2),vtilr(ixi^s,2))
5932
5933 call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
5934 vtill(ixi^s,1),vtilr(ixi^s,1))
5935
5936 ! Reconstruct magnetic fields
5937 ! Eventhough the arrays are larger, reconstruct works with
5938 ! the limits ixG.
5939 if(b0field) then
5940 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)+block%B0(ixi^s,idim1,idim1)
5941 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)+block%B0(ixi^s,idim2,idim2)
5942 else
5943 bfacetot(ixi^s,idim1)=bfacesct(ixi^s,idim1)
5944 bfacetot(ixi^s,idim2)=bfacesct(ixi^s,idim2)
5945 end if
5946 call reconstruct(ixi^l,ixc^l,idim2,bfacetot(ixi^s,idim1),&
5947 btill(ixi^s,idim1),btilr(ixi^s,idim1))
5948
5949 call reconstruct(ixi^l,ixc^l,idim1,bfacetot(ixi^s,idim2),&
5950 btill(ixi^s,idim2),btilr(ixi^s,idim2))
5951
5952 ! Take the maximum characteristic
5953
5954 cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
5955 cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
5956
5957 cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
5958 cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
5959
5960
5961 ! Calculate eletric field
5962 fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
5963 + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
5964 - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
5965 /(cp(ixc^s,1)+cm(ixc^s,1)) &
5966 +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
5967 + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
5968 - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
5969 /(cp(ixc^s,2)+cm(ixc^s,2))
5970
5971 ! add resistive electric field at cell edges E=-vxB+eta J
5972 if(twofl_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+e_resi(ixc^s,idir)
5973 fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
5974
5975 if (.not.slab) then
5976 where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
5977 fe(ixc^s,idir)=zero
5978 end where
5979 end if
5980
5981 end do
5982
5983 ! allow user to change inductive electric field, especially for boundary driven applications
5984 if(associated(usr_set_electric_field)) &
5985 call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
5986
5987 circ(ixi^s,1:ndim)=zero
5988
5989 ! Calculate circulation on each face: interal(fE dot dl)
5990 do idim1=1,ndim ! Coordinate perpendicular to face
5991 ixcmax^d=ixomax^d;
5992 ixcmin^d=ixomin^d-kr(idim1,^d);
5993 do idim2=1,ndim
5994 do idir=sdim,3 ! Direction of line integral
5995 ! Assemble indices
5996 if(lvc(idim1,idim2,idir)/=0) then
5997 hxc^l=ixc^l-kr(idim2,^d);
5998 ! Add line integrals in direction idir
5999 circ(ixc^s,idim1)=circ(ixc^s,idim1)&
6000 +lvc(idim1,idim2,idir)&
6001 *(fe(ixc^s,idir)&
6002 -fe(hxc^s,idir))
6003 end if
6004 end do
6005 end do
6006 {do ix^db=ixcmin^db,ixcmax^db\}
6007 ! Divide by the area of the face to get dB/dt
6008 if(s%surfaceC(ix^d,idim1) > smalldouble) then
6009 ! Time update cell-face magnetic field component
6010 bfaces(ix^d,idim1)=bfaces(ix^d,idim1)-circ(ix^d,idim1)/s%surfaceC(ix^d,idim1)
6011 end if
6012 {end do\}
6013 end do
6014
6015 end associate
6016 end subroutine twofl_update_faces_hll
6017
6018 !> calculate eta J at cell edges
6019 subroutine get_resistive_electric_field(ixI^L,ixO^L,wp,sCT,s,jce)
6021 use mod_usr_methods
6022 use mod_geometry
6023
6024 integer, intent(in) :: ixi^l, ixo^l
6025 ! cell-center primitive variables
6026 double precision, intent(in) :: wp(ixi^s,1:nw)
6027 type(state), intent(in) :: sct, s
6028 ! current on cell edges
6029 double precision :: jce(ixi^s,sdim:3)
6030
6031 ! current on cell centers
6032 double precision :: jcc(ixi^s,7-2*ndir:3)
6033 ! location at cell faces
6034 double precision :: xs(ixgs^t,1:ndim)
6035 ! resistivity
6036 double precision :: eta(ixi^s)
6037 double precision :: gradi(ixgs^t)
6038 integer :: ix^d,ixc^l,ixa^l,ixb^l,idir,idirmin,idim1,idim2
6039
6040 associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
6041 ! calculate current density at cell edges
6042 jce=0.d0
6043 do idim1=1,ndim
6044 do idim2=1,ndim
6045 do idir=sdim,3
6046 if (lvc(idim1,idim2,idir)==0) cycle
6047 ixcmax^d=ixomax^d;
6048 ixcmin^d=ixomin^d+kr(idir,^d)-1;
6049 ixbmax^d=ixcmax^d-kr(idir,^d)+1;
6050 ixbmin^d=ixcmin^d;
6051 ! current at transverse faces
6052 xs(ixb^s,:)=x(ixb^s,:)
6053 xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
6054 call gradientf(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,2)
6055 if (lvc(idim1,idim2,idir)==1) then
6056 jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
6057 else
6058 jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
6059 end if
6060 end do
6061 end do
6062 end do
6063 ! get resistivity
6064 if(twofl_eta>zero)then
6065 jce(ixi^s,:)=jce(ixi^s,:)*twofl_eta
6066 else
6067 ixa^l=ixo^l^ladd1;
6068 call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
6069 call usr_special_resistivity(wp,ixi^l,ixa^l,idirmin,x,jcc,eta)
6070 ! calcuate eta on cell edges
6071 do idir=sdim,3
6072 ixcmax^d=ixomax^d;
6073 ixcmin^d=ixomin^d+kr(idir,^d)-1;
6074 jcc(ixc^s,idir)=0.d0
6075 {do ix^db=0,1\}
6076 if({ ix^d==1 .and. ^d==idir | .or.}) cycle
6077 ixamin^d=ixcmin^d+ix^d;
6078 ixamax^d=ixcmax^d+ix^d;
6079 jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
6080 {end do\}
6081 jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
6082 jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
6083 end do
6084 end if
6085
6086 end associate
6087 end subroutine get_resistive_electric_field
6088
6089 !> calculate cell-center values from face-center values
6090 subroutine twofl_face_to_center(ixO^L,s)
6092 ! Non-staggered interpolation range
6093 integer, intent(in) :: ixo^l
6094 type(state) :: s
6095
6096 integer :: fxo^l, gxo^l, hxo^l, jxo^l, kxo^l, idim
6097
6098 associate(w=>s%w, ws=>s%ws)
6099
6100 ! calculate cell-center values from face-center values in 2nd order
6101 do idim=1,ndim
6102 ! Displace index to the left
6103 ! Even if ixI^L is the full size of the w arrays, this is ok
6104 ! because the staggered arrays have an additional place to the left.
6105 hxo^l=ixo^l-kr(idim,^d);
6106 ! Interpolate to cell barycentre using arithmetic average
6107 ! This might be done better later, to make the method less diffusive.
6108 w(ixo^s,mag(idim))=half/s%surface(ixo^s,idim)*&
6109 (ws(ixo^s,idim)*s%surfaceC(ixo^s,idim)&
6110 +ws(hxo^s,idim)*s%surfaceC(hxo^s,idim))
6111 end do
6112
6113 ! calculate cell-center values from face-center values in 4th order
6114 !do idim=1,ndim
6115 ! gxO^L=ixO^L-2*kr(idim,^D);
6116 ! hxO^L=ixO^L-kr(idim,^D);
6117 ! jxO^L=ixO^L+kr(idim,^D);
6118
6119 ! ! Interpolate to cell barycentre using fourth order central formula
6120 ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
6121 ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
6122 ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
6123 ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
6124 ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
6125 !end do
6126
6127 ! calculate cell-center values from face-center values in 6th order
6128 !do idim=1,ndim
6129 ! fxO^L=ixO^L-3*kr(idim,^D);
6130 ! gxO^L=ixO^L-2*kr(idim,^D);
6131 ! hxO^L=ixO^L-kr(idim,^D);
6132 ! jxO^L=ixO^L+kr(idim,^D);
6133 ! kxO^L=ixO^L+2*kr(idim,^D);
6134
6135 ! ! Interpolate to cell barycentre using sixth order central formula
6136 ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
6137 ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
6138 ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
6139 ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
6140 ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
6141 ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
6142 ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
6143 !end do
6144
6145 end associate
6146
6147 end subroutine twofl_face_to_center
6148
6149 !> calculate magnetic field from vector potential
6150 subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
6153
6154 integer, intent(in) :: ixis^l, ixi^l, ixo^l
6155 double precision, intent(inout) :: ws(ixis^s,1:nws)
6156 double precision, intent(in) :: x(ixi^s,1:ndim)
6157
6158 double precision :: adummy(ixis^s,1:3)
6159
6160 call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
6161
6162 end subroutine b_from_vector_potential
6163
6164 subroutine hyperdiffusivity_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
6167 integer, intent(in) :: ixi^l, ixo^l
6168 double precision, intent(in) :: w(ixi^s,1:nw)
6169 double precision, intent(in) :: x(ixi^s,1:ndim)
6170 double precision, intent(in) :: dx^d
6171 double precision, intent(inout) :: dtnew
6172
6173 double precision :: nu(ixi^s),tmp(ixi^s),rho(ixi^s),temp(ixi^s)
6174 double precision :: divv(ixi^s,1:ndim)
6175 double precision :: vel(ixi^s,1:ndir)
6176 double precision :: csound(ixi^s),csound_dim(ixi^s,1:ndim)
6177 double precision :: dxarr(ndim)
6178 double precision :: maxcoef
6179 integer :: ixoo^l, hxb^l, hx^l, ii, jj
6180
6181
6182 ^d&dxarr(^d)=dx^d;
6183 maxcoef = smalldouble
6184
6185 ! charges
6186 call twofl_get_v_c(w,x,ixi^l,ixi^l,vel)
6187 call get_rhoc_tot(w,x,ixi^l,ixi^l,rho)
6188 call twofl_get_csound2_c_from_conserved(w,x,ixi^l,ixi^l,csound)
6189 csound(ixi^s) = sqrt(csound(ixi^s)) + sqrt(twofl_mag_en_all(w,ixi^l,ixi^l) /rho(ixi^s))
6190 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6191 do ii=1,ndim
6192 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s,ii))
6193 hxmin^d=iximin^d+1;
6194 hxmax^d=iximax^d-1;
6195 hxb^l=hx^l-kr(ii,^d);
6196 csound_dim(hx^s,ii) = (csound(hxb^s)+csound(hx^s))/2d0
6197 enddo
6198 call twofl_get_temp_c_pert_from_etot(w, x, ixi^l, ixi^l, temp)
6199 do ii=1,ndim
6200 !TODO the following is copied
6201 !rho_c
6202 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,rho_c_), ii, tmp(ixi^s))
6203 nu(ixo^s) = c_hyp(rho_c_) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6204 c_shk(rho_c_) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6205 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6206
6207 !TH c
6208 call hyp_coeff(ixi^l, ixoo^l, temp(ixi^s), ii, tmp(ixi^s))
6209 nu(ixo^s) = c_hyp(e_c_) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6210 c_shk(e_c_) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6211 nu(ixo^s) = nu(ixo^s) * rho(ixo^s) * rc/(twofl_gamma-1d0)
6212 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6213
6214 !visc c
6215 do jj=1,ndir
6216 call hyp_coeff(ixi^l, ixoo^l, vel(ixi^s,jj), ii, tmp(ixi^s))
6217 nu(ixo^s) = c_hyp(mom_c(jj)) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6218 c_shk(mom_c(jj)) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6219 nu(ixo^s) = nu(ixo^s) * rho(ixo^s)
6220 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6221 enddo
6222
6223 ! Ohmic
6224 do jj=1,ndir
6225 if(ii .ne. jj) then
6226 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,mag(jj)), ii, tmp(ixi^s))
6227 nu(ixo^s) = c_hyp(mag(jj)) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6228 c_shk(mag(jj)) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6229 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6230 endif
6231 enddo
6232
6233 enddo
6234
6235 !TODO the following is copied, as charges, and as in add_source!
6236 ! neutrals
6237 call twofl_get_v_n(w,x,ixi^l,ixi^l,vel)
6238 call twofl_get_csound_n(w,x,ixi^l,ixi^l,csound)
6239 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6240 do ii=1,ndim
6241 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s,ii))
6242 hxmin^d=iximin^d+1;
6243 hxmax^d=iximax^d-1;
6244 hxb^l=hx^l-kr(ii,^d);
6245 csound_dim(hx^s,ii) = (csound(hxb^s)+csound(hx^s))/2d0
6246 enddo
6247 call get_rhon_tot(w,x,ixi^l,ixo^l,rho)
6248 call twofl_get_temp_n_pert_from_etot(w, x, ixi^l, ixi^l, temp)
6249 do ii=1,ndim
6250 !rho_n
6251 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,rho_n_), ii, tmp(ixi^s))
6252 nu(ixo^s) = c_hyp(rho_n_) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6253 c_shk(rho_n_) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6254 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6255
6256 !TH n
6257 call hyp_coeff(ixi^l, ixoo^l, temp(ixi^s), ii, tmp(ixi^s))
6258 nu(ixo^s) = c_hyp(e_n_) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6259 c_shk(e_n_) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6260 nu(ixo^s) = nu(ixo^s) * rho(ixo^s) * rn/(twofl_gamma-1d0)
6261 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6262
6263 !visc n
6264 do jj=1,ndir
6265 call hyp_coeff(ixi^l, ixoo^l, vel(ixi^s,jj), ii, tmp(ixi^s))
6266 nu(ixo^s) = c_hyp(mom_n(jj)) * csound_dim(ixo^s,ii) * dxlevel(ii) * tmp(ixo^s) + &
6267 c_shk(mom_n(jj)) * (dxlevel(ii)**2) *divv(ixo^s,ii)
6268 nu(ixo^s) = nu(ixo^s) * rho(ixo^s)
6269 maxcoef = max(maxcoef,maxval(nu(ixo^s)))
6270 enddo
6271 enddo
6272
6273 dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**2/maxcoef,dtnew)
6274 end subroutine hyperdiffusivity_get_dt
6275
6276 subroutine add_source_hyperdiffusive(qdt,ixI^L,ixO^L,w,wCT,x)
6279
6280 integer, intent(in) :: ixi^l, ixo^l
6281 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
6282 double precision, intent(inout) :: w(ixi^s,1:nw)
6283 double precision, intent(in) :: wct(ixi^s,1:nw)
6284
6285 double precision :: divv(ixi^s,1:ndim)
6286 double precision :: vel(ixi^s,1:ndir)
6287 double precision :: csound(ixi^s),csound_dim(ixi^s,1:ndim)
6288 integer :: ii,ixoo^l,hxb^l,hx^l
6289 double precision :: rho(ixi^s)
6290
6291 call twofl_get_v_c(wct,x,ixi^l,ixi^l,vel)
6292 call get_rhoc_tot(wct,x,ixi^l,ixi^l,rho)
6293 call twofl_get_csound2_c_from_conserved(wct,x,ixi^l,ixi^l,csound)
6294 csound(ixi^s) = sqrt(csound(ixi^s)) + sqrt(twofl_mag_en_all(wct,ixi^l,ixi^l) /rho(ixi^s))
6295 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6296 do ii=1,ndim
6297 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s,ii))
6298 hxmin^d=iximin^d+1;
6299 hxmax^d=iximax^d-1;
6300 hxb^l=hx^l-kr(ii,^d);
6301 csound_dim(hx^s,ii) = (csound(hxb^s)+csound(hx^s))/2d0
6302 enddo
6304 call add_viscosity_hyper_source(rho,mom_c(1), e_c_)
6305 call add_th_cond_c_hyper_source(rho)
6306 call add_ohmic_hyper_source()
6307
6308 call twofl_get_v_n(wct,x,ixi^l,ixi^l,vel)
6309 call twofl_get_csound_n(wct,x,ixi^l,ixi^l,csound)
6310 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6311 do ii=1,ndim
6312 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s,ii))
6313 hxmin^d=iximin^d+1;
6314 hxmax^d=iximax^d-1;
6315 hxb^l=hx^l-kr(ii,^d);
6316 csound_dim(hx^s,ii) = (csound(hxb^s)+csound(hx^s))/2d0
6317 enddo
6319 call get_rhon_tot(wct,x,ixi^l,ixi^l,rho)
6320 call add_viscosity_hyper_source(rho,mom_n(1), e_n_)
6321 call add_th_cond_n_hyper_source(rho)
6322
6323 contains
6324
6325 subroutine add_density_hyper_source(index_rho)
6326 integer, intent(in) :: index_rho
6327
6328 double precision :: nu(ixI^S), tmp(ixI^S)
6329
6330 do ii=1,ndim
6331 call hyp_coeff(ixi^l, ixoo^l, wct(ixi^s,index_rho), ii, tmp(ixi^s))
6332 nu(ixoo^s) = c_hyp(index_rho) * csound_dim(ixoo^s,ii) * dxlevel(ii) * tmp(ixoo^s) + &
6333 c_shk(index_rho) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6334 !print*, "IXOO HYP ", ixOO^L, " IDIMM ", ii
6335 call second_same_deriv(ixi^l, ixoo^l, nu(ixi^s), wct(ixi^s,index_rho), ii, tmp)
6336
6337 w(ixo^s,index_rho) = w(ixo^s,index_rho) + qdt * tmp(ixo^s)
6338 !print*, "RHO ", index_rho, maxval(abs(tmp(ixO^S)))
6339 enddo
6340 end subroutine add_density_hyper_source
6341
6342 subroutine add_th_cond_c_hyper_source(var2)
6343 double precision, intent(in) :: var2(ixI^S)
6344 double precision :: nu(ixI^S), tmp(ixI^S), var(ixI^S)
6345 call twofl_get_temp_c_pert_from_etot(wct, x, ixi^l, ixi^l, var)
6346 do ii=1,ndim
6347 call hyp_coeff(ixi^l, ixoo^l, var(ixi^s), ii, tmp(ixi^s))
6348 nu(ixoo^s) = c_hyp(e_c_) * csound_dim(ixoo^s,ii) * dxlevel(ii) * tmp(ixoo^s) + &
6349 c_shk(e_c_) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6350 call second_same_deriv2(ixi^l, ixoo^l, nu(ixi^s), var2(ixi^s) ,var(ixi^s), ii, tmp)
6351 w(ixo^s,e_c_) = w(ixo^s,e_c_) + qdt * tmp(ixo^s) * rc/(twofl_gamma-1d0)
6352 !print*, "TH C ", maxval(abs(tmp(ixO^S)))
6353 enddo
6354 end subroutine add_th_cond_c_hyper_source
6355
6356 subroutine add_th_cond_n_hyper_source(var2)
6357 double precision, intent(in) :: var2(ixI^S)
6358 double precision :: nu(ixI^S), tmp(ixI^S), var(ixI^S)
6359 call twofl_get_temp_n_pert_from_etot(wct, x, ixi^l, ixi^l, var)
6360 do ii=1,ndim
6361 call hyp_coeff(ixi^l, ixoo^l, var(ixi^s), ii, tmp(ixi^s))
6362 nu(ixoo^s) = c_hyp(e_n_) * csound_dim(ixoo^s,ii) * dxlevel(ii) * tmp(ixoo^s) + &
6363 c_shk(e_n_) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6364 call second_same_deriv2(ixi^l, ixoo^l, nu(ixi^s), var2(ixi^s) ,var(ixi^s), ii, tmp)
6365 w(ixo^s,e_n_) = w(ixo^s,e_n_) + qdt * tmp(ixo^s) * rn/(twofl_gamma-1d0)
6366 !print*, "TH N ", maxval(abs(tmp(ixO^S)))
6367 enddo
6368 end subroutine add_th_cond_n_hyper_source
6369
6370 subroutine add_viscosity_hyper_source(rho,index_mom1, index_e)
6371 double precision, intent(in) :: rho(ixI^S)
6372 integer, intent(in) :: index_mom1, index_e
6373
6374 double precision :: nu(ixI^S,1:ndir,1:ndim), tmp(ixI^S),tmp2(ixI^S)
6375 integer :: jj
6376
6377 do jj=1,ndir
6378 do ii=1,ndim
6379 call hyp_coeff(ixi^l, ixoo^l, vel(ixi^s,jj), ii, tmp(ixi^s))
6380 nu(ixoo^s,jj,ii) = c_hyp(index_mom1-1+jj) * csound_dim(ixoo^s,ii) * dxlevel(ii) * tmp(ixoo^s) + &
6381 c_shk(index_mom1-1+jj) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6382 enddo
6383 enddo
6384
6385 do jj=1,ndir
6386 do ii=1,ndim
6387 call second_same_deriv2(ixi^l, ixoo^l, nu(ixi^s,jj,ii), rho(ixi^s), vel(ixi^s,jj), ii, tmp)
6388 call second_same_deriv2(ixi^l, ixoo^l, nu(ixi^s,jj,ii), wct(ixi^s,index_mom1-1+jj), vel(ixi^s,jj), ii, tmp2)
6389 if(ii .eq. jj) then
6390 w(ixo^s,index_mom1-1+jj) = w(ixo^s,index_mom1-1+jj) + qdt * tmp(ixo^s)
6391 w(ixo^s,index_e) = w(ixo^s,index_e) + qdt * tmp2(ixo^s)
6392
6393 else
6394 w(ixo^s,index_mom1-1+jj) = w(ixo^s,index_mom1-1+jj) + 0.5*qdt * tmp(ixo^s)
6395 w(ixo^s,index_e) = w(ixo^s,index_e) + 0.5*qdt * tmp2(ixo^s)
6396 call second_cross_deriv2(ixi^l, ixoo^l, nu(ixi^s,ii,jj), rho(ixi^s), vel(ixi^s,ii), jj, ii, tmp)
6397 w(ixo^s,index_mom1-1+jj) = w(ixo^s,index_mom1-1+jj) + 0.5*qdt * tmp(ixo^s)
6398 call second_cross_deriv2(ixi^l, ixoo^l, nu(ixi^s,jj,ii), wct(ixi^s,index_mom1-1+jj), vel(ixi^s,jj), ii, jj, tmp2)
6399 w(ixo^s,index_e) = w(ixo^s,index_e) + 0.5*qdt * tmp2(ixo^s)
6400 endif
6401
6402 enddo
6403 enddo
6404
6405 end subroutine add_viscosity_hyper_source
6406
6407 subroutine add_ohmic_hyper_source()
6408 double precision :: nu(ixI^S,1:ndir,1:ndim), tmp(ixI^S)
6409 integer :: jj
6410
6411 do jj=1,ndir
6412 do ii=1,ndim
6413 if(ii .ne. jj) then
6414 call hyp_coeff(ixi^l, ixoo^l, wct(ixi^s,mag(jj)), ii, tmp(ixi^s))
6415 nu(ixoo^s,jj,ii) = c_hyp(mag(jj)) * csound_dim(ixoo^s,ii) * dxlevel(ii) * tmp(ixoo^s) + &
6416 c_shk(mag(jj)) * (dxlevel(ii)**2) *divv(ixoo^s,ii)
6417 endif
6418 enddo
6419 enddo
6420
6421 do jj=1,ndir
6422 do ii=1,ndim
6423 if(ii .ne. jj) then
6424 !mag field
6425 call second_same_deriv(ixi^l, ixoo^l, nu(ixi^s,jj,ii), wct(ixi^s,mag(jj)), ii, tmp)
6426 w(ixo^s,mag(jj)) = w(ixo^s,mag(jj)) + qdt * tmp(ixo^s)
6427 call second_cross_deriv(ixi^l, ixoo^l, nu(ixi^s,ii,jj), wct(ixi^s,mag(ii)), jj, ii, tmp)
6428 w(ixo^s,mag(jj)) = w(ixo^s,mag(jj)) + qdt * tmp(ixo^s)
6429 !in the total energy
6430 call second_same_deriv(ixi^l, ixoo^l, nu(ixi^s,jj,ii), wct(ixi^s,mag(jj)), ii, tmp)
6431 w(ixo^s,e_c_) = w(ixo^s,e_c_) + qdt * tmp(ixo^s)
6432 call second_cross_deriv2(ixi^l, ixoo^l, nu(ixi^s,ii,jj), wct(ixi^s,mag(jj)), wct(ixi^s,mag(ii)), jj, ii, tmp)
6433 w(ixo^s,e_c_) = w(ixo^s,e_c_) + qdt * tmp(ixo^s)
6434 endif
6435
6436 enddo
6437 enddo
6438
6439 end subroutine add_ohmic_hyper_source
6440
6441 end subroutine add_source_hyperdiffusive
6442
6443 function dump_hyperdiffusivity_coef_x(ixI^L,ixO^L, w, x, nwc) result(wnew)
6446 integer, intent(in) :: ixI^L, ixO^L, nwc
6447 double precision, intent(in) :: w(ixI^S, 1:nw)
6448 double precision, intent(in) :: x(ixI^S,1:ndim)
6449 double precision :: wnew(ixO^S, 1:nwc)
6450
6451 if(nw .ne. nwc) call mpistop("nw != nwc")
6452 wnew(ixo^s,1:nw) = dump_hyperdiffusivity_coef_dim(ixi^l,ixo^l, w, x, 1)
6453
6454 end function dump_hyperdiffusivity_coef_x
6455
6456 function dump_hyperdiffusivity_coef_y(ixI^L,ixO^L, w, x, nwc) result(wnew)
6459 integer, intent(in) :: ixI^L, ixO^L, nwc
6460 double precision, intent(in) :: w(ixI^S, 1:nw)
6461 double precision, intent(in) :: x(ixI^S,1:ndim)
6462 double precision :: wnew(ixO^S, 1:nwc)
6463
6464 if(nw .ne. nwc) call mpistop("nw != nwc")
6465 wnew(ixo^s,1:nw) = dump_hyperdiffusivity_coef_dim(ixi^l,ixo^l, w, x, 2)
6466
6467 end function dump_hyperdiffusivity_coef_y
6468
6469 function dump_hyperdiffusivity_coef_z(ixI^L,ixO^L, w, x, nwc) result(wnew)
6472 integer, intent(in) :: ixI^L, ixO^L, nwc
6473 double precision, intent(in) :: w(ixI^S, 1:nw)
6474 double precision, intent(in) :: x(ixI^S,1:ndim)
6475 double precision :: wnew(ixO^S, 1:nwc)
6476
6477 if(nw .ne. nwc) call mpistop("nw != nwc")
6478 wnew(ixo^s,1:nw) = dump_hyperdiffusivity_coef_dim(ixi^l,ixo^l, w, x, 3)
6479
6480 end function dump_hyperdiffusivity_coef_z
6481
6482 function dump_hyperdiffusivity_coef_dim(ixI^L,ixOP^L, w, x, ii) result(wnew)
6485 integer, intent(in) :: ixI^L, ixOP^L, ii
6486 double precision, intent(in) :: w(ixI^S, 1:nw)
6487 double precision, intent(in) :: x(ixI^S,1:ndim)
6488 double precision :: wnew(ixOP^S, 1:nw)
6489
6490 double precision :: nu(ixI^S),tmp(ixI^S),rho(ixI^S),temp(ixI^S)
6491 double precision :: divv(ixI^S)
6492 double precision :: vel(ixI^S,1:ndir)
6493 double precision :: csound(ixI^S),csound_dim(ixI^S)
6494 double precision :: dxarr(ndim)
6495 integer :: ixOO^L, hxb^L, hx^L, jj, ixO^L
6496
6497 ! this is done because of save_physical_boundary = true
6498 ixomin^d=max(ixopmin^d,iximin^d+3);
6499 ixomax^d=min(ixopmax^d,iximax^d-3);
6500
6501 wnew(ixop^s,1:nw) = 0d0
6502
6503 ! charges
6504 call twofl_get_temp_c_pert_from_etot(w, x, ixi^l, ixi^l, temp)
6505 call twofl_get_v_c(w,x,ixi^l,ixi^l,vel)
6506 call get_rhoc_tot(w,x,ixi^l,ixi^l,rho)
6507 call twofl_get_csound2_c_from_conserved(w,x,ixi^l,ixi^l,csound)
6508 csound(ixi^s) = sqrt(csound(ixi^s)) + sqrt(twofl_mag_en_all(w,ixi^l,ixi^l) /rho(ixi^s))
6509 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6510 !for dim
6511 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s))
6512 hxmin^d=iximin^d+1;
6513 hxmax^d=iximax^d-1;
6514 hxb^l=hx^l-kr(ii,^d);
6515 csound_dim(hx^s) = (csound(hxb^s)+csound(hx^s))/2d0
6516
6517 !TODO the following is copied
6518 !rho_c
6519 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,rho_c_), ii, tmp(ixi^s))
6520 nu(ixo^s) = c_hyp(rho_c_) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6521 c_shk(rho_c_) * (dxlevel(ii)**2) *divv(ixo^s)
6522
6523 wnew(ixo^s,rho_c_) = nu(ixo^s)
6524
6525 !TH c
6526 call hyp_coeff(ixi^l, ixoo^l, temp(ixi^s), ii, tmp(ixi^s))
6527 nu(ixo^s) = c_hyp(e_c_) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6528 c_shk(e_c_) * (dxlevel(ii)**2) *divv(ixo^s)
6529 nu(ixo^s) = nu(ixo^s) * rho(ixo^s) * rc/(twofl_gamma-1d0)
6530 wnew(ixo^s,e_c_) = nu(ixo^s)
6531
6532 !visc c
6533 do jj=1,ndir
6534 call hyp_coeff(ixi^l, ixoo^l, vel(ixi^s,jj), ii, tmp(ixi^s))
6535 nu(ixo^s) = c_hyp(mom_c(jj)) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6536 c_shk(mom_c(jj)) * (dxlevel(ii)**2) *divv(ixo^s)
6537 nu(ixo^s) = nu(ixo^s) * rho(ixo^s)
6538 wnew(ixo^s,mom_c(jj)) = nu(ixo^s)
6539 enddo
6540
6541 ! Ohmic
6542 do jj=1,ndir
6543 if(ii .ne. jj) then
6544 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,mag(jj)), ii, tmp(ixi^s))
6545 nu(ixo^s) = c_hyp(mag(jj)) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6546 c_shk(mag(jj)) * (dxlevel(ii)**2) *divv(ixo^s)
6547 wnew(ixo^s,mag(jj)) = nu(ixo^s)
6548 endif
6549 enddo
6550
6551 !end for dim
6552
6553 ! neutrals
6554 call get_rhon_tot(w,x,ixi^l,ixo^l,rho)
6555 call twofl_get_temp_n_pert_from_etot(w, x, ixi^l, ixi^l, temp)
6556 call twofl_get_v_n(w,x,ixi^l,ixi^l,vel)
6557 call twofl_get_csound_n(w,x,ixi^l,ixi^l,csound)
6558 csound(ixi^s) = csound(ixi^s) + sqrt(sum(vel(ixi^s,1:ndir)**2 ,dim=ndim+1))
6559 !for dim
6560 call div_vel_coeff(ixi^l, ixoo^l, vel, ii, divv(ixi^s))
6561 hxb^l=ixoo^l-kr(ii,^d);
6562 csound_dim(ixoo^s) = (csound(hxb^s)+csound(ixoo^s))/2d0
6563 !rho_n
6564 call hyp_coeff(ixi^l, ixoo^l, w(ixi^s,rho_n_), ii, tmp(ixi^s))
6565 nu(ixo^s) = c_hyp(rho_n_) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6566 c_shk(rho_n_) * (dxlevel(ii)**2) *divv(ixoo^s)
6567 wnew(ixo^s,rho_n_) = nu(ixo^s)
6568
6569 !TH n
6570 call hyp_coeff(ixi^l, ixoo^l, temp(ixi^s), ii, tmp(ixi^s))
6571 nu(ixo^s) = c_hyp(e_n_) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6572 c_shk(e_n_) * (dxlevel(ii)**2) *divv(ixo^s)
6573 nu(ixo^s) = nu(ixo^s) * rho(ixo^s) * rn/(twofl_gamma-1d0)
6574 wnew(ixo^s,e_n_) = nu(ixo^s)
6575
6576 !visc n
6577 do jj=1,ndir
6578 call hyp_coeff(ixi^l, ixoo^l, vel(ixi^s,jj), ii, tmp(ixi^s))
6579 nu(ixo^s) = c_hyp(mom_n(jj)) * csound_dim(ixo^s) * dxlevel(ii) * tmp(ixo^s) + &
6580 c_shk(mom_n(jj)) * (dxlevel(ii)**2) *divv(ixo^s)
6581 nu(ixo^s) = nu(ixo^s) * rho(ixo^s)
6582 wnew(ixo^s,mom_n(jj)) = nu(ixo^s)
6583 enddo
6584 !end for dim
6585
6586 end function dump_hyperdiffusivity_coef_dim
6587
6588 function dump_coll_terms(ixI^L,ixO^L, w, x, nwc) result(wnew)
6590 integer, intent(in) :: ixI^L,ixO^L, nwc
6591 double precision, intent(in) :: w(ixI^S, 1:nw)
6592 double precision, intent(in) :: x(ixI^S,1:ndim)
6593 double precision :: wnew(ixO^S, 1:nwc)
6594 double precision :: tmp(ixI^S),tmp2(ixI^S)
6595
6596 call get_alpha_coll(ixi^l, ixo^l, w, x, tmp(ixi^s))
6597 wnew(ixo^s,1)= tmp(ixo^s)
6598 call get_gamma_ion_rec(ixi^l, ixo^l, w, x, tmp(ixi^s), tmp2(ixi^s))
6599 wnew(ixo^s,2)= tmp(ixo^s)
6600 wnew(ixo^s,3)= tmp2(ixo^s)
6601
6602 end function dump_coll_terms
6603
6604 subroutine get_gamma_ion_rec(ixI^L, ixO^L, w, x, gamma_rec, gamma_ion)
6606
6607 integer, intent(in) :: ixi^l, ixo^l
6608 double precision, intent(in) :: w(ixi^s,1:nw)
6609 double precision, intent(in) :: x(ixi^s,1:ndim)
6610 double precision, intent(out) :: gamma_rec(ixi^s),gamma_ion(ixi^s)
6611 ! calculations are done in S.I. units
6612 double precision, parameter :: a = 2.91e-14, & !m3/s
6613 k = 0.39, &
6614 xx = 0.232, &
6615 eion = 13.6 ! eV
6616 double precision, parameter :: echarge=1.6022d-19 !C
6617 double precision :: rho(ixi^s), tmp(ixi^s)
6618
6619 call twofl_get_pthermal_c(w,x,ixi^l,ixo^l,tmp)
6620 call get_rhoc_tot(w,x,ixi^l,ixo^l,rho)
6621 tmp(ixo^s) = tmp(ixo^s)/(rc * rho(ixo^s))
6622
6623 !transform to SI units
6624 tmp(ixo^s) = tmp(ixo^s) * unit_temperature * kb_si/echarge !* BK/ECHARGE means K to eV
6625 !number electrons rho_c = n_e * MH, in normalized units MH=1 and n = rho
6626 rho(ixo^s) = rho(ixo^s) * unit_numberdensity
6627 if(.not. si_unit) then
6628 !1/cm^3 = 1e6/m^3
6629 rho(ixo^s) = rho(ixo^s) * 1d6
6630 endif
6631 gamma_rec(ixo^s) = rho(ixo^s) /sqrt(tmp(ixo^s)) * 2.6e-19
6632 gamma_ion(ixo^s) = ((rho(ixo^s) * a) /(xx + eion/tmp(ixo^s))) * ((eion/tmp(ixo^s))**k) * exp(-eion/tmp(ixo^s))
6633 ! see Voronov table: valid for temp min = 1eV(approx 11605 K), Temp max = 20KeV
6634 !to normalized
6635 gamma_rec(ixo^s) = gamma_rec(ixo^s) * unit_time
6636 gamma_ion(ixo^s) = gamma_ion(ixo^s) * unit_time
6637
6638 if (associated(usr_mask_gamma_ion_rec)) then
6639 call usr_mask_gamma_ion_rec(ixi^l,ixo^l,w,x,gamma_ion, gamma_rec)
6640 end if
6641 end subroutine get_gamma_ion_rec
6642
6643 subroutine get_alpha_coll(ixI^L, ixO^L, w, x, alpha)
6645 integer, intent(in) :: ixi^l, ixo^l
6646 double precision, intent(in) :: w(ixi^s,1:nw)
6647 double precision, intent(in) :: x(ixi^s,1:ndim)
6648 double precision, intent(out) :: alpha(ixi^s)
6650 alpha(ixo^s) = twofl_alpha_coll
6651 else
6652 call get_alpha_coll_plasma(ixi^l, ixo^l, w, x, alpha)
6653 endif
6654 if (associated(usr_mask_alpha)) then
6655 call usr_mask_alpha(ixi^l,ixo^l,w,x,alpha)
6656 end if
6657 end subroutine get_alpha_coll
6658
6659 subroutine get_alpha_coll_plasma(ixI^L, ixO^L, w, x, alpha)
6661 integer, intent(in) :: ixi^l, ixo^l
6662 double precision, intent(in) :: w(ixi^s,1:nw)
6663 double precision, intent(in) :: x(ixi^s,1:ndim)
6664 double precision, intent(out) :: alpha(ixi^s)
6665 double precision :: pe(ixi^s),rho(ixi^s), tmp(ixi^s), tmp2(ixi^s)
6666
6667 double precision :: sigma_in = 1e-19 ! m^2
6668 ! make calculation in SI physical units
6669
6670 call twofl_get_pthermal_c(w,x,ixi^l,ixo^l,pe)
6671 call get_rhoc_tot(w,x,ixi^l,ixo^l,rho)
6672 tmp(ixo^s) = pe(ixo^s)/(rc * rho(ixo^s))
6673 call twofl_get_pthermal_n(w,x,ixi^l,ixo^l,pe)
6674 call get_rhon_tot(w,x,ixi^l,ixo^l,rho)
6675 tmp2(ixo^s) = pe(ixo^s)/(rn * rho(ixo^s))
6676 alpha(ixo^s) = (2d0/(mp_si**(3d0/2) * sqrt(dpi))*sqrt(0.5*(tmp(ixo^s)+tmp2(ixo^s))*unit_temperature*kb_si) * sigma_in)*unit_time * unit_density
6677 if(.not. si_unit) then
6678 alpha(ixo^s) = alpha(ixo^s) * 1d3 ! this comes from unit_density: g/cm^3 = 1e-3 kg/m^3
6679 endif
6680
6681 end subroutine get_alpha_coll_plasma
6682
6683 subroutine calc_mult_factor1(ixI^L, ixO^L, step_dt, JJ, res)
6684 integer, intent(in) :: ixi^l, ixo^l
6685 double precision, intent(in) :: step_dt
6686 double precision, intent(in) :: jj(ixi^s)
6687 double precision, intent(out) :: res(ixi^s)
6688
6689 res(ixo^s) = step_dt/(1d0 + step_dt * jj(ixo^s))
6690
6691 end subroutine calc_mult_factor1
6692
6693 subroutine calc_mult_factor2(ixI^L, ixO^L, step_dt, JJ, res)
6694 integer, intent(in) :: ixi^l, ixo^l
6695 double precision, intent(in) :: step_dt
6696 double precision, intent(in) :: jj(ixi^s)
6697 double precision, intent(out) :: res(ixi^s)
6698
6699 res(ixo^s) = (1d0 - exp(-step_dt * jj(ixo^s)))/jj(ixo^s)
6700
6701 end subroutine calc_mult_factor2
6702
6703 subroutine advance_implicit_grid(ixI^L, ixO^L, w, wout, x, dtfactor,qdt)
6705 integer, intent(in) :: ixi^l, ixo^l
6706 double precision, intent(in) :: qdt
6707 double precision, intent(in) :: dtfactor
6708 double precision, intent(in) :: w(ixi^s,1:nw)
6709 double precision, intent(in) :: x(ixi^s,1:ndim)
6710 double precision, intent(out) :: wout(ixi^s,1:nw)
6711
6712 integer :: idir
6713 double precision :: tmp(ixi^s),tmp1(ixi^s),tmp2(ixi^s),tmp3(ixi^s),tmp4(ixi^s),tmp5(ixi^s)
6714 double precision :: v_c(ixi^s,ndir), v_n(ixi^s,ndir)
6715 double precision :: rhon(ixi^s), rhoc(ixi^s), alpha(ixi^s)
6716 double precision, allocatable :: gamma_rec(:^d&), gamma_ion(:^D&)
6717
6718 !TODO latest changes sets already wout to w in implicit update (see where psb=psa)
6719 ! commment out setting mag and density when they are not modified here
6720
6721 ! copy vars at the indices which are not updated here: mag. field
6722 wout(ixo^s,mag(:)) = w(ixo^s,mag(:))
6723
6724 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
6725 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
6726 !update density
6727 if(twofl_coll_inc_ionrec) then
6728 allocate(gamma_ion(ixi^s), gamma_rec(ixi^s))
6729 call get_gamma_ion_rec(ixi^l, ixo^l, w, x, gamma_rec, gamma_ion)
6730 tmp2(ixo^s) = gamma_rec(ixo^s) + gamma_ion(ixo^s)
6731 call calc_mult_factor(ixi^l, ixo^l, dtfactor * qdt, tmp2, tmp3)
6732 tmp(ixo^s) = (-gamma_ion(ixo^s) * rhon(ixo^s) + &
6733 gamma_rec(ixo^s) * rhoc(ixo^s))
6734 wout(ixo^s,rho_n_) = w(ixo^s,rho_n_) + tmp(ixo^s) * tmp3(ixo^s)
6735 wout(ixo^s,rho_c_) = w(ixo^s,rho_c_) - tmp(ixo^s) * tmp3(ixo^s)
6736 else
6737 wout(ixo^s,rho_n_) = w(ixo^s,rho_n_)
6738 wout(ixo^s,rho_c_) = w(ixo^s,rho_c_)
6739 endif
6740
6741 call get_alpha_coll(ixi^l, ixo^l, w, x, alpha)
6742
6743 !-J11 + J12 for momentum and kinetic energy
6744 tmp2(ixo^s) = alpha(ixo^s) * (rhon(ixo^s) + rhoc(ixo^s))
6745 if(twofl_coll_inc_ionrec) then
6746 tmp2(ixo^s) = tmp2(ixo^s) + gamma_ion(ixo^s) + gamma_rec(ixo^s)
6747 endif
6748 call calc_mult_factor(ixi^l, ixo^l, dtfactor * qdt, tmp2, tmp3)
6749
6750 ! momentum update
6751 do idir=1,ndir
6752
6753 tmp(ixo^s) = alpha(ixo^s)* (-rhoc(ixo^s) * w(ixo^s,mom_n(idir)) + rhon(ixo^s) * w(ixo^s,mom_c(idir)))
6754 if(twofl_coll_inc_ionrec) then
6755 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * w(ixo^s,mom_n(idir)) + gamma_rec(ixo^s) * w(ixo^s,mom_c(idir))
6756 endif
6757
6758 wout(ixo^s,mom_n(idir)) = w(ixo^s,mom_n(idir)) + tmp(ixo^s) * tmp3(ixo^s)
6759 wout(ixo^s,mom_c(idir)) = w(ixo^s,mom_c(idir)) - tmp(ixo^s) * tmp3(ixo^s)
6760 enddo
6761
6762 ! energy update
6763
6764 ! kinetic energy update
6765 if(.not. phys_internal_e) then
6766 ! E_tot includes kinetic energy
6767 tmp1(ixo^s) = twofl_kin_en_n(w,ixi^l,ixo^l)
6768 tmp2(ixo^s) = twofl_kin_en_c(w,ixi^l,ixo^l)
6769 tmp4(ixo^s) = w(ixo^s,e_n_) - tmp1(ixo^s) !E_tot - E_kin
6770 tmp5(ixo^s) = w(ixo^s,e_c_) - tmp2(ixo^s)
6771 if(phys_total_energy) then
6772 tmp5(ixo^s) = tmp5(ixo^s) - twofl_mag_en(w,ixi^l,ixo^l)
6773 endif
6774
6775 !!implicit update
6776 tmp(ixo^s) = alpha(ixo^s)*(-rhoc(ixo^s) * tmp1(ixo^s) + rhon(ixo^s) * tmp2(ixo^s))
6777 if(twofl_coll_inc_ionrec) then
6778 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * tmp1(ixo^s) + gamma_rec(ixo^s) * tmp2(ixo^s)
6779 endif
6780
6781 wout(ixo^s,e_n_) = w(ixo^s,e_n_) + tmp(ixo^s) * tmp3(ixo^s)
6782 wout(ixo^s,e_c_) = w(ixo^s,e_c_) - tmp(ixo^s) * tmp3(ixo^s)
6783
6784 else
6785 tmp4(ixo^s) = w(ixo^s,e_n_)
6786 tmp5(ixo^s) = w(ixo^s,e_c_)
6787 ! calculate velocities, using the already updated variables
6788 call twofl_get_v_n(wout,x,ixi^l,ixo^l,v_n)
6789 call twofl_get_v_c(wout,x,ixi^l,ixo^l,v_c)
6790 tmp1(ixo^s) = alpha(ixo^s) * rhoc(ixo^s) * rhon(ixo^s)
6791 tmp2(ixo^s) = tmp1(ixo^s)
6792 if(twofl_coll_inc_ionrec) then
6793 tmp1(ixo^s) = tmp1(ixo^s) + rhoc(ixo^s) * gamma_rec(ixo^s)
6794 tmp2(ixo^s) = tmp2(ixo^s) + rhon(ixo^s) * gamma_ion(ixo^s)
6795 endif
6796
6797 tmp(ixo^s) = 0.5d0 * sum((v_c(ixo^s,1:ndir) - v_n(ixo^s,1:ndir))**2, dim=ndim+1) &
6798 * dtfactor * qdt
6799 wout(ixo^s,e_n_) = w(ixo^s,e_n_) + tmp(ixo^s)*tmp1(ixo^s)
6800 wout(ixo^s,e_c_) = w(ixo^s,e_c_) + tmp(ixo^s)*tmp2(ixo^s)
6801 endif
6802
6803 !update internal energy
6804 if(twofl_coll_inc_te) then
6805 if(has_equi_pe_n0) then
6806 tmp2(ixo^s)= block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
6807 endif
6808 if(has_equi_pe_c0) then
6809 tmp3(ixo^s)=block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
6810 endif
6811 if (twofl_equi_thermal) then
6812 tmp(ixo^s) = alpha(ixo^s) *(-1d0/rn*(rhoc(ixo^s) * tmp4(ixo^s) + &
6813 tmp2(ixo^s)*w(ixo^s,rho_c_)) + 1d0/rc*(rhon(ixo^s) * tmp5(ixo^s) +&
6814 tmp3(ixo^s)*w(ixo^s,rho_n_)))
6815 endif
6816 if(has_equi_pe_n0) then
6817 tmp4(ixo^s) = tmp2(ixo^s) + tmp4(ixo^s)
6818 endif
6819 if(has_equi_pe_c0) then
6820 tmp5(ixo^s) = tmp3(ixo^s) + tmp5(ixo^s)
6821 endif
6822 if (.not. twofl_equi_thermal) then
6823 tmp(ixo^s) = alpha(ixo^s) *(-rhoc(ixo^s)/rn * tmp4(ixo^s) + rhon(ixo^s)/rc * tmp5(ixo^s))
6824 endif
6825 tmp2(ixo^s) = alpha(ixo^s) * (rhon(ixo^s)/rc + rhoc(ixo^s)/rn)
6826 if(twofl_coll_inc_ionrec) then
6827 tmp2(ixo^s) = tmp2(ixo^s) + gamma_rec(ixo^s)/rc + gamma_ion(ixo^s)/rn
6828 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s)/rn * tmp4(ixo^s) + gamma_rec(ixo^s)/rc * tmp5(ixo^s)
6829 endif
6830 call calc_mult_factor(ixi^l, ixo^l, dtfactor * qdt, tmp2, tmp3)
6831 wout(ixo^s,e_n_) = wout(ixo^s,e_n_)+tmp(ixo^s)*tmp3(ixo^s)
6832 wout(ixo^s,e_c_) = wout(ixo^s,e_c_)-tmp(ixo^s)*tmp3(ixo^s)
6833 endif
6834 if(twofl_coll_inc_ionrec) then
6835 deallocate(gamma_ion, gamma_rec)
6836 endif
6837 end subroutine advance_implicit_grid
6838
6839 !> Implicit solve of psb=psa+dtfactor*dt*F_im(psb)
6840 subroutine twofl_implicit_coll_terms_update(dtfactor,qdt,qtC,psb,psa)
6843
6844 type(state), target :: psa(max_blocks)
6845 type(state), target :: psb(max_blocks)
6846 double precision, intent(in) :: qdt
6847 double precision, intent(in) :: qtc
6848 double precision, intent(in) :: dtfactor
6849
6850 integer :: iigrid, igrid
6851 !print*, "IMPL call ", it
6852
6853 call getbc(global_time,0.d0,psa,1,nw)
6854 !$OMP PARALLEL DO PRIVATE(igrid)
6855 do iigrid=1,igridstail; igrid=igrids(iigrid);
6856 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
6857 block=>psa(igrid)
6858 call advance_implicit_grid(ixg^ll, ixg^ll, psa(igrid)%w, psb(igrid)%w, psa(igrid)%x, dtfactor,qdt)
6859 end do
6860 !$OMP END PARALLEL DO
6861
6862 end subroutine twofl_implicit_coll_terms_update
6863
6864 !> inplace update of psa==>F_im(psa)
6865 subroutine twofl_evaluate_implicit(qtC,psa)
6867 type(state), target :: psa(max_blocks)
6868 double precision, intent(in) :: qtc
6869
6870 integer :: iigrid, igrid, level
6871
6872 !$OMP PARALLEL DO PRIVATE(igrid)
6873 do iigrid=1,igridstail; igrid=igrids(iigrid);
6874 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
6875 block=>psa(igrid)
6876 call coll_terms(ixg^ll,ixm^ll,psa(igrid)%w,psa(igrid)%x)
6877 end do
6878 !$OMP END PARALLEL DO
6879
6880 end subroutine twofl_evaluate_implicit
6881
6882 subroutine coll_terms(ixI^L,ixO^L,w,x)
6884 integer, intent(in) :: ixi^l, ixo^l
6885 double precision, intent(inout) :: w(ixi^s, 1:nw)
6886 double precision, intent(in) :: x(ixi^s,1:ndim)
6887
6888 integer :: idir
6889 double precision :: tmp(ixi^s),tmp1(ixi^s),tmp2(ixi^s),tmp3(ixi^s),tmp4(ixi^s),tmp5(ixi^s)
6890 !double precision :: v_c(ixI^S,ndir), v_n(ixI^S,ndir)
6891 double precision, allocatable :: v_c(:^d&,:), v_n(:^D&,:)
6892 double precision, allocatable :: rho_c1(:^d&), rho_n1(:^D&)
6893 double precision :: rhon(ixi^s), rhoc(ixi^s), alpha(ixi^s)
6894 double precision, allocatable :: gamma_rec(:^d&), gamma_ion(:^D&)
6895
6896 ! copy density before overwrite
6897 if(twofl_equi_thermal) then
6898 allocate(rho_n1(ixi^s), rho_c1(ixi^s))
6899 rho_n1(ixo^s) = w(ixo^s,rho_n_)
6900 rho_c1(ixo^s) = w(ixo^s,rho_c_)
6901 endif
6902
6903 ! get total density before overwrite density
6904 call get_rhon_tot(w,x,ixi^l,ixo^l,rhon)
6905 call get_rhoc_tot(w,x,ixi^l,ixo^l,rhoc)
6906 if(phys_internal_e) then
6907 ! get velocity before overwrite momentum
6908 allocate(v_n(ixi^s,ndir), v_c(ixi^s,ndir))
6909 call twofl_get_v_n(w,x,ixi^l,ixo^l,v_n)
6910 call twofl_get_v_c(w,x,ixi^l,ixo^l,v_c)
6911 else
6912 ! get ke before overwrite density and momentum
6913 tmp1(ixo^s) = twofl_kin_en_n(w,ixi^l,ixo^l)
6914 tmp2(ixo^s) = twofl_kin_en_c(w,ixi^l,ixo^l)
6915 endif
6916
6917 !update density
6918 if(twofl_coll_inc_ionrec) then
6919 allocate(gamma_ion(ixi^s), gamma_rec(ixi^s))
6920 call get_gamma_ion_rec(ixi^l, ixo^l, w, x, gamma_rec, gamma_ion)
6921 tmp(ixo^s) = -gamma_ion(ixo^s) * rhon(ixo^s) + &
6922 gamma_rec(ixo^s) * rhoc(ixo^s)
6923 w(ixo^s,rho_n_) = tmp(ixo^s)
6924 w(ixo^s,rho_c_) = -tmp(ixo^s)
6925 else
6926 w(ixo^s,rho_n_) = 0d0
6927 w(ixo^s,rho_c_) = 0d0
6928
6929 endif
6930
6931 call get_alpha_coll(ixi^l, ixo^l, w, x, alpha)
6932
6933 ! momentum update
6934 do idir=1,ndir
6935
6936 tmp(ixo^s) = alpha(ixo^s)* (-rhoc(ixo^s) * w(ixo^s,mom_n(idir)) + rhon(ixo^s) * w(ixo^s,mom_c(idir)))
6937 if(twofl_coll_inc_ionrec) then
6938 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * w(ixo^s,mom_n(idir)) + gamma_rec(ixo^s) * w(ixo^s,mom_c(idir))
6939 endif
6940
6941 w(ixo^s,mom_n(idir)) = tmp(ixo^s)
6942 w(ixo^s,mom_c(idir)) = -tmp(ixo^s)
6943 enddo
6944
6945 ! energy update
6946
6947 ! kinetic energy update
6948 if(.not. phys_internal_e) then
6949 ! E_tot includes kinetic energy
6950 tmp4(ixo^s) = w(ixo^s,e_n_) - tmp1(ixo^s) !E_tot - E_kin
6951 tmp5(ixo^s) = w(ixo^s,e_c_) - tmp2(ixo^s)
6952 if(phys_total_energy) then
6953 tmp5(ixo^s) = tmp5(ixo^s) - twofl_mag_en(w,ixi^l,ixo^l)
6954 endif
6955 ! tmp4 = eint_n, tmp5 = eint_c
6956 ! tmp1 = ke_n, tmp2 = ke_c
6957 tmp(ixo^s) = alpha(ixo^s)*(-rhoc(ixo^s) * tmp1(ixo^s) + rhon(ixo^s) * tmp2(ixo^s))
6958 if(twofl_coll_inc_ionrec) then
6959 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * tmp1(ixo^s) + gamma_rec(ixo^s) * tmp2(ixo^s)
6960 endif
6961
6962 w(ixo^s,e_n_) = tmp(ixo^s)
6963 w(ixo^s,e_c_) = -tmp(ixo^s)
6964
6965 else
6966 tmp4(ixo^s) = w(ixo^s,e_n_)
6967 tmp5(ixo^s) = w(ixo^s,e_c_)
6968 tmp1(ixo^s) = alpha(ixo^s) * rhoc(ixo^s) * rhon(ixo^s)
6969 tmp2(ixo^s) = tmp1(ixo^s)
6970 if(twofl_coll_inc_ionrec) then
6971 tmp1(ixo^s) = tmp1(ixo^s) + rhoc(ixo^s) * gamma_rec(ixo^s)
6972 tmp2(ixo^s) = tmp2(ixo^s) + rhon(ixo^s) * gamma_ion(ixo^s)
6973 endif
6974
6975 tmp(ixo^s) = 0.5d0 * sum((v_c(ixo^s,1:ndir) - v_n(ixo^s,1:ndir))**2, dim=ndim+1)
6976 w(ixo^s,e_n_) = tmp(ixo^s)*tmp1(ixo^s)
6977 w(ixo^s,e_c_) = tmp(ixo^s)*tmp2(ixo^s)
6978 endif
6979
6980 !update internal energy
6981 if(twofl_coll_inc_te) then
6982
6983 if(has_equi_pe_n0) then
6984 tmp2(ixo^s)= block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
6985 endif
6986 if(has_equi_pe_c0) then
6987 tmp3(ixo^s)=block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
6988 endif
6989 if (twofl_equi_thermal) then
6990 tmp(ixo^s) = alpha(ixo^s) *(-1d0/rn*(rhoc(ixo^s) * tmp4(ixo^s) + &
6991 tmp2(ixo^s)*rho_c1(ixo^s)) + 1d0/rc*(rhon(ixo^s) * tmp5(ixo^s) +&
6992 tmp3(ixo^s)*rho_n1(ixo^s)))
6993 endif
6994 if(has_equi_pe_n0) then
6995 tmp4(ixo^s) = tmp2(ixo^s) + tmp4(ixo^s)
6996 endif
6997 if(has_equi_pe_c0) then
6998 tmp5(ixo^s) = tmp3(ixo^s) + tmp5(ixo^s)
6999 endif
7000 if (.not. twofl_equi_thermal) then
7001 tmp(ixo^s) = alpha(ixo^s) *(-rhoc(ixo^s)/rn * tmp4(ixo^s) + rhon(ixo^s)/rc * tmp5(ixo^s))
7002 endif
7003
7004 if(twofl_coll_inc_ionrec) then
7005 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s)/rn * tmp4(ixo^s) + gamma_rec(ixo^s)/rc * tmp5(ixo^s)
7006 endif
7007
7008 w(ixo^s,e_n_) = w(ixo^s,e_n_)+tmp(ixo^s)
7009 w(ixo^s,e_c_) = w(ixo^s,e_c_)-tmp(ixo^s)
7010 endif
7011 if(twofl_coll_inc_ionrec) then
7012 deallocate(gamma_ion, gamma_rec)
7013 endif
7014 if(phys_internal_e) then
7015 deallocate(v_n, v_c)
7016 endif
7017 if(twofl_equi_thermal) then
7018 deallocate(rho_n1, rho_c1)
7019 endif
7020 !set contribution to mag field
7021 w(ixo^s,mag(1:ndir)) = 0d0
7022
7023 end subroutine coll_terms
7024
7025 subroutine twofl_explicit_coll_terms_update(qdt,ixI^L,ixO^L,w,wCT,x)
7027
7028 integer, intent(in) :: ixi^l, ixo^l
7029 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
7030 double precision, intent(inout) :: w(ixi^s,1:nw)
7031 double precision, intent(in) :: wct(ixi^s,1:nw)
7032
7033 integer :: idir
7034 double precision :: tmp(ixi^s),tmp1(ixi^s),tmp2(ixi^s),tmp3(ixi^s),tmp4(ixi^s),tmp5(ixi^s)
7035 double precision :: v_c(ixi^s,ndir), v_n(ixi^s,ndir)
7036 double precision :: rhon(ixi^s), rhoc(ixi^s), alpha(ixi^s)
7037 double precision, allocatable :: gamma_rec(:^d&), gamma_ion(:^D&)
7038
7039 call get_rhon_tot(wct,x,ixi^l,ixo^l,rhon)
7040 call get_rhoc_tot(wct,x,ixi^l,ixo^l,rhoc)
7041 !update density
7042 if(twofl_coll_inc_ionrec) then
7043 allocate(gamma_ion(ixi^s), gamma_rec(ixi^s))
7044 call get_gamma_ion_rec(ixi^l, ixo^l, wct, x, gamma_rec, gamma_ion)
7045 tmp(ixo^s) = qdt *(-gamma_ion(ixo^s) * rhon(ixo^s) + &
7046 gamma_rec(ixo^s) * rhoc(ixo^s))
7047 w(ixo^s,rho_n_) = w(ixo^s,rho_n_) + tmp(ixo^s)
7048 w(ixo^s,rho_c_) = w(ixo^s,rho_c_) - tmp(ixo^s)
7049 endif
7050
7051 call get_alpha_coll(ixi^l, ixo^l, wct, x, alpha)
7052
7053 ! momentum update
7054 do idir=1,ndir
7055
7056 tmp(ixo^s) = alpha(ixo^s)* (-rhoc(ixo^s) * wct(ixo^s,mom_n(idir)) + rhon(ixo^s) * wct(ixo^s,mom_c(idir)))
7057 if(twofl_coll_inc_ionrec) then
7058 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * wct(ixo^s,mom_n(idir)) + gamma_rec(ixo^s) * wct(ixo^s,mom_c(idir))
7059 endif
7060 tmp(ixo^s) =tmp(ixo^s) * qdt
7061
7062 w(ixo^s,mom_n(idir)) = w(ixo^s,mom_n(idir)) + tmp(ixo^s)
7063 w(ixo^s,mom_c(idir)) = w(ixo^s,mom_c(idir)) - tmp(ixo^s)
7064 enddo
7065
7066 ! energy update
7067
7068 ! kinetic energy update
7069 if(.not. phys_internal_e) then
7070 ! E_tot includes kinetic energy
7071 tmp1(ixo^s) = twofl_kin_en_n(wct,ixi^l,ixo^l)
7072 tmp2(ixo^s) = twofl_kin_en_c(wct,ixi^l,ixo^l)
7073 tmp4(ixo^s) = wct(ixo^s,e_n_) - tmp1(ixo^s) !E_tot - E_kin
7074 tmp5(ixo^s) = wct(ixo^s,e_c_) - tmp2(ixo^s)
7075 if(phys_total_energy) then
7076 tmp5(ixo^s) = tmp5(ixo^s) - twofl_mag_en(wct,ixi^l,ixo^l)
7077 endif
7078
7079 tmp(ixo^s) = alpha(ixo^s)*(-rhoc(ixo^s) * tmp1(ixo^s) + rhon(ixo^s) * tmp2(ixo^s))
7080 if(twofl_coll_inc_ionrec) then
7081 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s) * tmp1(ixo^s) + gamma_rec(ixo^s) * tmp2(ixo^s)
7082 endif
7083 tmp(ixo^s) =tmp(ixo^s) * qdt
7084
7085 w(ixo^s,e_n_) = w(ixo^s,e_n_) + tmp(ixo^s)
7086 w(ixo^s,e_c_) = w(ixo^s,e_c_) - tmp(ixo^s)
7087
7088 else
7089 tmp4(ixo^s) = w(ixo^s,e_n_)
7090 tmp5(ixo^s) = w(ixo^s,e_c_)
7091 call twofl_get_v_n(wct,x,ixi^l,ixo^l,v_n)
7092 call twofl_get_v_c(wct,x,ixi^l,ixo^l,v_c)
7093 tmp1(ixo^s) = alpha(ixo^s) * rhoc(ixo^s) * rhon(ixo^s)
7094 tmp2(ixo^s) = tmp1(ixo^s)
7095 if(twofl_coll_inc_ionrec) then
7096 tmp1(ixo^s) = tmp1(ixo^s) + rhoc(ixo^s) * gamma_rec(ixo^s)
7097 tmp2(ixo^s) = tmp2(ixo^s) + rhon(ixo^s) * gamma_ion(ixo^s)
7098 endif
7099
7100 tmp(ixo^s) = 0.5d0 * sum((v_c(ixo^s,1:ndir) - v_n(ixo^s,1:ndir))**2, dim=ndim+1) * qdt
7101 w(ixo^s,e_n_) = w(ixo^s,e_n_) + tmp(ixo^s)*tmp1(ixo^s)
7102 w(ixo^s,e_c_) = w(ixo^s,e_c_) + tmp(ixo^s)*tmp2(ixo^s)
7103 endif
7104
7105 !update internal energy
7106 if(twofl_coll_inc_te) then
7107 if(has_equi_pe_n0) then
7108 tmp2(ixo^s)= block%equi_vars(ixo^s,equi_pe_n0_,0)*inv_gamma_1
7109 endif
7110 if(has_equi_pe_c0) then
7111 tmp3(ixo^s)=block%equi_vars(ixo^s,equi_pe_c0_,0)*inv_gamma_1
7112 endif
7113 if (twofl_equi_thermal) then
7114 tmp(ixo^s) = alpha(ixo^s) *(-1d0/rn*(rhoc(ixo^s) * tmp4(ixo^s) + &
7115 tmp2(ixo^s)*wct(ixo^s,rho_c_)) + 1d0/rc*(rhon(ixo^s) * tmp5(ixo^s) +&
7116 tmp3(ixo^s)*wct(ixo^s,rho_n_)))
7117 endif
7118 if(has_equi_pe_n0) then
7119 tmp4(ixo^s) = tmp2(ixo^s) + tmp4(ixo^s)
7120 endif
7121 if(has_equi_pe_c0) then
7122 tmp5(ixo^s) = tmp3(ixo^s) + tmp5(ixo^s)
7123 endif
7124 if (.not. twofl_equi_thermal) then
7125 tmp(ixo^s) = alpha(ixo^s) *(-rhoc(ixo^s)/rn * tmp4(ixo^s) + rhon(ixo^s)/rc * tmp5(ixo^s))
7126 endif
7127
7128 if(twofl_coll_inc_ionrec) then
7129 tmp(ixo^s) = tmp(ixo^s) - gamma_ion(ixo^s)/rn * tmp4(ixo^s) + gamma_rec(ixo^s)/rc * tmp5(ixo^s)
7130 endif
7131
7132 tmp(ixo^s) =tmp(ixo^s) * qdt
7133
7134 w(ixo^s,e_n_) = w(ixo^s,e_n_)+tmp(ixo^s)
7135 w(ixo^s,e_c_) = w(ixo^s,e_c_)-tmp(ixo^s)
7136 endif
7137 if(twofl_coll_inc_ionrec) then
7138 deallocate(gamma_ion, gamma_rec)
7139 endif
7140 end subroutine twofl_explicit_coll_terms_update
7141
7142 subroutine rfactor_c(w,x,ixI^L,ixO^L,Rfactor)
7144 integer, intent(in) :: ixi^l, ixo^l
7145 double precision, intent(in) :: w(ixi^s,1:nw)
7146 double precision, intent(in) :: x(ixi^s,1:ndim)
7147 double precision, intent(out):: rfactor(ixi^s)
7148
7149 rfactor(ixo^s)=rc
7150
7151 end subroutine rfactor_c
7152
7153end module mod_twofl_phys
subroutine twofl_get_p_c_total(w, x, ixil, ixol, p)
subroutine twofl_get_csound2_primitive(w, x, ixil, ixol, csound2)
subroutine add_density_hyper_source(index_rho)
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter bigdouble
A very large real number.
subroutine reconstruct(ixil, ixcl, idir, q, ql, qr)
Reconstruct scalar q within ixO^L to 1/2 dx in direction idir Return both left and right reconstructe...
subroutine b_from_vector_potentiala(ixisl, ixil, ixol, ws, x, a)
calculate magnetic field from vector potential A at cell edges
subroutine add_convert_method(phys_convert_vars, nwc, dataset_names, file_suffix)
Definition mod_convert.t:59
Module for flux conservation near refinement boundaries.
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)
update ghost cells of all blocks including physical boundaries
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
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.
logical h_correction
If true, do H-correction to fix the carbuncle problem at grid-aligned shocks.
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
double precision unit_charge
Physical scaling factor for charge.
integer ixghi
Upper index of grid block arrays.
pure subroutine cross_product(ixil, ixol, a, b, axb)
Cross product of two vectors.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
double precision unit_time
Physical scaling factor for time.
double precision unit_density
Physical scaling factor for density.
integer, parameter unitpar
file handle for IO
double precision global_time
The global simulation time.
double precision unit_mass
Physical scaling factor for mass.
logical use_imex_scheme
whether IMEX in use or not
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer it
Number of time steps taken.
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
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
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
double precision unit_velocity
Physical scaling factor for velocity.
double precision c_norm
Normalised speed of light.
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter sdim
starting dimension for electric field
logical phys_trac
Use TRAC for MHD or 1D HD.
logical need_global_cmax
need global maximal wave speed
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
logical fix_small_values
fix small values with average or replace methods
logical crash
Save a snapshot before crash a run met unphysical values.
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
logical check_small_values
check and optionally fix unphysical small values (density, gas pressure)
integer, parameter ixglo
Lower index of grid block arrays (always 1)
Subroutines for Roe-type Riemann solver for HD.
subroutine second_same_deriv(ixil, ixol, nu_hyper, var, idimm, res)
subroutine div_vel_coeff(ixil, ixol, vel, idimm, nu_vel)
subroutine second_cross_deriv2(ixil, ixol, nu_hyper, var2, var, idimm, idimm2, res)
subroutine hyp_coeff(ixil, ixol, var, idimm, nu_hyp)
subroutine second_cross_deriv(ixil, ixol, nu_hyper, var, idimm, idimm2, res)
subroutine second_same_deriv2(ixil, ixol, nu_hyper, var2, var, idimm, res)
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.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
Module for handling problematic values in simulations, such as negative pressures.
subroutine, public small_values_average(ixil, ixol, w, x, w_flag, windex)
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
subroutine, public small_values_error(wprim, x, ixil, ixol, w_flag, subname)
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Generic supertimestepping method which can be used for multiple source terms in the governing equatio...
subroutine, public add_sts_method(sts_getdt, sts_set_sources, startvar, nflux, startwbc, nwbc, evolve_b)
subroutine which added programatically a term to be calculated using STS Params: sts_getdt function c...
subroutine, public set_conversion_methods_to_head(sts_before_first_cycle, sts_after_last_cycle)
Set the hooks called before the first cycle and after the last cycle in the STS update This method sh...
subroutine, public set_error_handling_to_head(sts_error_handling)
Set the hook of error handling in the STS update. This method is called before updating the BC....
subroutine, public sts_init()
Initialize sts module.
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
subroutine, public tc_get_hd_params(fl, read_hd_params)
Init TC coefficients: HD case.
double precision function, public get_tc_dt_mhd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation) Note: also used in 1D MHD (or for neutrals i...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_hd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine get_euv_image(qunit, fl)
subroutine get_sxr_image(qunit, fl)
subroutine get_euv_spectrum(qunit, fl)
subroutine get_whitelight_image(qunit, fl)
Magneto-hydrodynamics module.
logical, public twofl_coll_inc_ionrec
whether include ionization/recombination inelastic collisional terms
subroutine, public b_from_vector_potential(ixisl, ixil, ixol, ws, x)
calculate magnetic field from vector potential
logical, public, protected twofl_dump_full_vars
whether dump full variables (when splitting is used) in a separate dat file
subroutine, public get_gamma_ion_rec(ixil, ixol, w, x, gamma_rec, gamma_ion)
subroutine, public twofl_get_v_c_idim(w, x, ixil, ixol, idim, v)
Calculate v_c component.
double precision, public, protected rn
logical, public clean_initial_divb
clean initial divB
double precision, public twofl_eta_hyper
The MHD hyper-resistivity.
subroutine, public twofl_get_csound2_c_from_conserved(w, x, ixil, ixol, csound2)
double precision, public twofl_eta
The MHD resistivity.
integer, public, protected twofl_trac_type
Which TRAC method is used
logical, public has_equi_pe_c0
type(tc_fluid), allocatable, public tc_fl_c
logical, public twofl_alpha_coll_constant
double precision, dimension(:), allocatable, public, protected c_shk
subroutine, public twofl_face_to_center(ixol, s)
calculate cell-center values from face-center values
logical, public, protected twofl_dump_hyperdiffusivity_coef
double precision, public twofl_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
integer, parameter, public eq_energy_ki
logical, public, protected twofl_thermal_conduction_n
subroutine, public twofl_phys_init()
subroutine, public get_rhon_tot(w, x, ixil, ixol, rhon)
logical, public, protected twofl_thermal_conduction_c
Whether thermal conduction is used.
double precision, public twofl_adiab
The adiabatic constant.
logical, public twofl_equi_thermal_c
character(len=std_len), public, protected type_ct
Method type of constrained transport.
integer, public tweight_c_
subroutine, public twofl_get_pthermal_c(w, x, ixil, ixol, pth)
logical, public, protected twofl_radiative_cooling_n
integer, parameter, public eq_energy_none
integer, public e_n_
type(te_fluid), allocatable, public te_fl_c
procedure(mask_subroutine2), pointer, public usr_mask_gamma_ion_rec
double precision, public, protected rc
logical, public, protected twofl_dump_coll_terms
whether dump collisional terms in a separte dat file
logical, public twofl_equi_thermal_n
logical, public, protected twofl_radiative_cooling_c
Whether radiative cooling is added.
logical, public, protected b0field_forcefree
B0 field is force-free.
integer, public e_c_
Index of the energy density (-1 if not present)
integer, public equi_rho_n0_
integer, public, protected c
Indices of the momentum density for the form of better vectorization.
subroutine, public twofl_get_v_n_idim(w, x, ixil, ixol, idim, v)
Calculate v component.
integer, parameter, public eq_energy_int
integer, dimension(:), allocatable, public mom_c
Indices of the momentum density.
logical, public twofl_coll_inc_te
whether include thermal exchange collisional terms
logical, public has_equi_rho_c0
equi vars flags
logical, public, protected twofl_viscosity
Whether viscosity is added.
double precision, public dtcollpar
logical, public divbwave
Add divB wave in Roe solver.
subroutine, public twofl_to_primitive(ixil, ixol, w, x)
Transform conservative variables into primitive ones.
integer, public tcoff_n_
double precision, dimension(:), allocatable, public, protected c_hyp
integer, public equi_rho_c0_
equi vars indices in the stateequi_vars array
logical, public, protected twofl_glm
Whether GLM-MHD is used.
double precision, public twofl_alpha_coll
collisional alpha
logical, public, protected twofl_trac
Whether TRAC method is used.
double precision, public twofl_etah
The MHD Hall coefficient.
subroutine, public get_alpha_coll(ixil, ixol, w, x, alpha)
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
integer, public, protected b
integer, public equi_pe_c0_
integer, parameter, public eq_energy_tot
integer, dimension(:), allocatable, public mom_n
logical, public, protected twofl_gravity
Whether gravity is added: common flag for charges and neutrals.
integer, public tcoff_c_
Index of the cutoff temperature for the TRAC method.
subroutine, public twofl_clean_divb_multigrid(qdt, qt, active)
double precision, public, protected twofl_trac_mask
Height of the mask used in the TRAC method.
logical, public has_equi_pe_n0
procedure(mask_subroutine), pointer, public usr_mask_alpha
integer, public, protected twofl_divb_nth
Whether divB is computed with a fourth order approximation.
integer, public rho_c_
Index of the density (in the w array)
subroutine, public get_normalized_divb(w, ixil, ixol, divb)
get dimensionless div B = |divB| * volume / area / |B|
type(rc_fluid), allocatable, public rc_fl_c
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)...
subroutine, public twofl_to_conserved(ixil, ixol, w, x)
Transform primitive variables into conservative ones.
logical, public twofl_equi_thermal
integer, public, protected c_
logical, public has_equi_rho_n0
subroutine, public get_rhoc_tot(w, x, ixil, ixol, rhoc)
integer, public rho_n_
subroutine, public twofl_get_pthermal_n(w, x, ixil, ixol, pth)
logical, public, protected twofl_hyperdiffusivity
Whether hyperdiffusivity is used.
integer, public, protected twofl_eq_energy
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
integer, public, protected m
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
double precision, public twofl_gamma
The adiabatic index.
integer, public equi_pe_n0_
logical, public, protected twofl_hall
Whether Hall-MHD is used.
integer, public tweight_n_
integer, public, protected psi_
Indices of the GLM psi.
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
Module with all the methods that users can customize in AMRVAC.
procedure(special_resistivity), pointer usr_special_resistivity
procedure(phys_gravity), pointer usr_gravity
procedure(set_equi_vars), pointer usr_set_equi_vars
procedure(set_electric_field), pointer usr_set_electric_field
procedure(set_wlr), pointer usr_set_wlr
integer nw
Total number of variables.
integer number_species
number of species: each species has different characterictic speeds and should be used accordingly in...
The module add viscous source terms and check time step.
procedure(sub_add_source), pointer, public viscosity_add_source
subroutine, public viscosity_init(phys_wider_stencil)
Initialize the module.
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11