MPI-AMRVAC  3.0
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
mod_thermal_conduction.t
Go to the documentation of this file.
1 !> Thermal conduction for HD and MHD
2 !> Adaptation of mod_thermal_conduction for the mod_supertimestepping
3 !> In order to use it set use_mhd_tc=1 (for the mhd impl) or 2 (for the hd impl) in mhd_list (for the mhd module both hd and mhd impl can be used)
4 !> or use_new_hd_tc in hd_list parameters to true
5 !> (for the hd module, hd implementation has to be used)
6 !> The TC is set by calling one
7 !> tc_init_hd_for_total_energy and tc_init_mhd_for_total_energy might
8 !> The second argument: ixArray has to be [rho_,e_,mag(1)] for mhd (Be aware that the other components of the mag field are assumed consecutive) and [rho_,e_] for hd
9 !> additionally when internal energy equation is solved, an additional element of this array is eaux_: the index of the internal energy variable.
10 !>
11 !> 10.07.2011 developed by Chun Xia and Rony Keppens
12 !> 01.09.2012 moved to modules folder by Oliver Porth
13 !> 13.10.2013 optimized further by Chun Xia
14 !> 12.03.2014 implemented RKL2 super timestepping scheme to reduce iterations
15 !> and improve stability and accuracy up to second order in time by Chun Xia.
16 !> 23.08.2014 implemented saturation and perpendicular TC by Chun Xia
17 !> 12.01.2017 modulized by Chun Xia
18 !>
19 !> PURPOSE:
20 !> IN MHD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
21 !> S=DIV(KAPPA_i,j . GRAD_j T)
22 !> where KAPPA_i,j = tc_k_para b_i b_j + tc_k_perp (I - b_i b_j)
23 !> b_i b_j = B_i B_j / B**2, I is the unit matrix, and i, j= 1, 2, 3 for 3D
24 !> IN HD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
25 !> S=DIV(tc_k_para . GRAD T)
26 !> USAGE:
27 !> 1. in mod_usr.t -> subroutine usr_init(), add
28 !> unit_length=your length unit
29 !> unit_numberdensity=your number density unit
30 !> unit_velocity=your velocity unit
31 !> unit_temperature=your temperature unit
32 !> before call (m)hd_activate()
33 !> 2. to switch on thermal conduction in the (m)hd_list of amrvac.par add:
34 !> (m)hd_thermal_conduction=.true.
35 !> 3. in the tc_list of amrvac.par :
36 !> tc_perpendicular=.true. ! (default .false.) turn on thermal conduction perpendicular to magnetic field
37 !> tc_saturate=.false. ! (default .true. ) turn off thermal conduction saturate effect
38 !> tc_slope_limiter='MC' ! choose limiter for slope-limited anisotropic thermal conduction in MHD
39 
41  use mod_global_parameters, only: std_len
42  use mod_geometry
43  implicit none
44 
45  !> The adiabatic index
46  double precision :: tc_gamma_1
47 
48  abstract interface
49  subroutine get_var_subr(w,x,ixI^L,ixO^L,res)
51  integer, intent(in) :: ixI^L, ixO^L
52  double precision, intent(in) :: w(ixI^S,nw)
53  double precision, intent(in) :: x(ixI^S,1:ndim)
54  double precision, intent(out):: res(ixI^S)
55  end subroutine get_var_subr
56 
57 
58  end interface
59 
60  type tc_fluid
61 
62  procedure(get_var_subr), pointer, nopass :: get_rho => null()
63  procedure(get_var_subr), pointer, nopass :: get_rho_equi => null()
64  procedure(get_var_subr), pointer,nopass :: get_temperature_from_eint => null()
65  procedure(get_var_subr), pointer,nopass :: get_temperature_from_conserved => null()
66  procedure(get_var_subr), pointer,nopass :: get_temperature_equi => null()
67  !> Indices of the variables
68  integer :: e_=-1
69  !> Index of cut off temperature for TRAC
70  integer :: tcoff_
71  ! if has_equi = .true. get_temperature_equi and get_rho_equi have to be set
72  logical :: has_equi=.false.
73 
74  ! the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
75  !> Coefficient of thermal conductivity (parallel to magnetic field)
76  double precision :: tc_k_para
77 
78  !> Coefficient of thermal conductivity perpendicular to magnetic field
79  double precision :: tc_k_perp
80 
81  !> Name of slope limiter for transverse component of thermal flux
82  character(len=std_len) :: tc_slope_limiter
83  !> Logical switch for test constant conductivity
84  logical :: tc_constant=.false.
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=.true.
90  ! END the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
91  end type tc_fluid
92 
93 
94  public :: tc_get_mhd_params
95  public :: tc_get_hd_params
96  public :: get_tc_dt_mhd
97  public :: get_tc_dt_hd
98  public :: sts_set_source_tc_mhd
99  public :: sts_set_source_tc_hd
100 
101 contains
102 
103 
104 
105  subroutine tc_init_params(phys_gamma)
107  double precision, intent(in) :: phys_gamma
108 
109  tc_gamma_1=phys_gamma-1d0
110  end subroutine tc_init_params
111 
112 
113  !> Init TC coeffiecients: MHD case
114  subroutine tc_get_mhd_params(fl,read_mhd_params)
115 
117 
118  interface
119  subroutine read_mhd_params(fl)
121  import tc_fluid
122  type(tc_fluid), intent(inout) :: fl
123 
124  end subroutine read_mhd_params
125  end interface
126 
127  type(tc_fluid), intent(inout) :: fl
128 
129  fl%tc_slope_limiter='MC'
130 
131  fl%tc_k_para=0.d0
132 
133  fl%tc_k_perp=0.d0
134 
135  call read_mhd_params(fl)
136 
137  if(fl%tc_k_para==0.d0 .and. fl%tc_k_perp==0.d0) then
138  if(si_unit) then
139  ! Spitzer thermal conductivity with SI units
140  fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
141  ! thermal conductivity perpendicular to magnetic field
142  fl%tc_k_perp=4.d-30*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
143  else
144  ! Spitzer thermal conductivity with cgs units
145  fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
146  ! thermal conductivity perpendicular to magnetic field
147  fl%tc_k_perp=4.d-10*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
148  end if
149  if(mype .eq. 0) print*, "Spitzer MHD: par: ",fl%tc_k_para, &
150  " ,perp: ",fl%tc_k_perp
151  else
152  fl%tc_constant=.true.
153  end if
154 
155  contains
156 
157  !> Read tc module parameters from par file: MHD case
158 
159  end subroutine tc_get_mhd_params
160 
161 
162  subroutine tc_get_hd_params(fl,read_hd_params)
164 
165  interface
166  subroutine read_hd_params(fl)
168  import tc_fluid
169  type(tc_fluid), intent(inout) :: fl
170 
171  end subroutine read_hd_params
172  end interface
173  type(tc_fluid), intent(inout) :: fl
174 
175  fl%tc_k_para=0.d0
176  !> Read tc parameters from par file: HD case
177  call read_hd_params(fl)
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  end subroutine tc_get_hd_params
189 
190  !> Get the explicut timestep for the TC (mhd implementation)
191  function get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
192  !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
193  !where tc_k_para_i=tc_k_para*B_i**2/B**2
194  !and T=p/rho
196 
197  type(tc_fluid), intent(in) :: fl
198  integer, intent(in) :: ixi^l, ixo^l
199  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
200  double precision, intent(in) :: w(ixi^s,1:nw)
201  double precision :: dtnew
202 
203  double precision :: dxinv(1:ndim),mf(ixi^s,1:ndir)
204  double precision :: tmp2(ixi^s),tmp(ixi^s),te(ixi^s),b2(ixi^s)
205  double precision :: dtdiff_tcond,maxtmp2
206  integer :: idim,ix^d
207 
208  ^d&dxinv(^d)=one/dx^d;
209 
210  !temperature
211  call fl%get_temperature_from_conserved(w,x,ixi^l,ixo^l,te)
212 
213  !tc_k_para_i
214  if(fl%tc_constant) then
215  tmp(ixo^s)=fl%tc_k_para
216  else
217  call fl%get_rho(w,x,ixi^l,ixo^l,tmp2)
218  tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)/tmp2(ixo^s)
219  end if
220 
221  ! B
222  if(b0field) then
223  mf(ixo^s,:)=w(ixo^s,iw_mag(:))+block%B0(ixo^s,:,0)
224  else
225  mf(ixo^s,:)=w(ixo^s,iw_mag(:))
226  end if
227  ! B^-2
228  b2(ixo^s)=sum(mf(ixo^s,:)**2,dim=ndim+1)
229  ! B_i**2/B**2
230  where(b2(ixo^s)/=0.d0)
231  ^d&mf(ixo^s,^d)=mf(ixo^s,^d)**2/b2(ixo^s);
232  elsewhere
233  ^d&mf(ixo^s,^d)=1.d0;
234  end where
235 
236  if(fl%tc_saturate) b2(ixo^s)=22.d0*dsqrt(te(ixo^s))
237  dtnew=bigdouble
238  do idim=1,ndim
239  tmp2(ixo^s)=tmp(ixo^s)*mf(ixo^s,idim)
240  if(fl%tc_saturate) then
241  where(tmp2(ixo^s)>b2(ixo^s))
242  tmp2(ixo^s)=b2(ixo^s)
243  end where
244  end if
245  maxtmp2=maxval(tmp2(ixo^s))
246  if(maxtmp2==0.d0) maxtmp2=smalldouble
247  ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
248  dtdiff_tcond=1.d0/tc_gamma_1/(maxtmp2*dxinv(idim)**2)
249  ! limit the time step
250  dtnew=min(dtnew,dtdiff_tcond)
251  end do
252  dtnew=dtnew/dble(ndim)
253 
254  end function get_tc_dt_mhd
255 
256  !> anisotropic thermal conduction with slope limited symmetric scheme
257  !> Sharma 2007 Journal of Computational Physics 227, 123
258  subroutine sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
260  use mod_fix_conserve
261  integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
262  double precision, intent(in) :: x(ixi^s,1:ndim)
263  double precision, intent(in) :: w(ixi^s,1:nw)
264  double precision, intent(inout) :: wres(ixi^s,1:nw)
265  double precision, intent(in) :: my_dt
266  logical, intent(in) :: fix_conserve_at_step
267  type(tc_fluid), intent(in) :: fl
268 
269  !! qd store the heat conduction energy changing rate
270  double precision :: qd(ixi^s)
271  double precision :: rho(ixi^s),te(ixi^s)
272  double precision :: qvec(ixi^s,1:ndim)
273  double precision, allocatable, dimension(:^D&,:) :: qvec_equi
274 
275  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
276  double precision :: alpha,dxinv(ndim)
277  integer :: idims,idir,ix^d,ix^l,ixc^l,ixa^l,ixb^l
278 
279  ! coefficient of limiting on normal component
280  if(ndim<3) then
281  alpha=0.75d0
282  else
283  alpha=0.85d0
284  end if
285  ix^l=ixo^l^ladd1;
286 
287  dxinv=1.d0/dxlevel
288 
289  call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
290  call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
291  call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
292  if(fl%has_equi) then
293  allocate(qvec_equi(ixi^s,1:ndim))
294  call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
295  call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
296  call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
297  do idims=1,ndim
298  qvec(ix^s,idims)=qvec(ix^s,idims) - qvec_equi(ix^s,idims)
299  end do
300  deallocate(qvec_equi)
301  endif
302 
303  qd=0.d0
304  if(slab_uniform) then
305  do idims=1,ndim
306  qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
307  ixb^l=ixo^l-kr(idims,^d);
308  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
309  end do
310  else
311  do idims=1,ndim
312  qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
313  ixb^l=ixo^l-kr(idims,^d);
314  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
315  end do
316  qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
317  end if
318 
319  if(fix_conserve_at_step) then
320  allocate(fluxall(ixi^s,1,1:ndim))
321  fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
322  call store_flux(igrid,fluxall,1,ndim,nflux)
323  deallocate(fluxall)
324  end if
325 
326  wres(ixo^s,fl%e_)=qd(ixo^s)
327 
328  end subroutine sts_set_source_tc_mhd
329 
330  subroutine set_source_tc_mhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
332  use mod_fix_conserve
333  integer, intent(in) :: ixI^L, ixO^L
334  double precision, intent(in) :: x(ixI^S,1:ndim)
335  double precision, intent(in) :: w(ixI^S,1:nw)
336  type(tc_fluid), intent(in) :: fl
337  double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
338  double precision, intent(in) :: alpha
339  double precision, intent(out) :: qvec(ixI^S,1:ndim)
340 
341  !! qd store the heat conduction energy changing rate
342  double precision :: qd(ixI^S)
343 
344  double precision, dimension(ixI^S,1:ndir) :: mf,Bc,Bcf
345  double precision, dimension(ixI^S,1:ndim) :: gradT
346  double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,qe,Binv,minq,maxq,Bnorm
347  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
348  integer, dimension(ndim) :: lowindex
349  integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
350 
351  ix^l=ixo^l^ladd1;
352 
353  ! T gradient at cell faces
354  ! B vector
355  if(b0field) then
356  mf(ixi^s,:)=w(ixi^s,iw_mag(:))+block%B0(ixi^s,:,0)
357  else
358  mf(ixi^s,:)=w(ixi^s,iw_mag(:))
359  end if
360  ! |B|
361  binv(ix^s)=dsqrt(sum(mf(ix^s,:)**2,dim=ndim+1))
362  where(binv(ix^s)/=0.d0)
363  binv(ix^s)=1.d0/binv(ix^s)
364  elsewhere
365  binv(ix^s)=bigdouble
366  end where
367  ! b unit vector: magnetic field direction vector
368  do idims=1,ndim
369  mf(ix^s,idims)=mf(ix^s,idims)*binv(ix^s)
370  end do
371  ! ixC is cell-corner index
372  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
373  ! b unit vector at cell corner
374  bc=0.d0
375  {do ix^db=0,1\}
376  ixamin^d=ixcmin^d+ix^d;
377  ixamax^d=ixcmax^d+ix^d;
378  bc(ixc^s,1:ndim)=bc(ixc^s,1:ndim)+mf(ixa^s,1:ndim)
379  {end do\}
380  bc(ixc^s,1:ndim)=bc(ixc^s,1:ndim)*0.5d0**ndim
381  ! T gradient at cell faces
382  gradt=0.d0
383  do idims=1,ndim
384  ixbmin^d=ixmin^d;
385  ixbmax^d=ixmax^d-kr(idims,^d);
386  call gradientc(te,ixi^l,ixb^l,idims,minq)
387  gradt(ixb^s,idims)=minq(ixb^s)
388  end do
389  if(fl%tc_constant) then
390  if(fl%tc_perpendicular) then
391  ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
392  ke(ixc^s)=fl%tc_k_perp
393  else
394  ka(ixc^s)=fl%tc_k_para
395  end if
396  else
397  ! conductivity at cell center
398  if(phys_trac) then
399  minq(ix^s)=te(ix^s)
400  where(minq(ix^s) < block%wextra(ix^s,fl%Tcoff_))
401  minq(ix^s)=block%wextra(ix^s,fl%Tcoff_)
402  end where
403  minq(ix^s)=fl%tc_k_para*sqrt(minq(ix^s)**5)
404  else
405  minq(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
406  end if
407  ka=0.d0
408  {do ix^db=0,1\}
409  ixbmin^d=ixcmin^d+ix^d;
410  ixbmax^d=ixcmax^d+ix^d;
411  ka(ixc^s)=ka(ixc^s)+minq(ixb^s)
412  {end do\}
413  ! cell corner conductivity
414  ka(ixc^s)=0.5d0**ndim*ka(ixc^s)
415  ! compensate with perpendicular conductivity
416  if(fl%tc_perpendicular) then
417  minq(ix^s)=fl%tc_k_perp*rho(ix^s)**2*binv(ix^s)**2/dsqrt(te(ix^s))
418  ke=0.d0
419  {do ix^db=0,1\}
420  ixbmin^d=ixcmin^d+ix^d;
421  ixbmax^d=ixcmax^d+ix^d;
422  ke(ixc^s)=ke(ixc^s)+minq(ixb^s)
423  {end do\}
424  ! cell corner conductivity: k_parallel-k_perpendicular
425  ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
426  where(ke(ixc^s)<ka(ixc^s))
427  ka(ixc^s)=ka(ixc^s)-ke(ixc^s)
428  elsewhere
429  ka(ixc^s)=0.d0
430  ke(ixc^s)=ka(ixc^s)
431  end where
432  end if
433  end if
434  if(fl%tc_slope_limiter=='no') then
435  ! calculate thermal conduction flux with symmetric scheme
436  do idims=1,ndim
437  !qd corner values
438  qd=0.d0
439  {do ix^db=0,1 \}
440  if({ ix^d==0 .and. ^d==idims | .or.}) then
441  ixbmin^d=ixcmin^d+ix^d;
442  ixbmax^d=ixcmax^d+ix^d;
443  qd(ixc^s)=qd(ixc^s)+gradt(ixb^s,idims)
444  end if
445  {end do\}
446  ! temperature gradient at cell corner
447  qvec(ixc^s,idims)=qd(ixc^s)*0.5d0**(ndim-1)
448  end do
449  ! b grad T at cell corner
450  qd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
451  do idims=1,ndim
452  ! TC flux at cell corner
453  gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qd(ixc^s)
454  if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
455  end do
456  ! TC flux at cell face
457  qvec=0.d0
458  do idims=1,ndim
459  ixb^l=ixo^l-kr(idims,^d);
460  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
461  {do ix^db=0,1 \}
462  if({ ix^d==0 .and. ^d==idims | .or.}) then
463  ixbmin^d=ixamin^d-ix^d;
464  ixbmax^d=ixamax^d-ix^d;
465  qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
466  end if
467  {end do\}
468  qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
469  if(fl%tc_saturate) then
470  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
471  ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
472  bcf=0.d0
473  {do ix^db=0,1 \}
474  if({ ix^d==0 .and. ^d==idims | .or.}) then
475  ixbmin^d=ixamin^d-ix^d;
476  ixbmax^d=ixamax^d-ix^d;
477  bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
478  end if
479  {end do\}
480  ! averaged b at face centers
481  bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
482  ixb^l=ixa^l+kr(idims,^d);
483  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))
484  {do ix^db=ixamin^db,ixamax^db\}
485  if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
486  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
487  end if
488  {end do\}
489  end if
490  end do
491  else
492  ! calculate thermal conduction flux with slope-limited symmetric scheme
493  qvec=0.d0
494  do idims=1,ndim
495  ixb^l=ixo^l-kr(idims,^d);
496  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
497  ! calculate normal of magnetic field
498  ixb^l=ixa^l+kr(idims,^d);
499  bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
500  bcf=0.d0
501  kaf=0.d0
502  kef=0.d0
503  {do ix^db=0,1 \}
504  if({ ix^d==0 .and. ^d==idims | .or.}) then
505  ixbmin^d=ixamin^d-ix^d;
506  ixbmax^d=ixamax^d-ix^d;
507  bcf(ixa^s,1:ndim)=bcf(ixa^s,1:ndim)+bc(ixb^s,1:ndim)
508  kaf(ixa^s)=kaf(ixa^s)+ka(ixb^s)
509  if(fl%tc_perpendicular) kef(ixa^s)=kef(ixa^s)+ke(ixb^s)
510  end if
511  {end do\}
512  ! averaged b at face centers
513  bcf(ixa^s,1:ndim)=bcf(ixa^s,1:ndim)*0.5d0**(ndim-1)
514  ! averaged thermal conductivity at face centers
515  kaf(ixa^s)=kaf(ixa^s)*0.5d0**(ndim-1)
516  if(fl%tc_perpendicular) kef(ixa^s)=kef(ixa^s)*0.5d0**(ndim-1)
517  ! limited normal component
518  minq(ixa^s)=min(alpha*gradt(ixa^s,idims),gradt(ixa^s,idims)/alpha)
519  maxq(ixa^s)=max(alpha*gradt(ixa^s,idims),gradt(ixa^s,idims)/alpha)
520  ! eq (19)
521  !corner values of gradT
522  qdd=0.d0
523  {do ix^db=0,1 \}
524  if({ ix^d==0 .and. ^d==idims | .or.}) then
525  ixbmin^d=ixcmin^d+ix^d;
526  ixbmax^d=ixcmax^d+ix^d;
527  qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
528  end if
529  {end do\}
530  ! temperature gradient at cell corner
531  qdd(ixc^s)=qdd(ixc^s)*0.5d0**(ndim-1)
532  ! eq (21)
533  qe=0.d0
534  {do ix^db=0,1 \}
535  qd(ixc^s)=qdd(ixc^s)
536  if({ ix^d==0 .and. ^d==idims | .or.}) then
537  ixbmin^d=ixamin^d-ix^d;
538  ixbmax^d=ixamax^d-ix^d;
539  where(qd(ixb^s)<=minq(ixa^s))
540  qd(ixb^s)=minq(ixa^s)
541  elsewhere(qd(ixb^s)>=maxq(ixa^s))
542  qd(ixb^s)=maxq(ixa^s)
543  end where
544  qvec(ixa^s,idims)=qvec(ixa^s,idims)+bc(ixb^s,idims)**2*qd(ixb^s)
545  if(fl%tc_perpendicular) qe(ixa^s)=qe(ixa^s)+qd(ixb^s)
546  end if
547  {end do\}
548  qvec(ixa^s,idims)=kaf(ixa^s)*qvec(ixa^s,idims)*0.5d0**(ndim-1)
549  ! add normal flux from perpendicular conduction
550  if(fl%tc_perpendicular) qvec(ixa^s,idims)=qvec(ixa^s,idims)+kef(ixa^s)*qe(ixa^s)*0.5d0**(ndim-1)
551  ! limited transverse component, eq (17)
552  ixbmin^d=ixamin^d;
553  ixbmax^d=ixamax^d+kr(idims,^d);
554  do idir=1,ndim
555  if(idir==idims) cycle
556  qd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
557  qd(ixi^s)=slope_limiter(qd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
558  qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qd(ixa^s)
559  end do
560 
561  ! consider magnetic null point
562  !where(Binv(ixA^S)==0.d0)
563  ! qvec(ixA^S,idims)=tc_k_para*(0.5d0*(Te(ixA^S)+Te(ixB^S)))**2.5d0*gradT(ixA^S,idims)
564  !end where
565 
566  if(fl%tc_saturate) then
567  ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
568  ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
569  ixb^l=ixa^l+kr(idims,^d);
570  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))
571  {do ix^db=ixamin^db,ixamax^db\}
572  if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
573  ! write(*,*) 'it',it,qvec(ix^D,idims),qd(ix^D),' TC saturated at ',&
574  ! x(ix^D,:),' rho',rho(ix^D),' Te',Te(ix^D)
575  qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
576  end if
577  {end do\}
578  end if
579  end do
580  end if
581 
582  end subroutine set_source_tc_mhd
583 
584  function slope_limiter(f,ixI^L,ixO^L,idims,pm,tc_slope_limiter) result(lf)
586  integer, intent(in) :: ixi^l, ixo^l, idims, pm
587  double precision, intent(in) :: f(ixi^s)
588  double precision :: lf(ixi^s)
589  character(len=*), intent(in) :: tc_slope_limiter
590 
591  double precision :: signf(ixi^s)
592  integer :: ixb^l
593 
594  ixb^l=ixo^l+pm*kr(idims,^d);
595  signf(ixo^s)=sign(1.d0,f(ixo^s))
596  select case(tc_slope_limiter)
597  case('minmod')
598  ! minmod limiter
599  lf(ixo^s)=signf(ixo^s)*max(0.d0,min(abs(f(ixo^s)),signf(ixo^s)*f(ixb^s)))
600  case ('MC')
601  ! montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
602  lf(ixo^s)=two*signf(ixo^s)* &
603  max(zero,min(dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s),&
604  signf(ixo^s)*quarter*(f(ixb^s)+f(ixo^s))))
605  case ('superbee')
606  ! Roes superbee limiter (eq.3.51i)
607  lf(ixo^s)=signf(ixo^s)* &
608  max(zero,min(two*dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s)),&
609  min(dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s)))
610  case ('koren')
611  ! Barry Koren Right variant
612  lf(ixo^s)=signf(ixo^s)* &
613  max(zero,min(two*dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s),&
614  (two*f(ixb^s)*signf(ixo^s)+dabs(f(ixo^s)))*third))
615  case default
616  call mpistop("Unknown slope limiter for thermal conduction")
617  end select
618 
619  end function slope_limiter
620 
621  !> Calculate gradient of a scalar q at cell interfaces in direction idir
622  subroutine gradientc(q,ixI^L,ixO^L,idir,gradq)
624 
625  integer, intent(in) :: ixI^L, ixO^L, idir
626  double precision, intent(in) :: q(ixI^S)
627  double precision, intent(inout) :: gradq(ixI^S)
628  integer :: jxO^L
629 
630  associate(x=>block%x)
631 
632  jxo^l=ixo^l+kr(idir,^d);
633  select case(coordinate)
634  case(cartesian)
635  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/dxlevel(idir)
636  case(cartesian_stretched)
637  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,idir)-x(ixo^s,idir))
638  case(spherical)
639  select case(idir)
640  case(1)
641  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,1)-x(ixo^s,1))
642  {^nooned
643  case(2)
644  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/( (x(jxo^s,2)-x(ixo^s,2))*x(ixo^s,1) )
645  }
646  {^ifthreed
647  case(3)
648  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)) )
649  }
650  end select
651  case(cylindrical)
652  if(idir==phi_) then
653  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/((x(jxo^s,phi_)-x(ixo^s,phi_))*x(ixo^s,r_))
654  else
655  gradq(ixo^s)=(q(jxo^s)-q(ixo^s))/(x(jxo^s,idir)-x(ixo^s,idir))
656  end if
657  case default
658  call mpistop('Unknown geometry')
659  end select
660 
661  end associate
662  end subroutine gradientc
663 
664  function get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
665  ! Check diffusion time limit dt < dx_i**2 / ((gamma-1)*tc_k_para_i/rho)
667 
668  integer, intent(in) :: ixi^l, ixo^l
669  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
670  double precision, intent(in) :: w(ixi^s,1:nw)
671  type(tc_fluid), intent(in) :: fl
672  double precision :: dtnew
673 
674  double precision :: dxinv(1:ndim), tmp(ixi^s), te(ixi^s), rho(ixi^s)
675  double precision :: dtdiff_tcond,dtdiff_tsat
676  integer :: idim,ix^d
677 
678  ^d&dxinv(^d)=one/dx^d;
679 
680  call fl%get_temperature_from_conserved(w,x,ixi^l,ixo^l,te)
681  call fl%get_rho(w,x,ixi^l,ixo^l,rho)
682 
683  tmp(ixo^s)=tc_gamma_1*fl%tc_k_para*dsqrt((te(ixo^s))**5)/rho(ixo^s)
684  dtnew = bigdouble
685 
686  do idim=1,ndim
687  ! dt< dx_idim**2/((gamma-1)*tc_k_para_idim/rho)
688  dtdiff_tcond=1d0/maxval(tmp(ixo^s)*dxinv(idim)**2)
689  if(fl%tc_saturate) then
690  ! dt< dx_idim**2/((gamma-1)*sqrt(Te)*5*phi)
691  dtdiff_tsat=1d0/maxval(tc_gamma_1*dsqrt(te(ixo^s))*&
692  5.d0*dxinv(idim)**2)
693  ! choose the slower flux (bigger time scale) between classic and saturated
694  dtdiff_tcond=max(dtdiff_tcond,dtdiff_tsat)
695  end if
696  ! limit the time step
697  dtnew=min(dtnew,dtdiff_tcond)
698  end do
699  dtnew=dtnew/dble(ndim)
700 
701  end function get_tc_dt_hd
702 
703  subroutine sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
705  use mod_fix_conserve
706 
707  integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
708  double precision, intent(in) :: x(ixi^s,1:ndim)
709  double precision, intent(in) :: w(ixi^s,1:nw)
710  double precision, intent(inout) :: wres(ixi^s,1:nw)
711  double precision, intent(in) :: my_dt
712  logical, intent(in) :: fix_conserve_at_step
713  type(tc_fluid), intent(in) :: fl
714 
715  double precision :: te(ixi^s),rho(ixi^s)
716  double precision :: qvec(ixi^s,1:ndim),qd(ixi^s)
717  double precision, allocatable, dimension(:^D&,:) :: qvec_equi
718  double precision, allocatable, dimension(:^D&,:,:) :: fluxall
719 
720  double precision :: dxinv(ndim)
721  integer :: idims,ix^l,ixb^l
722 
723  ix^l=ixo^l^ladd1;
724 
725  dxinv=1.d0/dxlevel
726 
727  !calculate Te in whole domain (+ghosts)
728  call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te)
729  call fl%get_rho(w, x, ixi^l, ixi^l, rho)
730  call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
731  if(fl%has_equi) then
732  allocate(qvec_equi(ixi^s,1:ndim))
733  call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
734  call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
735  call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
736  do idims=1,ndim
737  qvec(ix^s,idims)=qvec(ix^s,idims) - qvec_equi(ix^s,idims)
738  end do
739  deallocate(qvec_equi)
740  endif
741 
742 
743  qd=0.d0
744  if(slab_uniform) then
745  do idims=1,ndim
746  qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
747  ixb^l=ixo^l-kr(idims,^d);
748  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
749  end do
750  else
751  do idims=1,ndim
752  qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
753  ixb^l=ixo^l-kr(idims,^d);
754  qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
755  end do
756  qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
757  end if
758 
759  if(fix_conserve_at_step) then
760  allocate(fluxall(ixi^s,1,1:ndim))
761  fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
762  call store_flux(igrid,fluxall,1,ndim,nflux)
763  deallocate(fluxall)
764  end if
765  wres(ixo^s,fl%e_)=qd(ixo^s)
766 
767  end subroutine sts_set_source_tc_hd
768 
769  subroutine set_source_tc_hd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
771  use mod_fix_conserve
772 
773  integer, intent(in) :: ixI^L, ixO^L
774  double precision, intent(in) :: x(ixI^S,1:ndim)
775  double precision, intent(in) :: w(ixI^S,1:nw)
776  type(tc_fluid), intent(in) :: fl
777  double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
778  double precision, intent(out) :: qvec(ixI^S,1:ndim)
779 
780 
781  double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
782 
783  double precision :: dxinv(ndim)
784  integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L,ixD^L
785 
786  ix^l=ixo^l^ladd1;
787  ! ixC is cell-corner index
788  ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
789 
790  dxinv=1.d0/dxlevel
791 
792  !calculate Te in whole domain (+ghosts)
793  ! cell corner temperature in ke
794  ke=0.d0
795  ixamax^d=ixmax^d; ixamin^d=ixmin^d-1;
796  {do ix^db=0,1\}
797  ixbmin^d=ixamin^d+ix^d;
798  ixbmax^d=ixamax^d+ix^d;
799  ke(ixa^s)=ke(ixa^s)+te(ixb^s)
800  {end do\}
801  ke(ixa^s)=0.5d0**ndim*ke(ixa^s)
802  ! T gradient (central difference) at cell corners
803  gradt=0.d0
804  do idims=1,ndim
805  ixbmin^d=ixmin^d;
806  ixbmax^d=ixmax^d-kr(idims,^d);
807  call gradient(ke,ixi^l,ixb^l,idims,qd)
808  gradt(ixb^s,idims)=qd(ixb^s)
809  end do
810  ! transition region adaptive conduction
811  if(phys_trac) then
812  where(ke(ixi^s) < block%wextra(ixi^s,fl%Tcoff_))
813  ke(ixi^s)=block%wextra(ixi^s,fl%Tcoff_)
814  end where
815  end if
816  ! cell corner conduction flux
817  do idims=1,ndim
818  gradt(ixc^s,idims)=gradt(ixc^s,idims)*fl%tc_k_para*sqrt(ke(ixc^s)**5)
819  end do
820 
821  if(fl%tc_saturate) then
822  ! consider saturation with unsigned saturated TC flux = 5 phi rho c**3
823  ! saturation flux at cell center
824  qd(ix^s)=5.d0*rho(ix^s)*dsqrt(te(ix^s)**3)
825  !cell corner values of qd in ke
826  ke=0.d0
827  {do ix^db=0,1\}
828  ixbmin^d=ixcmin^d+ix^d;
829  ixbmax^d=ixcmax^d+ix^d;
830  ke(ixc^s)=ke(ixc^s)+qd(ixb^s)
831  {end do\}
832  ! cell corner saturation flux
833  ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
834  ! magnitude of cell corner conduction flux
835  qd(ixc^s)=norm2(gradt(ixc^s,:),dim=ndim+1)
836  {do ix^db=ixcmin^db,ixcmax^db\}
837  if(qd(ix^d)>ke(ix^d)) then
838  ke(ix^d)=ke(ix^d)/qd(ix^d)
839  do idims=1,ndim
840  gradt(ix^d,idims)=ke(ix^d)*gradt(ix^d,idims)
841  end do
842  end if
843  {end do\}
844  end if
845 
846  ! conductionflux at cell face
847  !face center values of gradT in qvec
848  qvec=0.d0
849  do idims=1,ndim
850  ixb^l=ixo^l-kr(idims,^d);
851  ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
852  {do ix^db=0,1 \}
853  if({ ix^d==0 .and. ^d==idims | .or.}) then
854  ixbmin^d=ixamin^d-ix^d;
855  ixbmax^d=ixamax^d-ix^d;
856  qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
857  end if
858  {end do\}
859  qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
860  end do
861 
862 
863  end subroutine set_source_tc_hd
864 
865 
866 
867 
868 end module mod_thermal_conduction
subroutine mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: comm_lib.t:194
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
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.
integer, dimension(:), allocatable, parameter d
integer ndir
Number of spatial dimensions (components) for vector variables.
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
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
double precision, dimension(ndim) dxlevel
Thermal conduction for HD and MHD Adaptation of mod_thermal_conduction for the mod_supertimestepping ...
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)
Read tc module parameters from par file: MHD case.
subroutine set_source_tc_mhd(ixIL, ixOL, w, x, fl, qvec, rho, Te, alpha)
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_mhd(ixIL, ixOL, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
subroutine gradientc(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q at cell interfaces in direction idir.
double precision function, public get_tc_dt_hd(w, ixIL, ixOL, dxD, x, fl)
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 coeffiecients: MHD case.
double precision function, dimension(ixi^s) slope_limiter(f, ixIL, ixOL, idims, pm, tc_slope_limiter)
double precision function, public get_tc_dt_mhd(w, ixIL, ixOL, dxD, x, fl)
Get the explicut timestep for the TC (mhd implementation)