MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
mod_thermal_conduction.t
Go to the documentation of this file.
1 !> Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module
2 !> Adaptation of mod_thermal_conduction for the mod_supertimestepping
3 !>
4 !> The TC is set by calling
5 !> tc_init_params()
6 !>
7 !> Organized such that it can call either isotropic (HD) or anisotropic (MHD) variants
8 !> it adds a heat conduction source to each energy equation
9 !> and can be recycled within a multi-fluid context (such as plasma-neutral twofl module)
10 !>
11 !>
12 !> 10.07.2011 developed by Chun Xia and Rony Keppens
13 !> 01.09.2012 moved to modules folder by Oliver Porth
14 !> 13.10.2013 optimized further by Chun Xia
15 !> 12.03.2014 implemented RKL2 super timestepping scheme to reduce iterations
16 !> and improve stability and accuracy up to second order in time by Chun Xia.
17 !> 23.08.2014 implemented saturation and perpendicular TC by Chun Xia
18 !> 12.01.2017 modulized by Chun Xia
19 !> adapted by Beatrice Popescu to twofluid settings
20 !> 06.09.2024 cleaned up for use in rhd and rmhd modules (Nishant Narechania and Rony Keppens)
21 !>
22 !> PURPOSE:
23 !> IN MHD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
24 !> S=DIV(KAPPA_i,j . GRAD_j T)
25 !> where KAPPA_i,j = tc_k_para b_i b_j + tc_k_perp (I - b_i b_j)
26 !> b_i b_j = B_i B_j / B**2, I is the unit matrix, and i, j= 1, 2, 3 for 3D
27 !> IN HD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
28 !> S=DIV(tc_k_para . GRAD T)
29 !> USAGE:
30 !> 1. in mod_usr.t -> subroutine usr_init(), add
31 !> unit_length=your length unit
32 !> unit_numberdensity=your number density unit
33 !> unit_velocity=your velocity unit
34 !> unit_temperature=your temperature unit
35 !> before call (m)hd_activate()
36 !> 2. to switch on thermal conduction in the (r)(m)hd_list of amrvac.par add:
37 !> (r)(m)hd_thermal_conduction=.true.
38 !> 3. in the tc_list of amrvac.par :
39 !> tc_perpendicular=.true. ! (default .false.) turn on thermal conduction perpendicular to magnetic field
40 !> tc_saturate=.true. ! (default .false. ) turn on thermal conduction saturate effect
41 !> tc_slope_limiter='MC' ! choose limiter for slope-limited anisotropic thermal conduction in MHD
42 !> note: twofl_list incorporates instances for charges and neutrals
43 
45  use mod_global_parameters, only: std_len
46  use mod_geometry
47  use mod_comm_lib, only: mpistop
48  implicit none
49 
50  !> The adiabatic index
51  double precision :: tc_gamma_1
52 
53  abstract interface
54  subroutine get_var_subr(w,x,ixI^L,ixO^L,res)
56  integer, intent(in) :: ixI^L, ixO^L
57  double precision, intent(in) :: w(ixI^S,nw)
58  double precision, intent(in) :: x(ixI^S,1:ndim)
59  double precision, intent(out):: res(ixI^S)
60  end subroutine get_var_subr
61  end interface
62 
63  type tc_fluid
64 
65  ! BEGIN the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
66  !> Coefficient of thermal conductivity (parallel to magnetic field)
67  double precision :: tc_k_para
68 
69  !> Coefficient of thermal conductivity perpendicular to magnetic field
70  double precision :: tc_k_perp
71 
72  !> Indices of the variables
73  integer :: e_=-1
74  !> Index of cut off temperature for TRAC
75  integer :: tcoff_
76  !> Name of slope limiter for transverse component of thermal flux
77  integer :: tc_slope_limiter
78 
79  ! if has_equi = .true. get_temperature_equi and get_rho_equi have to be set
80  logical :: has_equi=.false.
81 
82  !> Logical switch for test constant conductivity
83  logical :: tc_constant=.false.
84 
85  !> Calculate thermal conduction perpendicular to magnetic field (.true.) or not (.false.)
86  logical :: tc_perpendicular=.false.
87 
88  !> Consider thermal conduction saturation effect (.true.) or not (.false.)
89  logical :: tc_saturate=.false.
90  ! END the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
91  procedure(get_var_subr), pointer, nopass :: get_rho => null()
92  procedure(get_var_subr), pointer, nopass :: get_rho_equi => null()
93  procedure(get_var_subr), pointer,nopass :: get_temperature_from_eint => null()
94  procedure(get_var_subr), pointer,nopass :: get_temperature_from_conserved => null()
95  procedure(get_var_subr), pointer,nopass :: get_temperature_equi => null()
96  end type tc_fluid
97 
98 
99  public :: tc_get_mhd_params
100  public :: tc_get_hd_params
101  public :: tc_get_ffhd_params
102  public :: get_tc_dt_mhd
103  public :: get_tc_dt_hd
104  public :: get_tc_dt_ffhd
105  public :: sts_set_source_tc_mhd
106  public :: sts_set_source_tc_hd
107  public :: sts_set_source_tc_ffhd
108 
109 contains
110 
111  subroutine tc_init_params(phys_gamma)
113  double precision, intent(in) :: phys_gamma
114 
115  tc_gamma_1=phys_gamma-1d0
116  end subroutine tc_init_params
117 
118  !> Init TC coefficients: MHD case
119  subroutine tc_get_mhd_params(fl,read_mhd_params)
121 
122  interface
123  subroutine read_mhd_params(fl)
125  import tc_fluid
126  type(tc_fluid), intent(inout) :: fl
127 
128  end subroutine read_mhd_params
129  end interface
130  type(tc_fluid), intent(inout) :: fl
131 
132  fl%tc_slope_limiter=1
133  fl%tc_k_para=0.d0
134  fl%tc_k_perp=0.d0
135 
136  !> Read tc module parameters from par file: MHD case
137  call read_mhd_params(fl)
138 
139  if(fl%tc_k_para==0.d0 .and. fl%tc_k_perp==0.d0) then
140  if(si_unit) then
141  ! Spitzer thermal conductivity with SI units
142  fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
143  ! thermal conductivity perpendicular to magnetic field
144  fl%tc_k_perp=4.d-30*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
145  else
146  ! Spitzer thermal conductivity with cgs units
147  fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
148  ! thermal conductivity perpendicular to magnetic field
149  fl%tc_k_perp=4.d-10*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
150  end if
151  if(mype .eq. 0) print*, "Spitzer MHD: par: ",fl%tc_k_para, &
152  " ,perp: ",fl%tc_k_perp
153  else
154  fl%tc_constant=.true.
155  end if
156 
157  end subroutine tc_get_mhd_params
158 
159  !> Init TC coefficients: HD case
160  subroutine tc_get_hd_params(fl,read_hd_params)
162 
163  interface
164  subroutine read_hd_params(fl)
166  import tc_fluid
167  type(tc_fluid), intent(inout) :: fl
168 
169  end subroutine read_hd_params
170  end interface
171  type(tc_fluid), intent(inout) :: fl
172 
173  fl%tc_k_para=0.d0
174 
175  !> Read tc parameters from par file: HD case
176  call read_hd_params(fl)
177 
178  if(fl%tc_k_para==0.d0 ) then
179  if(si_unit) then
180  ! Spitzer thermal conductivity with SI units
181  fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
182  else
183  ! Spitzer thermal conductivity with cgs units
184  fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
185  end if
186  if(mype .eq. 0) print*, "Spitzer HD par: ",fl%tc_k_para
187  end if
188 
189  end subroutine tc_get_hd_params
190 
191  subroutine tc_get_ffhd_params(fl,read_ffhd_params)
193 
194  interface
195  subroutine read_ffhd_params(fl)
197  import tc_fluid
198  type(tc_fluid), intent(inout) :: fl
199  end subroutine read_ffhd_params
200  end interface
201 
202  type(tc_fluid), intent(inout) :: fl
203 
204  fl%tc_k_para=0.d0
205  !> Read tc parameters from par file: ffHD case
206  call read_ffhd_params(fl)
207  if(fl%tc_k_para==0.d0 ) then
208  if(si_unit) then
209  ! Spitzer thermal conductivity with SI units
210  fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
211  else
212  ! Spitzer thermal conductivity with cgs units
213  fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
214  endif
215  if(mype .eq. 0) print*, "Spitzer ffHD par: ",fl%tc_k_para
216  else
217  fl%tc_constant=.true.
218  endif
219  end subroutine tc_get_ffhd_params
220 
221  !> Get the explicut timestep for the TC (mhd implementation)
222  function get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
223  !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
224  !where tc_k_para_i=tc_k_para*B_i**2/B**2
225  !and T=p/rho
227 
228  type(tc_fluid), intent(in) :: fl
229  integer, intent(in) :: ixi^l, ixo^l
230  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
231  double precision, intent(in) :: w(ixi^s,1:nw)
232  double precision :: dtnew
233 
234  double precision :: mf(ixo^s,1:ndim),te(ixi^s),rho(ixi^s),gradt(ixi^s)
235  double precision :: tmp(ixo^s),hfs(ixo^s)
236  double precision :: dtdiff_tcond,maxtmp2
237  integer :: idims,ix^d
238 
239  !temperature
240  call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
241 
242  ! B
243  {do ix^db=ixomin^db,ixomax^db\}
244  if(b0field) then
245  ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
246  else
247  ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))\
248  end if
249  ! Bsquared
250  tmp(ix^d)=(^d&mf({ix^d},^d)**2+)
251  ! B_i**2/B**2
252  if(tmp(ix^d)/=0.d0) then
253  ^d&mf({ix^d},^d)=mf({ix^d},^d)**2/tmp({ix^d})\
254  else
255  ^d&mf({ix^d},^d)=1.d0\
256  end if
257  {end do\}
258 
259  dtnew=bigdouble
260  call fl%get_rho(w,x,ixi^l,ixo^l,rho)
261 
262  !tc_k_para_i
263  if(fl%tc_constant) then
264  tmp(ixo^s)=fl%tc_k_para
265  else
266  if(fl%tc_saturate) then
267  ! Kannan 2016 MN 458, 410
268  ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
269  ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
270  tmp(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
271  do idims=1,ndim
272  call gradient(te,ixi^l,ixo^l,idims,gradt)
273  if(idims==1) then
274  hfs(ixo^s)=gradt(ixo^s)*sqrt(mf(ixo^s,idims))
275  else
276  hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)*sqrt(mf(ixo^s,idims))
277  end if
278  end do
279  ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT.b|))
280  tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)/(1.d0+4.2d0*tmp(ixo^s)*dabs(hfs(ixo^s))/te(ixo^s))
281  else
282  ! kappa=kappa_Spizer
283  tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)
284  end if
285  end if
286 
287  if(slab_uniform) then
288  do idims=1,ndim
289  ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
290  maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*dxlevel(idims)))
291  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
292  dtdiff_tcond=dxlevel(idims)/(tc_gamma_1*maxtmp2+smalldouble)
293  ! limit the time step
294  dtnew=min(dtnew,dtdiff_tcond)
295  end do
296  else
297  do idims=1,ndim
298  ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
299  maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*block%ds(ixo^s,idims)**2))
300  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
301  dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
302  ! limit the time step
303  dtnew=min(dtnew,dtdiff_tcond)
304  end do
305  end if
306  dtnew=dtnew/dble(ndim)
307  end function get_tc_dt_mhd
308 
309  !> anisotropic thermal conduction with slope limited symmetric scheme
310  !> Sharma 2007 Journal of Computational Physics 227, 123
311  subroutine sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
313  use mod_fix_conserve
314  integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
315  double precision, intent(in) :: x(ixi^s,1:ndim)
316  double precision, intent(in) :: w(ixi^s,1:nw)
317  double precision, intent(inout) :: wres(ixi^s,1:nw)
318  double precision, intent(in) :: my_dt
319  logical, intent(in) :: fix_conserve_at_step
320  type(tc_fluid), intent(in) :: fl
321 
322  !! qd store the heat conduction energy changing rate
323  double precision :: qd(ixo^s)
324  double precision :: rho(ixi^s),te(ixi^s)
325  double precision :: qvec(ixi^s,1:ndim)
326  double precision :: fluxall(ixi^s,1,1:ndim)
327  double precision :: alpha,dxinv(ndim)
328  double precision, allocatable, dimension(:^D&,:) :: qvec_equi
329  integer :: idims,ixa^l
330 
331  ! coefficient of limiting on normal component
332  if(ndim<3) then
333  alpha=0.75d0
334  else
335  alpha=0.85d0
336  end if
337 
338  dxinv=1.d0/dxlevel
339 
340  call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
341  call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
342  call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
343  if(fl%has_equi) then
344  allocate(qvec_equi(ixi^s,1:ndim))
345  call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
346  call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
347  call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
348  do idims=1,ndim
349  ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
350  qvec(ixa^s,idims)=qvec(ixa^s,idims)-qvec_equi(ixa^s,idims)
351  end do
352  deallocate(qvec_equi)
353  end if
354 
355  if(slab_uniform) then
356  do idims=1,ndim
357  ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
358  qvec(ixa^s,idims)=dxinv(idims)*qvec(ixa^s,idims)
359  ixa^l=ixo^l-kr(idims,^d);
360  if(idims==1) then
361  qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
362  else
363  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
364  end if
365  end do
366  else
367  do idims=1,ndim
368  ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
369  qvec(ixa^s,idims)=qvec(ixa^s,idims)*block%surfaceC(ixa^s,idims)
370  ixa^l=ixo^l-kr(idims,^d);
371  if(idims==1) then
372  qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
373  else
374  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
375  end if
376  end do
377  qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
378  end if
379 
380  if(fix_conserve_at_step) then
381  do idims=1,ndim
382  ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
383  fluxall(ixa^s,1,idims)=my_dt*qvec(ixa^s,idims)
384  end do
385  call store_flux(igrid,fluxall,1,ndim,nflux)
386  end if
387 
388  wres(ixo^s,fl%e_)=qd(ixo^s)
389  end subroutine sts_set_source_tc_mhd
390 
391  subroutine set_source_tc_mhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
393  integer, intent(in) :: ixI^L, ixO^L
394  double precision, intent(in) :: x(ixI^S,1:ndim)
395  double precision, intent(in) :: w(ixI^S,1:nw)
396  type(tc_fluid), intent(in) :: fl
397  double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
398  double precision, intent(in) :: alpha
399  double precision, intent(out) :: qvec(ixI^S,1:ndim)
400 
401  !! qdd store the heat conduction energy changing rate
402  double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf,gradT
403  double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,Bnorm
404  double precision :: minq,maxq,qd(ixI^S,2**(ndim-1))
405  integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
406 
407  ix^l=ixo^l^ladd1;
408 
409  ! T gradient at cell faces
410  ! B vector
411  if(b0field) then
412  {do ix^db=ixmin^db,ixmax^db\}
413  ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
414  ! |B|
415  bnorm(ix^d)=dsqrt(^d&mf({ix^d},^d)**2+)
416  if(bnorm(ix^d)/=0.d0) then
417  bnorm(ix^d)=1.d0/bnorm(ix^d)
418  else
419  bnorm(ix^d)=bigdouble
420  end if
421  ! b unit vector: magnetic field direction vector
422  ^d&mf({ix^d},^d)=mf({ix^d},^d)*bnorm({ix^d})\
423  {end do\}
424  else
425  {do ix^db=ixmin^db,ixmax^db\}
426  ! |B|
427  bnorm(ix^d)=dsqrt(^d&w({ix^d},iw_mag(^d))**2+)
428  if(bnorm(ix^d)/=0.d0) then
429  bnorm(ix^d)=1.d0/bnorm(ix^d)
430  else
431  bnorm(ix^d)=bigdouble
432  end if
433  ! b unit vector: magnetic field direction vector
434  ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))*bnorm({ix^d})\
435  {end do\}
436  end if
437  ! ixC is cell-corner index
438  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
439  ! b unit vector at cell corner
440  {^ifthreed
441  do idims=1,3
442  {do ix^db=ixcmin^db,ixcmax^db\}
443  bc(ix^d,idims)=0.125d0*(mf(ix1,ix2,ix3,idims)+mf(ix1+1,ix2,ix3,idims)&
444  +mf(ix1,ix2+1,ix3,idims)+mf(ix1+1,ix2+1,ix3,idims)&
445  +mf(ix1,ix2,ix3+1,idims)+mf(ix1+1,ix2,ix3+1,idims)&
446  +mf(ix1,ix2+1,ix3+1,idims)+mf(ix1+1,ix2+1,ix3+1,idims))
447  {end do\}
448  end do
449  }
450  {^iftwod
451  do idims=1,2
452  {do ix^db=ixcmin^db,ixcmax^db\}
453  bc(ix^d,idims)=0.25d0*(mf(ix1,ix2,idims)+mf(ix1+1,ix2,idims)&
454  +mf(ix1,ix2+1,idims)+mf(ix1+1,ix2+1,idims))
455  {end do\}
456  end do
457  }
458  ! T gradient at cell faces
459  do idims=1,ndim
460  ixbmin^d=ixmin^d;
461  ixbmax^d=ixmax^d-kr(idims,^d);
462  call gradientc(te,x,ixi^l,ixb^l,idims,gradt(ixi^s,idims))
463  end do
464  if(fl%tc_constant) then
465  if(fl%tc_perpendicular) then
466  ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
467  ke(ixc^s)=fl%tc_k_perp
468  else
469  ka(ixc^s)=fl%tc_k_para
470  end if
471  else
472  ! conductivity at cell center
473  if(phys_trac) then
474  {do ix^db=ixmin^db,ixmax^db\}
475  if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
476  qdd(ix^d)=fl%tc_k_para*sqrt(block%wextra(ix^d,fl%Tcoff_)**5)
477  else
478  qdd(ix^d)=fl%tc_k_para*sqrt(te(ix^d)**5)
479  end if
480  {end do\}
481  else
482  qdd(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
483  end if
484  ! cell corner parallel conductivity in ka
485  {^ifthreed
486  {do ix^db=ixcmin^db,ixcmax^db\}
487  ka(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
488  +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
489  +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
490  +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
491  {end do\}
492  }
493  {^iftwod
494  {do ix^db=ixcmin^db,ixcmax^db\}
495  ka(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
496  +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
497  {end do\}
498  }
499  ! compensate with perpendicular conductivity
500  if(fl%tc_perpendicular) then
501  qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2*bnorm(ix^s)**2/dsqrt(te(ix^s))
502  {^ifthreed
503  {do ix^db=ixcmin^db,ixcmax^db\}
504  ke(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
505  +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
506  +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
507  +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
508  if(ke(ix^d)<ka(ix^d)) then
509  ka(ix^d)=ka(ix^d)-ke(ix^d)
510  else
511  ke(ix^d)=ka(ix^d)
512  ka(ix^d)=0.d0
513  end if
514  {end do\}
515  }
516  {^iftwod
517  {do ix^db=ixcmin^db,ixcmax^db\}
518  ke(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
519  +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
520  if(ke(ix^d)<ka(ix^d)) then
521  ka(ix^d)=ka(ix^d)-ke(ix^d)
522  else
523  ke(ix^d)=ka(ix^d)
524  ka(ix^d)=0.d0
525  end if
526  {end do\}
527  }
528  end if
529  end if
530  if(fl%tc_slope_limiter==0) then
531  ! calculate thermal conduction flux with symmetric scheme
532  do idims=1,ndim
533  !qdd corner values
534  qdd=0.d0
535  {do ix^db=0,1 \}
536  if({ ix^d==0 .and. ^d==idims | .or.}) then
537  ixbmin^d=ixcmin^d+ix^d;
538  ixbmax^d=ixcmax^d+ix^d;
539  qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
540  end if
541  {end do\}
542  ! temperature gradient at cell corner
543  qvec(ixc^s,idims)=qdd(ixc^s)*0.5d0**(ndim-1)
544  end do
545  ! b grad T at cell corner
546  qdd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
547  do idims=1,ndim
548  ! TC flux at cell corner
549  gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qdd(ixc^s)
550  if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
551  end do
552  ! TC flux at cell face
553  qvec=0.d0
554  do idims=1,ndim
555  ixb^l=ixo^l-kr(idims,^d);
556  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
557  {do ix^db=0,1 \}
558  if({ ix^d==0 .and. ^d==idims | .or.}) then
559  ixbmin^d=ixamin^d-ix^d;
560  ixbmax^d=ixamax^d-ix^d;
561  qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
562  end if
563  {end do\}
564  qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
565  if(fl%tc_saturate) then
566  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
567  ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
568  bcf=0.d0
569  {do ix^db=0,1 \}
570  if({ ix^d==0 .and. ^d==idims | .or.}) then
571  ixbmin^d=ixamin^d-ix^d;
572  ixbmax^d=ixamax^d-ix^d;
573  bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
574  end if
575  {end do\}
576  ! averaged b at face centers
577  bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
578  ixb^l=ixa^l+kr(idims,^d);
579  qdd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3*dabs(bcf(ixa^s,idims))
580  {do ix^db=ixamin^db,ixamax^db\}
581  if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
582  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
583  end if
584  {end do\}
585  end if
586  end do
587  else
588  ! calculate thermal conduction flux with slope-limited symmetric scheme
589  do idims=1,ndim
590  ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
591  {^ifthreed
592  if(idims==1) then
593  {do ix^db=ixamin^db,ixamax^db\}
594  ! averaged b at face centers
595  ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
596  +bc(ix1,ix2,ix3-1,^d)+bc(ix1,ix2-1,ix3-1,^d))\
597  kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
598  +ka(ix1,ix2,ix3-1)+ka(ix1,ix2-1,ix3-1))
599  ! averaged thermal conductivity at face centers
600  if(fl%tc_perpendicular) &
601  kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
602  +ke(ix1,ix2,ix3-1)+ke(ix1,ix2-1,ix3-1))
603  {end do\}
604  else if(idims==2) then
605  {do ix^db=ixamin^db,ixamax^db\}
606  ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1-1,ix2,ix3,^d)&
607  +bc(ix1,ix2,ix3-1,^d)+bc(ix1-1,ix2,ix3-1,^d))\
608  kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1-1,ix2,ix3)&
609  +ka(ix1,ix2,ix3-1)+ka(ix1-1,ix2,ix3-1))
610  if(fl%tc_perpendicular) &
611  kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1-1,ix2,ix3)&
612  +ke(ix1,ix2,ix3-1)+ke(ix1-1,ix2,ix3-1))
613  {end do\}
614  else
615  {do ix^db=ixamin^db,ixamax^db\}
616  ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
617  +bc(ix1-1,ix2,ix3,^d)+bc(ix1-1,ix2-1,ix3,^d))\
618  kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
619  +ka(ix1-1,ix2,ix3)+ka(ix1-1,ix2-1,ix3))
620  if(fl%tc_perpendicular) &
621  kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
622  +ke(ix1-1,ix2,ix3)+ke(ix1-1,ix2-1,ix3))
623  {end do\}
624  end if
625  }
626  {^iftwod
627  if(idims==1) then
628  {do ix^db=ixamin^db,ixamax^db\}
629  ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1,ix2-1,^d))\
630  kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1,ix2-1))
631  if(fl%tc_perpendicular) &
632  kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2-1))
633  {end do\}
634  else
635  {do ix^db=ixamin^db,ixamax^db\}
636  ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1-1,ix2,^d))\
637  kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1-1,ix2))
638  if(fl%tc_perpendicular) &
639  kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1-1,ix2))
640  {end do\}
641  end if
642  }
643  ! eq (19)
644  ! temperature gradient at cell corner
645  {^ifthreed
646  if(idims==1) then
647  {do ix^db=ixcmin^db,ixcmax^db\}
648  qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2+1,ix3,idims)&
649  +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1,ix2+1,ix3+1,idims))
650  {end do\}
651  else if(idims==2) then
652  {do ix^db=ixcmin^db,ixcmax^db\}
653  qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
654  +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1+1,ix2,ix3+1,idims))
655  {end do\}
656  else
657  {do ix^db=ixcmin^db,ixcmax^db\}
658  qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
659  +gradt(ix1,ix2+1,ix3,idims)+gradt(ix1+1,ix2+1,ix3,idims))
660  {end do\}
661  end if
662  }
663  {^iftwod
664  if(idims==1) then
665  {do ix^db=ixcmin^db,ixcmax^db\}
666  qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2+1,idims))
667  {end do\}
668  else
669  {do ix^db=ixcmin^db,ixcmax^db\}
670  qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1+1,ix2,idims))
671  {end do\}
672  end if
673  }
674  ! eq (21)
675  {^ifthreed
676  if(idims==1) then
677  {do ix^db=ixamin^db,ixamax^db\}
678  minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
679  maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
680  if(qdd(ix^d)<minq) then
681  qd(ix^d,1)=minq
682  else if(qdd(ix^d)>maxq) then
683  qd(ix^d,1)=maxq
684  else
685  qd(ix^d,1)=qdd(ix^d)
686  end if
687  if(qdd(ix1,ix2-1,ix3)<minq) then
688  qd(ix^d,2)=minq
689  else if(qdd(ix1,ix2-1,ix3)>maxq) then
690  qd(ix^d,2)=maxq
691  else
692  qd(ix^d,2)=qdd(ix1,ix2-1,ix3)
693  end if
694  if(qdd(ix1,ix2,ix3-1)<minq) then
695  qd(ix^d,3)=minq
696  else if(qdd(ix1,ix2,ix3-1)>maxq) then
697  qd(ix^d,3)=maxq
698  else
699  qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
700  end if
701  if(qdd(ix1,ix2-1,ix3-1)<minq) then
702  qd(ix^d,4)=minq
703  else if(qdd(ix1,ix2-1,ix3-1)>maxq) then
704  qd(ix^d,4)=maxq
705  else
706  qd(ix^d,4)=qdd(ix1,ix2-1,ix3-1)
707  end if
708  qvec(ix^d,idims)=kaf(ix^d)*0.25d0*(bc(ix^d,idims)**2*qd(ix^d,1)+bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,2)&
709  +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1,ix2-1,ix3-1,idims)**2*qd(ix^d,4))
710  if(fl%tc_perpendicular) &
711  qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.25d0*(qd(ix^d,1)+qd(ix^d,2)+qd(ix^d,3)+qd(ix^d,4))
712  {end do\}
713  else if(idims==2) then
714  {do ix^db=ixamin^db,ixamax^db\}
715  minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
716  maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
717  if(qdd(ix^d)<minq) then
718  qd(ix^d,1)=minq
719  else if(qdd(ix^d)>maxq) then
720  qd(ix^d,1)=maxq
721  else
722  qd(ix^d,1)=qdd(ix^d)
723  end if
724  if(qdd(ix1-1,ix2,ix3)<minq) then
725  qd(ix^d,2)=minq
726  else if(qdd(ix1-1,ix2,ix3)>maxq) then
727  qd(ix^d,2)=maxq
728  else
729  qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
730  end if
731  if(qdd(ix1,ix2,ix3-1)<minq) then
732  qd(ix^d,3)=minq
733  else if(qdd(ix1,ix2,ix3-1)>maxq) then
734  qd(ix^d,3)=maxq
735  else
736  qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
737  end if
738  if(qdd(ix1-1,ix2,ix3-1)<minq) then
739  qd(ix^d,4)=minq
740  else if(qdd(ix1-1,ix2,ix3-1)>maxq) then
741  qd(ix^d,4)=maxq
742  else
743  qd(ix^d,4)=qdd(ix1-1,ix2,ix3-1)
744  end if
745  qvec(ix^d,idims)=kaf(ix^d)*0.25d0*(bc(ix^d,idims)**2*qd(ix^d,1)+bc(ix1-1,ix2,ix3,idims)**2*qd(ix^d,2)&
746  +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2,ix3-1,idims)**2*qd(ix^d,4))
747  if(fl%tc_perpendicular) &
748  qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.25d0*(qd(ix^d,1)+qd(ix^d,2)+qd(ix^d,3)+qd(ix^d,4))
749  {end do\}
750  else
751  {do ix^db=ixamin^db,ixamax^db\}
752  minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
753  maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
754  if(qdd(ix^d)<minq) then
755  qd(ix^d,1)=minq
756  else if(qdd(ix^d)>maxq) then
757  qd(ix^d,1)=maxq
758  else
759  qd(ix^d,1)=qdd(ix^d)
760  end if
761  if(qdd(ix1-1,ix2,ix3)<minq) then
762  qd(ix^d,2)=minq
763  else if(qdd(ix1-1,ix2,ix3)>maxq) then
764  qd(ix^d,2)=maxq
765  else
766  qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
767  end if
768  if(qdd(ix1,ix2-1,ix3)<minq) then
769  qd(ix^d,3)=minq
770  else if(qdd(ix1,ix2-1,ix3)>maxq) then
771  qd(ix^d,3)=maxq
772  else
773  qd(ix^d,3)=qdd(ix1,ix2-1,ix3)
774  end if
775  if(qdd(ix1-1,ix2-1,ix3)<minq) then
776  qd(ix^d,4)=minq
777  else if(qdd(ix1-1,ix2-1,ix3)>maxq) then
778  qd(ix^d,4)=maxq
779  else
780  qd(ix^d,4)=qdd(ix1-1,ix2-1,ix3)
781  end if
782  qvec(ix^d,idims)=kaf(ix^d)*0.25d0*(bc(ix^d,idims)**2*qd(ix^d,1)+bc(ix1-1,ix2,ix3,idims)**2*qd(ix^d,2)&
783  +bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2-1,ix3,idims)**2*qd(ix^d,4))
784  if(fl%tc_perpendicular) &
785  qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.25d0*(qd(ix^d,1)+qd(ix^d,2)+qd(ix^d,3)+qd(ix^d,4))
786  {end do\}
787  end if
788  }
789  {^iftwod
790  if(idims==1) then
791  {do ix^db=ixamin^db,ixamax^db\}
792  minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
793  maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
794  if(qdd(ix^d)<minq) then
795  qd(ix^d,1)=minq
796  else if(qdd(ix^d)>maxq) then
797  qd(ix^d,1)=maxq
798  else
799  qd(ix^d,1)=qdd(ix^d)
800  end if
801  if(qdd(ix1,ix2-1)<minq) then
802  qd(ix^d,2)=minq
803  else if(qdd(ix1,ix2-1)>maxq) then
804  qd(ix^d,2)=maxq
805  else
806  qd(ix^d,2)=qdd(ix1,ix2-1)
807  end if
808  qvec(ix^d,idims)=kaf(ix^d)*0.5d0*(bc(ix1,ix2,idims)**2*qd(ix^d,1)+bc(ix1,ix2-1,idims)**2*qd(ix^d,2))
809  if(fl%tc_perpendicular) &
810  qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
811  {end do\}
812  else
813  {do ix^db=ixamin^db,ixamax^db\}
814  minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
815  maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
816  if(qdd(ix^d)<minq) then
817  qd(ix^d,1)=minq
818  else if(qdd(ix^d)>maxq) then
819  qd(ix^d,1)=maxq
820  else
821  qd(ix^d,1)=qdd(ix^d)
822  end if
823  if(qdd(ix1-1,ix2)<minq) then
824  qd(ix^d,2)=minq
825  else if(qdd(ix1-1,ix2)>maxq) then
826  qd(ix^d,2)=maxq
827  else
828  qd(ix^d,2)=qdd(ix1-1,ix2)
829  end if
830  qvec(ix^d,idims)=kaf(ix^d)*0.5d0*(bc(ix1,ix2,idims)**2*qd(ix^d,1)+bc(ix1-1,ix2,idims)**2*qd(ix^d,2))
831  if(fl%tc_perpendicular) &
832  qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
833  {end do\}
834  end if
835  }
836  ! calculate normal of magnetic field
837  ixb^l=ixa^l+kr(idims,^d);
838  bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
839  ! limited transverse component, eq (17)
840  ixbmin^d=ixamin^d;
841  ixbmax^d=ixamax^d+kr(idims,^d);
842  do idir=1,ndim
843  if(idir==idims) cycle
844  qdd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
845  qdd(ixi^s)=slope_limiter(qdd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
846  qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qdd(ixa^s)
847  end do
848  if(fl%tc_saturate) then
849  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
850  ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
851  ixb^l=ixa^l+kr(idims,^d);
852  qdd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3*dabs(bnorm(ixa^s))
853  {do ix^db=ixamin^db,ixamax^db\}
854  if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
855  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
856  end if
857  {end do\}
858  end if
859  end do
860  end if
861  end subroutine set_source_tc_mhd
862 
863  function slope_limiter(f,ixI^L,ixO^L,idims,pm,tc_slope_limiter) result(lf)
865  integer, intent(in) :: ixi^l, ixo^l, idims, pm
866  double precision, intent(in) :: f(ixi^s)
867  double precision :: lf(ixi^s)
868  integer, intent(in) :: tc_slope_limiter
869 
870  double precision :: signf(ixi^s)
871  integer :: ixb^l
872 
873  ixb^l=ixo^l+pm*kr(idims,^d);
874  signf(ixo^s)=sign(1.d0,f(ixo^s))
875  select case(tc_slope_limiter)
876  case(1)
877  ! 'MC' montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
878  lf(ixo^s)=two*signf(ixo^s)* &
879  max(zero,min(dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s),&
880  signf(ixo^s)*quarter*(f(ixb^s)+f(ixo^s))))
881  case(2)
882  ! 'minmod' limiter
883  lf(ixo^s)=signf(ixo^s)*max(0.d0,min(abs(f(ixo^s)),signf(ixo^s)*f(ixb^s)))
884  case(3)
885  ! 'superbee' Roes superbee limiter (eq.3.51i)
886  lf(ixo^s)=signf(ixo^s)* &
887  max(zero,min(two*dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s)),&
888  min(dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s)))
889  case(4)
890  ! 'koren' Barry Koren Right variant
891  lf(ixo^s)=signf(ixo^s)* &
892  max(zero,min(two*dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s),&
893  (two*f(ixb^s)*signf(ixo^s)+dabs(f(ixo^s)))*third))
894  case default
895  call mpistop("Unknown slope limiter for thermal conduction")
896  end select
897  end function slope_limiter
898 
899  !> Calculate gradient of a scalar q at cell interfaces in direction idir
900  subroutine gradientc(q,x,ixI^L,ixO^L,idir,gradq)
902  integer, intent(in) :: ixI^L, ixO^L, idir
903  double precision, intent(in) :: q(ixI^S),x(ixI^S,1:ndim)
904  double precision, intent(inout) :: gradq(ixI^S)
905  integer :: jxO^L
906 
907  jxo^l=ixo^l+kr(idir,^d);
908  select case(coordinate)
909  case(cartesian)
910  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/dxlevel(idir)
911  case(cartesian_stretched)
912  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,idir)-x(ixo^s,idir))
913  case(spherical)
914  select case(idir)
915  case(1)
916  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,1)-x(ixo^s,1))
917  {^nooned
918  case(2)
919  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/( (x(jxo^s,2)-x(ixo^s,2))*x(ixo^s,1) )
920  }
921  {^ifthreed
922  case(3)
923  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/( (x(jxo^s,3)-x(ixo^s,3))*x(ixo^s,1)*dsin(x(ixo^s,2)) )
924  }
925  end select
926  case(cylindrical)
927  if(idir==phi_) then
928  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/((x(jxo^s,phi_)-x(ixo^s,phi_))*x(ixo^s,r_))
929  else
930  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,idir)-x(ixo^s,idir))
931  end if
932  case default
933  call mpistop('Unknown geometry')
934  end select
935 
936  end subroutine gradientc
937 
938  !> Get the explicit timestep for the TC (hd implementation)
939  function get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
940  ! Check diffusion time limit dt < dx_i**2 / ((gamma-1)*tc_k_para_i/rho)
942 
943  integer, intent(in) :: ixi^l, ixo^l
944  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
945  double precision, intent(in) :: w(ixi^s,1:nw)
946  type(tc_fluid), intent(in) :: fl
947  double precision :: dtnew
948 
949  double precision :: tmp(ixo^s),tmp2(ixo^s),te(ixi^s),rho(ixi^s),hfs(ixo^s),gradt(ixi^s)
950  double precision :: dtdiff_tcond,maxtmp2
951  integer :: idim
952 
953  call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
954  call fl%get_rho(w,x,ixi^l,ixo^l,rho)
955 
956  if(fl%tc_saturate) then
957  ! Kannan 2016 MN 458, 410
958  ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
959  ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
960  tmp2(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
961  hfs=0.d0
962  do idim=1,ndim
963  call gradient(te,ixi^l,ixo^l,idim,gradt)
964  hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)**2
965  end do
966  ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT|))
967  tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/(rho(ixo^s)*(1.d0+4.2d0*tmp2(ixo^s)*sqrt(hfs(ixo^s))/te(ixo^s)))
968  else
969  tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/rho(ixo^s)
970  end if
971  dtnew = bigdouble
972 
973  if(slab_uniform) then
974  do idim=1,ndim
975  ! approximate thermal conduction flux: tc_k_para_i/rho/dx
976  tmp2(ixo^s)=tmp(ixo^s)/dxlevel(idim)
977  maxtmp2=maxval(tmp2(ixo^s))
978  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho)
979  dtdiff_tcond=dxlevel(idim)/(tc_gamma_1*maxtmp2+smalldouble)
980  ! limit the time step
981  dtnew=min(dtnew,dtdiff_tcond)
982  end do
983  else
984  do idim=1,ndim
985  ! approximate thermal conduction flux: tc_k_para_i/rho/dx
986  tmp2(ixo^s)=tmp(ixo^s)/block%ds(ixo^s,idim)
987  maxtmp2=maxval(tmp2(ixo^s)/block%ds(ixo^s,idim))
988  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
989  dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
990  ! limit the time step
991  dtnew=min(dtnew,dtdiff_tcond)
992  end do
993  end if
994  dtnew=dtnew/dble(ndim)
995  end function get_tc_dt_hd
996 
997  subroutine sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
999  use mod_fix_conserve
1000 
1001  integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1002  double precision, intent(in) :: x(ixi^s,1:ndim)
1003  double precision, intent(in) :: w(ixi^s,1:nw)
1004  double precision, intent(inout) :: wres(ixi^s,1:nw)
1005  double precision, intent(in) :: my_dt
1006  logical, intent(in) :: fix_conserve_at_step
1007  type(tc_fluid), intent(in) :: fl
1008 
1009  double precision :: te(ixi^s),rho(ixi^s)
1010  double precision :: qvec(ixi^s,1:ndim),qd(ixi^s)
1011  double precision, allocatable, dimension(:^D&,:) :: qvec_equi
1012  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
1013 
1014  double precision :: dxinv(ndim)
1015  integer :: idims,ix^l,ixb^l
1016 
1017  ix^l=ixo^l^ladd1;
1018 
1019  dxinv=1.d0/dxlevel
1020 
1021  !calculate Te in whole domain (+ghosts)
1022  call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te)
1023  call fl%get_rho(w, x, ixi^l, ixi^l, rho)
1024  call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
1025  if(fl%has_equi) then
1026  allocate(qvec_equi(ixi^s,1:ndim))
1027  call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
1028  call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
1029  call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
1030  do idims=1,ndim
1031  qvec(ix^s,idims)=qvec(ix^s,idims) - qvec_equi(ix^s,idims)
1032  end do
1033  deallocate(qvec_equi)
1034  endif
1035 
1036  qd=0.d0
1037  if(slab_uniform) then
1038  do idims=1,ndim
1039  qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
1040  ixb^l=ixo^l-kr(idims,^d);
1041  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1042  end do
1043  else
1044  do idims=1,ndim
1045  qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
1046  ixb^l=ixo^l-kr(idims,^d);
1047  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1048  end do
1049  qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
1050  end if
1051 
1052  if(fix_conserve_at_step) then
1053  allocate(fluxall(ixi^s,1,1:ndim))
1054  fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
1055  call store_flux(igrid,fluxall,1,ndim,nflux)
1056  deallocate(fluxall)
1057  end if
1058  wres(ixo^s,fl%e_)=qd(ixo^s)
1059  end subroutine sts_set_source_tc_hd
1060 
1061  subroutine set_source_tc_hd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
1063  integer, intent(in) :: ixI^L, ixO^L
1064  double precision, intent(in) :: x(ixI^S,1:ndim)
1065  double precision, intent(in) :: w(ixI^S,1:nw)
1066  type(tc_fluid), intent(in) :: fl
1067  double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
1068  double precision, intent(out) :: qvec(ixI^S,1:ndim)
1069  double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
1070  integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L,ixD^L
1071 
1072  ix^l=ixo^l^ladd1;
1073  ! ixC is cell-corner index
1074  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1075 
1076  ! calculate thermal conduction flux with symmetric scheme
1077  ! T gradient (central difference) at cell corners
1078  do idims=1,ndim
1079  ixbmin^d=ixmin^d;
1080  ixbmax^d=ixmax^d-kr(idims,^d);
1081  call gradientc(te,x,ixi^l,ixb^l,idims,ke)
1082  qd=0.d0
1083  {do ix^db=0,1 \}
1084  if({ix^d==0 .and. ^d==idims |.or. }) then
1085  ixbmin^d=ixcmin^d+ix^d;
1086  ixbmax^d=ixcmax^d+ix^d;
1087  qd(ixc^s)=qd(ixc^s)+ke(ixb^s)
1088  end if
1089  {end do\}
1090  ! temperature gradient at cell corner
1091  qvec(ixc^s,idims)=qd(ixc^s)*0.5d0**(ndim-1)
1092  end do
1093  ! conductivity at cell center
1094  if(phys_trac) then
1095  ! transition region adaptive conduction
1096  where(te(ix^s) < block%wextra(ix^s,fl%Tcoff_))
1097  qd(ix^s)=fl%tc_k_para*dsqrt(block%wextra(ix^s,fl%Tcoff_))**5
1098  else where
1099  qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s))**5
1100  end where
1101  else
1102  qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s))**5
1103  end if
1104  ke=0.d0
1105  {do ix^db=0,1\}
1106  ixbmin^d=ixcmin^d+ix^d;
1107  ixbmax^d=ixcmax^d+ix^d;
1108  ke(ixc^s)=ke(ixc^s)+qd(ixb^s)
1109  {end do\}
1110  ! cell corner conductivity
1111  ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
1112  ! cell corner conduction flux
1113  do idims=1,ndim
1114  gradt(ixc^s,idims)=ke(ixc^s)*qvec(ixc^s,idims)
1115  end do
1116 
1117  if(fl%tc_saturate) then
1118  ! consider saturation with unsigned saturated TC flux = 5 phi rho c**3
1119  ! saturation flux at cell center
1120  qd(ix^s)=5.5d0*rho(ix^s)*dsqrt(te(ix^s)**3)
1121  !cell corner values of qd in ke
1122  ke=0.d0
1123  {do ix^db=0,1\}
1124  ixbmin^d=ixcmin^d+ix^d;
1125  ixbmax^d=ixcmax^d+ix^d;
1126  ke(ixc^s)=ke(ixc^s)+qd(ixb^s)
1127  {end do\}
1128  ! cell corner saturation flux
1129  ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
1130  ! magnitude of cell corner conduction flux
1131  qd(ixc^s)=norm2(gradt(ixc^s,:),dim=ndim+1)
1132  {do ix^db=ixcmin^db,ixcmax^db\}
1133  if(qd(ix^d)>ke(ix^d)) then
1134  ke(ix^d)=ke(ix^d)/(qd(ix^d)+smalldouble)
1135  ^d&gradt({ix^d},^d)=ke({ix^d})*gradt({ix^d},^d)\
1136  end if
1137  {end do\}
1138  end if
1139 
1140  ! conduction flux at cell face
1141  qvec=0.d0
1142  do idims=1,ndim
1143  ixb^l=ixo^l-kr(idims,^d);
1144  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1145  {do ix^db=0,1 \}
1146  if({ ix^d==0 .and. ^d==idims | .or.}) then
1147  ixbmin^d=ixamin^d-ix^d;
1148  ixbmax^d=ixamax^d-ix^d;
1149  qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
1150  end if
1151  {end do\}
1152  qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
1153  end do
1154  end subroutine set_source_tc_hd
1155 
1156  !> Get the explicut timestep for the TC (ffhd implementation)
1157  function get_tc_dt_ffhd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
1158  !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
1159  !where tc_k_para_i=tc_k_para*B_i**2/B**2
1160  !and T=p/rho
1162  type(tc_fluid), intent(in) :: fl
1163  integer, intent(in) :: ixi^l, ixo^l
1164  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1165  double precision, intent(in) :: w(ixi^s,1:nw)
1166  double precision :: dtnew
1167  double precision :: mf(ixo^s,1:ndim),te(ixi^s),rho(ixi^s),gradt(ixi^s)
1168  double precision :: tmp2(ixo^s),tmp(ixo^s),hfs(ixo^s)
1169  double precision :: dtdiff_tcond,maxtmp2
1170  integer :: idims
1171 
1172  !temperature
1173  call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
1174  mf(ixo^s,1:ndim)=(block%B0(ixo^s,1:ndim,0))**2
1175 
1176  dtnew=bigdouble
1177  call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1178 
1179  !tc_k_para_i
1180  if(fl%tc_constant) then
1181  tmp(ixo^s)=fl%tc_k_para
1182  else
1183  if(fl%tc_saturate) then
1184  ! Kannan 2016 MN 458, 410
1185  ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
1186  ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
1187  tmp2(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
1188  hfs=0.d0
1189  do idims=1,ndim
1190  call gradient(te,ixi^l,ixo^l,idims,gradt)
1191  hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)*sqrt(mf(ixo^s,idims))
1192  end do
1193  ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT.b|))
1194  tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)/(1.d0+4.2d0*tmp2(ixo^s)*dabs(hfs(ixo^s))/te(ixo^s))
1195  else
1196  ! kappa=kappa_Spizer
1197  tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)
1198  end if
1199  end if
1200 
1201  if(slab_uniform) then
1202  do idims=1,ndim
1203  ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
1204  tmp2(ixo^s)=tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*dxlevel(idims))
1205  maxtmp2=maxval(tmp2(ixo^s))
1206  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
1207  dtdiff_tcond=dxlevel(idims)/(tc_gamma_1*maxtmp2+smalldouble)
1208  ! limit the time step
1209  dtnew=min(dtnew,dtdiff_tcond)
1210  end do
1211  else
1212  do idims=1,ndim
1213  ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
1214  tmp2(ixo^s)=tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*block%ds(ixo^s,idims))
1215  maxtmp2=maxval(tmp2(ixo^s)/block%ds(ixo^s,idims))
1216  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
1217  dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
1218  ! limit the time step
1219  dtnew=min(dtnew,dtdiff_tcond)
1220  end do
1221  end if
1222  dtnew=dtnew/dble(ndim)
1223  end function get_tc_dt_ffhd
1224 
1225  !> anisotropic thermal conduction with slope limited symmetric scheme
1226  !> Sharma 2007 Journal of Computational Physics 227, 123
1227  subroutine sts_set_source_tc_ffhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
1229  use mod_fix_conserve
1230  integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1231  double precision, intent(in) :: x(ixi^s,1:ndim)
1232  double precision, intent(in) :: w(ixi^s,1:nw)
1233  double precision, intent(inout) :: wres(ixi^s,1:nw)
1234  double precision, intent(in) :: my_dt
1235  logical, intent(in) :: fix_conserve_at_step
1236  type(tc_fluid), intent(in) :: fl
1237  !! qd store the heat conduction energy changing rate
1238  double precision :: qd(ixi^s)
1239  double precision :: rho(ixi^s),te(ixi^s)
1240  double precision :: qvec(ixi^s,1:ndim)
1241  double precision, allocatable, dimension(:^D&,:) :: qvec_equi
1242  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
1243  double precision :: alpha,dxinv(ndim)
1244  integer :: idims,idir,ix^d,ix^l,ixc^l,ixa^l,ixb^l
1245 
1246  ! coefficient of limiting on normal component
1247  if(ndim<3) then
1248  alpha=0.75d0
1249  else
1250  alpha=0.85d0
1251  end if
1252  ix^l=ixo^l^ladd1;
1253  dxinv=1.d0/dxlevel
1254  call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
1255  call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
1256  call set_source_tc_ffhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
1257 
1258  qd=0.d0
1259  if(slab_uniform) then
1260  do idims=1,ndim
1261  qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
1262  ixb^l=ixo^l-kr(idims,^d);
1263  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1264  end do
1265  else
1266  do idims=1,ndim
1267  qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
1268  ixb^l=ixo^l-kr(idims,^d);
1269  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1270  end do
1271  qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
1272  end if
1273 
1274  if(fix_conserve_at_step) then
1275  allocate(fluxall(ixi^s,1,1:ndim))
1276  fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
1277  call store_flux(igrid,fluxall,1,ndim,nflux)
1278  deallocate(fluxall)
1279  end if
1280  wres(ixo^s,fl%e_)=qd(ixo^s)
1281  end subroutine sts_set_source_tc_ffhd
1282 
1283  subroutine set_source_tc_ffhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
1285  integer, intent(in) :: ixI^L, ixO^L
1286  double precision, intent(in) :: x(ixI^S,1:ndim)
1287  double precision, intent(in) :: w(ixI^S,1:nw)
1288  type(tc_fluid), intent(in) :: fl
1289  double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
1290  double precision, intent(in) :: alpha
1291  double precision, intent(out) :: qvec(ixI^S,1:ndim)
1292  !! qd store the heat conduction energy changing rate
1293  double precision :: qd(ixI^S)
1294  double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf
1295  double precision, dimension(ixI^S,1:ndim) :: gradT
1296  double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,qe,Binv,minq,maxq,Bnorm
1297  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
1298  integer, dimension(ndim) :: lowindex
1299  integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L,ixA^D,ixB^D
1300 
1301  ix^l=ixo^l^ladd1;
1302 
1303  ! T gradient at cell faces
1304  ! B vector
1305  mf(ixi^s,1:ndim)=block%B0(ixi^s,1:ndim,0)
1306  ! ixC is cell-corner index
1307  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1308  ! b unit vector at cell corner
1309  bc=0.d0
1310  {do ix^db=0,1\}
1311  ixamin^d=ixcmin^d+ix^d;
1312  ixamax^d=ixcmax^d+ix^d;
1313  bc(ixc^s,1:ndim)=bc(ixc^s,1:ndim)+mf(ixa^s,1:ndim)
1314  {end do\}
1315  bc(ixc^s,1:ndim)=bc(ixc^s,1:ndim)*0.5d0**ndim
1316  ! T gradient at cell faces
1317  do idims=1,ndim
1318  ixbmin^d=ixmin^d;
1319  ixbmax^d=ixmax^d-kr(idims,^d);
1320  call gradientc(te,x,ixi^l,ixb^l,idims,minq)
1321  gradt(ixb^s,idims)=minq(ixb^s)
1322  end do
1323  if(fl%tc_constant) then
1324  ka(ixc^s)=fl%tc_k_para
1325  else
1326  ! conductivity at cell center
1327  if(phys_trac) then
1328  minq(ix^s)=te(ix^s)
1329  {do ix^db=ixmin^db,ixmax^db\}
1330  if(minq(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
1331  minq(ix^d)=block%wextra(ix^d,fl%Tcoff_)
1332  end if
1333  {end do\}
1334  minq(ix^s)=fl%tc_k_para*sqrt(minq(ix^s)**5)
1335  else
1336  minq(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
1337  end if
1338  ka=0.d0
1339  {do ix^db=0,1\}
1340  ixbmin^d=ixcmin^d+ix^d;
1341  ixbmax^d=ixcmax^d+ix^d;
1342  ka(ixc^s)=ka(ixc^s)+minq(ixb^s)
1343  {end do\}
1344  ! cell corner conductivity
1345  ka(ixc^s)=0.5d0**ndim*ka(ixc^s)
1346  end if
1347  if(fl%tc_slope_limiter==0) then
1348  ! calculate thermal conduction flux with symmetric scheme
1349  do idims=1,ndim
1350  !qd corner values
1351  qd=0.d0
1352  {do ix^db=0,1 \}
1353  if({ ix^d==0 .and. ^d==idims | .or.}) then
1354  ixbmin^d=ixcmin^d+ix^d;
1355  ixbmax^d=ixcmax^d+ix^d;
1356  qd(ixc^s)=qd(ixc^s)+gradt(ixb^s,idims)
1357  end if
1358  {end do\}
1359  ! temperature gradient at cell corner
1360  qvec(ixc^s,idims)=qd(ixc^s)*0.5d0**(ndim-1)
1361  end do
1362  ! b grad T at cell corner
1363  qd(ixc^s)=0.d0
1364  do idims=1,ndim
1365  qd(ixc^s)=qvec(ixc^s,idims)*bc(ixc^s,idims)+qd(ixc^s)
1366  end do
1367  do idims=1,ndim
1368  ! TC flux at cell corner
1369  gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qd(ixc^s)
1370  end do
1371  ! TC flux at cell face
1372  qvec=0.d0
1373  do idims=1,ndim
1374  ixb^l=ixo^l-kr(idims,^d);
1375  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1376  {do ix^db=0,1 \}
1377  if({ ix^d==0 .and. ^d==idims | .or.}) then
1378  ixbmin^d=ixamin^d-ix^d;
1379  ixbmax^d=ixamax^d-ix^d;
1380  qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
1381  end if
1382  {end do\}
1383  qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
1384  if(fl%tc_saturate) then
1385  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1386  ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
1387  bcf=0.d0
1388  {do ix^db=0,1 \}
1389  if({ ix^d==0 .and. ^d==idims | .or.}) then
1390  ixbmin^d=ixamin^d-ix^d;
1391  ixbmax^d=ixamax^d-ix^d;
1392  bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
1393  end if
1394  {end do\}
1395  ! averaged b at face centers
1396  bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
1397  ixb^l=ixa^l+kr(idims,^d);
1398  qd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3*dabs(bcf(ixa^s,idims))
1399  {do ix^db=ixamin^db,ixamax^db\}
1400  if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
1401  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
1402  end if
1403  {end do\}
1404  end if
1405  end do
1406  else
1407  ! calculate thermal conduction flux with slope-limited symmetric scheme
1408  qvec=0.d0
1409  do idims=1,ndim
1410  ixb^l=ixo^l-kr(idims,^d);
1411  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1412  ! calculate normal of magnetic field
1413  ixb^l=ixa^l+kr(idims,^d);
1414  bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
1415  bcf=0.d0
1416  kaf=0.d0
1417  kef=0.d0
1418  {do ix^db=0,1 \}
1419  if({ ix^d==0 .and. ^d==idims | .or.}) then
1420  ixbmin^d=ixamin^d-ix^d;
1421  ixbmax^d=ixamax^d-ix^d;
1422  bcf(ixa^s,1:ndim)=bcf(ixa^s,1:ndim)+bc(ixb^s,1:ndim)
1423  kaf(ixa^s)=kaf(ixa^s)+ka(ixb^s)
1424  end if
1425  {end do\}
1426  ! averaged b at face centers
1427  bcf(ixa^s,1:ndim)=bcf(ixa^s,1:ndim)*0.5d0**(ndim-1)
1428  ! averaged thermal conductivity at face centers
1429  kaf(ixa^s)=kaf(ixa^s)*0.5d0**(ndim-1)
1430  ! limited normal component
1431  minq(ixa^s)=min(alpha*gradt(ixa^s,idims),gradt(ixa^s,idims)/alpha)
1432  maxq(ixa^s)=max(alpha*gradt(ixa^s,idims),gradt(ixa^s,idims)/alpha)
1433  ! eq (19)
1434  !corner values of gradT
1435  qdd=0.d0
1436  {do ix^db=0,1 \}
1437  if({ ix^d==0 .and. ^d==idims | .or.}) then
1438  ixbmin^d=ixcmin^d+ix^d;
1439  ixbmax^d=ixcmax^d+ix^d;
1440  qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
1441  end if
1442  {end do\}
1443  ! temperature gradient at cell corner
1444  qdd(ixc^s)=qdd(ixc^s)*0.5d0**(ndim-1)
1445  ! eq (21)
1446  qe=0.d0
1447  {do ix^db=0,1 \}
1448  qd(ixc^s)=qdd(ixc^s)
1449  if({ ix^d==0 .and. ^d==idims | .or.}) then
1450  ixbmin^d=ixamin^d-ix^d;
1451  ixbmax^d=ixamax^d-ix^d;
1452  {do ixa^db=ixamin^db,ixamax^db
1453  ixb^db=ixa^db-ix^db\}
1454  if(qd(ixb^d)<=minq(ixa^d)) then
1455  qd(ixb^d)=minq(ixa^d)
1456  else if(qd(ixb^d)>=maxq(ixa^d)) then
1457  qd(ixb^d)=maxq(ixa^d)
1458  end if
1459  {end do\}
1460  qvec(ixa^s,idims)=qvec(ixa^s,idims)+bc(ixb^s,idims)**2*qd(ixb^s)
1461  end if
1462  {end do\}
1463  qvec(ixa^s,idims)=kaf(ixa^s)*qvec(ixa^s,idims)*0.5d0**(ndim-1)
1464  ! limited transverse component, eq (17)
1465  ixbmin^d=ixamin^d;
1466  ixbmax^d=ixamax^d+kr(idims,^d);
1467  do idir=1,ndim
1468  if(idir==idims) cycle
1469  qd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
1470  qd(ixi^s)=slope_limiter(qd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
1471  qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qd(ixa^s)
1472  end do
1473  if(fl%tc_saturate) then
1474  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1475  ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
1476  ixb^l=ixa^l+kr(idims,^d);
1477  qd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3*dabs(bnorm(ixa^s))
1478  {do ix^db=ixamin^db,ixamax^db\}
1479  if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
1480  !write(*,*) 'it',it,qvec(ix^D,idims),qd(ix^D),' TC saturated at ',&
1481  !x(ix^D,:),' rho',rho(ix^D),' Te',Te(ix^D)
1482  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
1483  end if
1484  {end do\}
1485  end if
1486  end do
1487  end if
1488  end subroutine set_source_tc_ffhd
1489 end module mod_thermal_conduction
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: mod_comm_lib.t:208
Module for flux conservation near refinement boundaries.
subroutine, public store_flux(igrid, fC, idimLIM, nwfluxin)
Module with geometry-related routines (e.g., divergence, curl)
Definition: mod_geometry.t:2
subroutine gradient(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:321
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
double precision unit_density
Physical scaling factor for density.
integer, parameter unitpar
file handle for IO
integer, dimension(3, 3) kr
Kronecker delta tensor.
double precision unit_numberdensity
Physical scaling factor for number density.
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision unit_length
Physical scaling factor for length.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
double precision unit_magneticfield
Physical scaling factor for magnetic field.
double precision unit_velocity
Physical scaling factor for velocity.
logical b0field
split magnetic field as background B0 field
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
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
Thermal conduction for HD and MHD or RHD and RMHD or twofl (plasma-neutral) module Adaptation of mod_...
subroutine, public sts_set_source_tc_hd(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
subroutine, public tc_get_hd_params(fl, read_hd_params)
Init TC coefficients: HD case.
subroutine, public sts_set_source_tc_ffhd(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 set_source_tc_mhd(ixIL, ixOL, w, x, fl, qvec, rho, Te, alpha)
subroutine gradientc(q, x, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q at cell interfaces in direction idir.
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_mhd(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
double precision function, public get_tc_dt_hd(w, ixIL, ixOL, dxD, x, fl)
Get the explicit timestep for the TC (hd implementation)
subroutine set_source_tc_hd(ixIL, ixOL, w, x, fl, qvec, rho, Te)
double precision tc_gamma_1
The adiabatic index.
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine set_source_tc_ffhd(ixIL, ixOL, w, x, fl, qvec, rho, Te, alpha)
double precision function, public get_tc_dt_ffhd(w, ixIL, ixOL, dxD, x, fl)
Get the explicut timestep for the TC (ffhd implementation)
double precision function, dimension(ixi^s) slope_limiter(f, ixIL, ixOL, idims, pm, tc_slope_limiter)
subroutine, public tc_get_ffhd_params(fl, read_ffhd_params)
double precision function, public get_tc_dt_mhd(w, ixIL, ixOL, dxD, x, fl)
Get the explicut timestep for the TC (mhd implementation)