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