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