MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
Loading...
Searching...
No Matches
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
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 public :: tc_get_mhd_params
99 public :: tc_get_hd_params
100 public :: get_tc_dt_mhd
101 public :: get_tc_dt_hd
102 public :: sts_set_source_tc_mhd
103 public :: sts_set_source_tc_hd
104
105contains
106
107 subroutine tc_init_params(phys_gamma)
109 double precision, intent(in) :: phys_gamma
110
111 tc_gamma_1=phys_gamma-1d0
112 end subroutine tc_init_params
113
114 !> Init TC coefficients: MHD case
115 subroutine tc_get_mhd_params(fl,read_mhd_params)
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 type(tc_fluid), intent(inout) :: fl
127
128 fl%tc_slope_limiter=1
129 fl%tc_k_para=0.d0
130 fl%tc_k_perp=0.d0
131
132 !> Read tc module parameters from par file: MHD case
133 call read_mhd_params(fl)
134
135 if(fl%tc_k_para==0.d0 .and. fl%tc_k_perp==0.d0) then
136 if(si_unit) then
137 ! Spitzer thermal conductivity with SI units
138 fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
139 ! thermal conductivity perpendicular to magnetic field
140 fl%tc_k_perp=4.d-30*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
141 else
142 ! Spitzer thermal conductivity with cgs units
143 fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
144 ! thermal conductivity perpendicular to magnetic field
145 fl%tc_k_perp=4.d-10*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
146 end if
147 if(mype .eq. 0) print*, "Spitzer MHD: par: ",fl%tc_k_para, &
148 " ,perp: ",fl%tc_k_perp
149 else
150 fl%tc_constant=.true.
151 end if
152 end subroutine tc_get_mhd_params
153
154 !> Init TC coefficients: HD case
155 subroutine tc_get_hd_params(fl,read_hd_params)
157
158 interface
159 subroutine read_hd_params(fl)
161 import tc_fluid
162 type(tc_fluid), intent(inout) :: fl
163
164 end subroutine read_hd_params
165 end interface
166 type(tc_fluid), intent(inout) :: fl
167
168 fl%tc_k_para=0.d0
169
170 !> Read tc parameters from par file: HD case
171 call read_hd_params(fl)
172
173 if(fl%tc_k_para==0.d0) then
174 if(si_unit) then
175 ! Spitzer thermal conductivity with SI units
176 fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
177 else
178 ! Spitzer thermal conductivity with cgs units
179 fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
180 end if
181 if(mype .eq. 0) print*, "Spitzer HD par: ",fl%tc_k_para
182 end if
183
184 end subroutine tc_get_hd_params
185
186 !> Get the explicut timestep for the TC (mhd implementation)
187 function get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
188 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
189 !where tc_k_para_i=tc_k_para*B_i**2/B**2
190 !and T=p/rho
192
193 type(tc_fluid), intent(in) :: fl
194 integer, intent(in) :: ixi^l, ixo^l
195 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
196 double precision, intent(in) :: w(ixi^s,1:nw)
197 double precision :: dtnew
198
199 double precision :: mf(ixo^s,1:ndim),te(ixi^s),rho(ixi^s),gradt(ixi^s)
200 double precision :: tmp(ixo^s),hfs(ixo^s),blocal(1:ndim)
201 double precision :: dtdiff_tcond,maxtmp2
202 integer :: idims,ix^d
203
204 !temperature
205 call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
206
207 ! B
208 if(allocated(iw_mag)) then
209 if(b0field) then
210 {do ix^db=ixomin^db,ixomax^db\}
211 ^d&blocal(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
212 {^iftwod
213 if(blocal(1)/=0.d0) then
214 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2)
215 else
216 mf(ix^d,1)=0.d0
217 end if
218 if(blocal(2)/=0.d0) then
219 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2)
220 else
221 mf(ix^d,2)=0.d0
222 end if
223 }
224 {^ifthreed
225 if(blocal(1)/=0.d0) then
226 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2+(blocal(3)/blocal(1))**2)
227 else
228 mf(ix^d,1)=0.d0
229 end if
230 if(blocal(2)/=0.d0) then
231 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2+(blocal(3)/blocal(2))**2)
232 else
233 mf(ix^d,2)=0.d0
234 end if
235 if(blocal(3)/=0.d0) then
236 mf(ix^d,3)=sign(1.d0,blocal(3))/dsqrt(1.d0+(blocal(1)/blocal(3))**2+(blocal(2)/blocal(3))**2)
237 else
238 mf(ix^d,3)=0.d0
239 end if
240 }
241 {end do\}
242 else
243 {do ix^db=ixomin^db,ixomax^db\}
244 {^iftwod
245 if(w(ix^d,iw_mag(1))/=0.d0) then
246 mf(ix^d,1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2)
247 else
248 mf(ix^d,1)=0.d0
249 end if
250 if(w(ix^d,iw_mag(2))/=0.d0) then
251 mf(ix^d,2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2)
252 else
253 mf(ix^d,2)=0.d0
254 end if
255 }
256 {^ifthreed
257 if(w(ix^d,iw_mag(1))/=0.d0) then
258 mf(ix^d,1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2+&
259 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
260 else
261 mf(ix^d,1)=0.d0
262 end if
263 if(w(ix^d,iw_mag(2))/=0.d0) then
264 mf(ix^d,2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2+&
265 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
266 else
267 mf(ix^d,2)=0.d0
268 end if
269 if(w(ix^d,iw_mag(3))/=0.d0) then
270 mf(ix^d,3)=sign(1.d0,w(ix^d,iw_mag(3)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(3)))**2+&
271 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
272 else
273 mf(ix^d,3)=0.d0
274 end if
275 }
276 {end do\}
277 end if
278 else
279 mf(ixo^s,1:ndim)=block%B0(ixo^s,1:ndim,0)
280 end if
281
282 dtnew=bigdouble
283 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
284
285 !tc_k_para_i
286 if(fl%tc_constant) then
287 tmp(ixo^s)=fl%tc_k_para
288 else
289 if(fl%tc_saturate) then
290 ! Kannan 2016 MN 458, 410
291 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
292 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
293 tmp(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
294 do idims=1,ndim
295 call gradient(te,ixi^l,ixo^l,idims,gradt)
296 if(idims==1) then
297 hfs(ixo^s)=gradt(ixo^s)*mf(ixo^s,idims)
298 else
299 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)*mf(ixo^s,idims)
300 end if
301 end do
302 ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT.b|))
303 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))
304 else
305 ! kappa=kappa_Spizer
306 tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)
307 end if
308 end if
309
310 do idims=1,ndim
311 ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
312 maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)**2/(rho(ixo^s)*block%ds(ixo^s,idims)**2))
313 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
314 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+1.d-307)
315 ! limit the time step
316 dtnew=min(dtnew,dtdiff_tcond)
317 end do
318 dtnew=dtnew/dble(ndim)
319 end function get_tc_dt_mhd
320
321 !> anisotropic thermal conduction with slope limited symmetric scheme
322 !> Sharma 2007 Journal of Computational Physics 227, 123
323 subroutine sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
326 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
327 double precision, intent(in) :: x(ixi^s,1:ndim)
328 double precision, intent(in) :: w(ixi^s,1:nw)
329 double precision, intent(inout) :: wres(ixi^s,1:nw)
330 double precision, intent(in) :: my_dt
331 logical, intent(in) :: fix_conserve_at_step
332 type(tc_fluid), intent(in) :: fl
333
334 !! qd store the heat conduction energy changing rate
335 double precision :: qd(ixo^s)
336 double precision :: rho(ixi^s),te(ixi^s)
337 double precision :: qvec(ixi^s,1:ndim)
338 double precision :: fluxall(ixi^s,1,1:ndim)
339 double precision :: alpha,dxinv(ndim)
340 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
341 integer :: idims,ixa^l
342
343 ! coefficient of limiting on normal component
344 if(ndim<3) then
345 alpha=0.75d0
346 else
347 alpha=0.85d0
348 end if
349
350 dxinv=1.d0/dxlevel
351
352 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
353 call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
354 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
355 if(fl%has_equi) then
356 allocate(qvec_equi(ixi^s,1:ndim))
357 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
358 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
359 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
360 do idims=1,ndim
361 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
362 qvec(ixa^s,idims)=qvec(ixa^s,idims)-qvec_equi(ixa^s,idims)
363 end do
364 deallocate(qvec_equi)
365 end if
366
367 if(slab_uniform) then
368 do idims=1,ndim
369 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
370 qvec(ixa^s,idims)=dxinv(idims)*qvec(ixa^s,idims)
371 ixa^l=ixo^l-kr(idims,^d);
372 if(idims==1) then
373 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
374 else
375 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
376 end if
377 end do
378 else
379 do idims=1,ndim
380 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
381 qvec(ixa^s,idims)=qvec(ixa^s,idims)*block%surfaceC(ixa^s,idims)
382 ixa^l=ixo^l-kr(idims,^d);
383 if(idims==1) then
384 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
385 else
386 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
387 end if
388 end do
389 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
390 end if
391
392 if(fix_conserve_at_step) then
393 do idims=1,ndim
394 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
395 fluxall(ixa^s,1,idims)=my_dt*qvec(ixa^s,idims)
396 end do
397 call store_flux(igrid,fluxall,1,ndim,nflux)
398 end if
399
400 wres(ixo^s,fl%e_)=qd(ixo^s)
401 end subroutine sts_set_source_tc_mhd
402
403 subroutine set_source_tc_mhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
405 integer, intent(in) :: ixI^L, ixO^L
406 double precision, intent(in) :: x(ixI^S,1:ndim)
407 double precision, intent(in) :: w(ixI^S,1:nw)
408 type(tc_fluid), intent(in) :: fl
409 double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
410 double precision, intent(in) :: alpha
411 double precision, intent(out) :: qvec(ixI^S,1:ndim)
412
413 !! qdd store the heat conduction energy changing rate
414 double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf,gradT
415 double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,Bnorm
416 double precision :: minq,maxq,qd(ixI^S,2**(ndim-1)), Blocal(ndim)
417 integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
418
419 ix^l=ixo^l^ladd1;
420
421 ! T gradient at cell faces
422 ! b unit vector mf: magnetic field direction vector
423 if(allocated(iw_mag)) then
424 if(b0field) then
425 {do ix^db=ixmin^db,ixmax^db\}
426 ^d&blocal(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
427 {^iftwod
428 if(blocal(1)/=0.d0) then
429 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2)
430 else
431 mf(ix^d,1)=0.d0
432 end if
433 if(blocal(2)/=0.d0) then
434 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2)
435 else
436 mf(ix^d,2)=0.d0
437 end if
438 }
439 {^ifthreed
440 if(blocal(1)/=0.d0) then
441 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2+(blocal(3)/blocal(1))**2)
442 else
443 mf(ix^d,1)=0.d0
444 end if
445 if(blocal(2)/=0.d0) then
446 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2+(blocal(3)/blocal(2))**2)
447 else
448 mf(ix^d,2)=0.d0
449 end if
450 if(blocal(3)/=0.d0) then
451 mf(ix^d,3)=sign(1.d0,blocal(3))/dsqrt(1.d0+(blocal(1)/blocal(3))**2+(blocal(2)/blocal(3))**2)
452 else
453 mf(ix^d,3)=0.d0
454 end if
455 }
456 {end do\}
457 else
458 {do ix^db=ixmin^db,ixmax^db\}
459 {^iftwod
460 if(w(ix^d,iw_mag(1))/=0.d0) then
461 mf(ix^d,1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2)
462 else
463 mf(ix^d,1)=0.d0
464 end if
465 if(w(ix^d,iw_mag(2))/=0.d0) then
466 mf(ix^d,2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2)
467 else
468 mf(ix^d,2)=0.d0
469 end if
470 }
471 {^ifthreed
472 if(w(ix^d,iw_mag(1))/=0.d0) then
473 mf(ix^d,1)=sign(1.d0,w(ix^d,iw_mag(1)))/dsqrt(1.d0+(w(ix^d,iw_mag(2))/w(ix^d,iw_mag(1)))**2+&
474 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
475 else
476 mf(ix^d,1)=0.d0
477 end if
478 if(w(ix^d,iw_mag(2))/=0.d0) then
479 mf(ix^d,2)=sign(1.d0,w(ix^d,iw_mag(2)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(2)))**2+&
480 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
481 else
482 mf(ix^d,2)=0.d0
483 end if
484 if(w(ix^d,iw_mag(3))/=0.d0) then
485 mf(ix^d,3)=sign(1.d0,w(ix^d,iw_mag(3)))/dsqrt(1.d0+(w(ix^d,iw_mag(1))/w(ix^d,iw_mag(3)))**2+&
486 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
487 else
488 mf(ix^d,3)=0.d0
489 end if
490 }
491 {end do\}
492 end if
493 else
494 mf(ix^s,1:ndim)=block%B0(ix^s,1:ndim,0)
495 endif
496 ! ixC is cell-corner index
497 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
498 ! b unit vector at cell corner
499 {^ifthreed
500 do idims=1,3
501 {do ix^db=ixcmin^db,ixcmax^db\}
502 bc(ix^d,idims)=0.125d0*(mf(ix1,ix2,ix3,idims)+mf(ix1+1,ix2,ix3,idims)&
503 +mf(ix1,ix2+1,ix3,idims)+mf(ix1+1,ix2+1,ix3,idims)&
504 +mf(ix1,ix2,ix3+1,idims)+mf(ix1+1,ix2,ix3+1,idims)&
505 +mf(ix1,ix2+1,ix3+1,idims)+mf(ix1+1,ix2+1,ix3+1,idims))
506 {end do\}
507 end do
508 }
509 {^iftwod
510 do idims=1,2
511 {do ix^db=ixcmin^db,ixcmax^db\}
512 bc(ix^d,idims)=0.25d0*(mf(ix1,ix2,idims)+mf(ix1+1,ix2,idims)&
513 +mf(ix1,ix2+1,idims)+mf(ix1+1,ix2+1,idims))
514 {end do\}
515 end do
516 }
517 ! T gradient at cell faces
518 do idims=1,ndim
519 ixbmin^d=ixmin^d;
520 ixbmax^d=ixmax^d-kr(idims,^d);
521 call gradientf(te,x,ixi^l,ixb^l,idims,gradt(ixi^s,idims))
522 end do
523 if(fl%tc_constant) then
524 if(fl%tc_perpendicular) then
525 ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
526 ke(ixc^s)=fl%tc_k_perp
527 else
528 ka(ixc^s)=fl%tc_k_para
529 end if
530 else
531 ! conductivity at cell center
532 if(phys_trac) then
533 {do ix^db=ixmin^db,ixmax^db\}
534 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
535 qdd(ix^d)=fl%tc_k_para*sqrt(block%wextra(ix^d,fl%Tcoff_)**5)
536 else
537 qdd(ix^d)=fl%tc_k_para*sqrt(te(ix^d)**5)
538 end if
539 {end do\}
540 else
541 qdd(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
542 end if
543 ! cell corner parallel conductivity in ka
544 {^ifthreed
545 {do ix^db=ixcmin^db,ixcmax^db\}
546 ka(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
547 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
548 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
549 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
550 {end do\}
551 }
552 {^iftwod
553 {do ix^db=ixcmin^db,ixcmax^db\}
554 ka(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
555 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
556 {end do\}
557 }
558 ! compensate with perpendicular conductivity
559 if(fl%tc_perpendicular) then
560 if(b0field) then
561 qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2/((^d&(w(ix^s,iw_mag(^d))+block%B0(ix^s,^d,0))**2+)*dsqrt(te(ix^s))+smalldouble)
562 else
563 qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2/((^d&w(ix^s,iw_mag(^d))**2+)*dsqrt(te(ix^s))+smalldouble)
564 end if
565 {^ifthreed
566 {do ix^db=ixcmin^db,ixcmax^db\}
567 ke(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
568 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
569 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
570 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
571 if(ke(ix^d)<ka(ix^d)) then
572 ka(ix^d)=ka(ix^d)-ke(ix^d)
573 else
574 ke(ix^d)=ka(ix^d)
575 ka(ix^d)=0.d0
576 end if
577 {end do\}
578 }
579 {^iftwod
580 {do ix^db=ixcmin^db,ixcmax^db\}
581 ke(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
582 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
583 if(ke(ix^d)<ka(ix^d)) then
584 ka(ix^d)=ka(ix^d)-ke(ix^d)
585 else
586 ke(ix^d)=ka(ix^d)
587 ka(ix^d)=0.d0
588 end if
589 {end do\}
590 }
591 end if
592 end if
593 if(fl%tc_slope_limiter==0) then
594 ! calculate thermal conduction flux with symmetric scheme
595 do idims=1,ndim
596 !qdd corner values
597 qdd=0.d0
598 {do ix^db=0,1 \}
599 if({ ix^d==0 .and. ^d==idims | .or.}) then
600 ixbmin^d=ixcmin^d+ix^d;
601 ixbmax^d=ixcmax^d+ix^d;
602 qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
603 end if
604 {end do\}
605 ! temperature gradient at cell corner
606 qvec(ixc^s,idims)=qdd(ixc^s)*0.5d0**(ndim-1)
607 end do
608 ! b grad T at cell corner
609 qdd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
610 do idims=1,ndim
611 ! TC flux at cell corner
612 gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qdd(ixc^s)
613 if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
614 end do
615 ! TC flux at cell face
616 qvec=0.d0
617 do idims=1,ndim
618 ixb^l=ixo^l-kr(idims,^d);
619 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
620 {do ix^db=0,1 \}
621 if({ ix^d==0 .and. ^d==idims | .or.}) then
622 ixbmin^d=ixamin^d-ix^d;
623 ixbmax^d=ixamax^d-ix^d;
624 qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
625 end if
626 {end do\}
627 qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
628 if(fl%tc_saturate) then
629 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
630 ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
631 bcf=0.d0
632 {do ix^db=0,1 \}
633 if({ ix^d==0 .and. ^d==idims | .or.}) then
634 ixbmin^d=ixamin^d-ix^d;
635 ixbmax^d=ixamax^d-ix^d;
636 bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
637 end if
638 {end do\}
639 ! averaged b at face centers
640 bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
641 ixb^l=ixa^l+kr(idims,^d);
642 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))
643 {do ix^db=ixamin^db,ixamax^db\}
644 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
645 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
646 end if
647 {end do\}
648 end if
649 end do
650 else
651 ! calculate thermal conduction flux with slope-limited symmetric scheme
652 do idims=1,ndim
653 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
654 {^ifthreed
655 if(idims==1) then
656 {do ix^db=ixamin^db,ixamax^db\}
657 ! averaged b at face centers
658 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
659 +bc(ix1,ix2,ix3-1,^d)+bc(ix1,ix2-1,ix3-1,^d))\
660 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
661 +ka(ix1,ix2,ix3-1)+ka(ix1,ix2-1,ix3-1))
662 ! averaged thermal conductivity at face centers
663 if(fl%tc_perpendicular) &
664 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
665 +ke(ix1,ix2,ix3-1)+ke(ix1,ix2-1,ix3-1))
666 {end do\}
667 else if(idims==2) then
668 {do ix^db=ixamin^db,ixamax^db\}
669 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1-1,ix2,ix3,^d)&
670 +bc(ix1,ix2,ix3-1,^d)+bc(ix1-1,ix2,ix3-1,^d))\
671 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1-1,ix2,ix3)&
672 +ka(ix1,ix2,ix3-1)+ka(ix1-1,ix2,ix3-1))
673 if(fl%tc_perpendicular) &
674 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1-1,ix2,ix3)&
675 +ke(ix1,ix2,ix3-1)+ke(ix1-1,ix2,ix3-1))
676 {end do\}
677 else
678 {do ix^db=ixamin^db,ixamax^db\}
679 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
680 +bc(ix1-1,ix2,ix3,^d)+bc(ix1-1,ix2-1,ix3,^d))\
681 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
682 +ka(ix1-1,ix2,ix3)+ka(ix1-1,ix2-1,ix3))
683 if(fl%tc_perpendicular) &
684 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
685 +ke(ix1-1,ix2,ix3)+ke(ix1-1,ix2-1,ix3))
686 {end do\}
687 end if
688 }
689 {^iftwod
690 if(idims==1) then
691 {do ix^db=ixamin^db,ixamax^db\}
692 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1,ix2-1,^d))\
693 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1,ix2-1))
694 if(fl%tc_perpendicular) &
695 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2-1))
696 {end do\}
697 else
698 {do ix^db=ixamin^db,ixamax^db\}
699 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1-1,ix2,^d))\
700 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1-1,ix2))
701 if(fl%tc_perpendicular) &
702 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1-1,ix2))
703 {end do\}
704 end if
705 }
706 ! eq (19)
707 ! temperature gradient at cell corner
708 {^ifthreed
709 if(idims==1) then
710 {do ix^db=ixcmin^db,ixcmax^db\}
711 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2+1,ix3,idims)&
712 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1,ix2+1,ix3+1,idims))
713 {end do\}
714 else if(idims==2) then
715 {do ix^db=ixcmin^db,ixcmax^db\}
716 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
717 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1+1,ix2,ix3+1,idims))
718 {end do\}
719 else
720 {do ix^db=ixcmin^db,ixcmax^db\}
721 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
722 +gradt(ix1,ix2+1,ix3,idims)+gradt(ix1+1,ix2+1,ix3,idims))
723 {end do\}
724 end if
725 }
726 {^iftwod
727 if(idims==1) then
728 {do ix^db=ixcmin^db,ixcmax^db\}
729 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2+1,idims))
730 {end do\}
731 else
732 {do ix^db=ixcmin^db,ixcmax^db\}
733 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1+1,ix2,idims))
734 {end do\}
735 end if
736 }
737 ! eq (21)
738 {^ifthreed
739 if(idims==1) then
740 {do ix^db=ixamin^db,ixamax^db\}
741 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
742 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
743 if(qdd(ix^d)<minq) then
744 qd(ix^d,1)=minq
745 else if(qdd(ix^d)>maxq) then
746 qd(ix^d,1)=maxq
747 else
748 qd(ix^d,1)=qdd(ix^d)
749 end if
750 if(qdd(ix1,ix2-1,ix3)<minq) then
751 qd(ix^d,2)=minq
752 else if(qdd(ix1,ix2-1,ix3)>maxq) then
753 qd(ix^d,2)=maxq
754 else
755 qd(ix^d,2)=qdd(ix1,ix2-1,ix3)
756 end if
757 if(qdd(ix1,ix2,ix3-1)<minq) then
758 qd(ix^d,3)=minq
759 else if(qdd(ix1,ix2,ix3-1)>maxq) then
760 qd(ix^d,3)=maxq
761 else
762 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
763 end if
764 if(qdd(ix1,ix2-1,ix3-1)<minq) then
765 qd(ix^d,4)=minq
766 else if(qdd(ix1,ix2-1,ix3-1)>maxq) then
767 qd(ix^d,4)=maxq
768 else
769 qd(ix^d,4)=qdd(ix1,ix2-1,ix3-1)
770 end if
771 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)&
772 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1,ix2-1,ix3-1,idims)**2*qd(ix^d,4))
773 if(fl%tc_perpendicular) &
774 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))
775 {end do\}
776 else if(idims==2) then
777 {do ix^db=ixamin^db,ixamax^db\}
778 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
779 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
780 if(qdd(ix^d)<minq) then
781 qd(ix^d,1)=minq
782 else if(qdd(ix^d)>maxq) then
783 qd(ix^d,1)=maxq
784 else
785 qd(ix^d,1)=qdd(ix^d)
786 end if
787 if(qdd(ix1-1,ix2,ix3)<minq) then
788 qd(ix^d,2)=minq
789 else if(qdd(ix1-1,ix2,ix3)>maxq) then
790 qd(ix^d,2)=maxq
791 else
792 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
793 end if
794 if(qdd(ix1,ix2,ix3-1)<minq) then
795 qd(ix^d,3)=minq
796 else if(qdd(ix1,ix2,ix3-1)>maxq) then
797 qd(ix^d,3)=maxq
798 else
799 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
800 end if
801 if(qdd(ix1-1,ix2,ix3-1)<minq) then
802 qd(ix^d,4)=minq
803 else if(qdd(ix1-1,ix2,ix3-1)>maxq) then
804 qd(ix^d,4)=maxq
805 else
806 qd(ix^d,4)=qdd(ix1-1,ix2,ix3-1)
807 end if
808 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)&
809 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2,ix3-1,idims)**2*qd(ix^d,4))
810 if(fl%tc_perpendicular) &
811 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))
812 {end do\}
813 else
814 {do ix^db=ixamin^db,ixamax^db\}
815 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
816 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
817 if(qdd(ix^d)<minq) then
818 qd(ix^d,1)=minq
819 else if(qdd(ix^d)>maxq) then
820 qd(ix^d,1)=maxq
821 else
822 qd(ix^d,1)=qdd(ix^d)
823 end if
824 if(qdd(ix1-1,ix2,ix3)<minq) then
825 qd(ix^d,2)=minq
826 else if(qdd(ix1-1,ix2,ix3)>maxq) then
827 qd(ix^d,2)=maxq
828 else
829 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
830 end if
831 if(qdd(ix1,ix2-1,ix3)<minq) then
832 qd(ix^d,3)=minq
833 else if(qdd(ix1,ix2-1,ix3)>maxq) then
834 qd(ix^d,3)=maxq
835 else
836 qd(ix^d,3)=qdd(ix1,ix2-1,ix3)
837 end if
838 if(qdd(ix1-1,ix2-1,ix3)<minq) then
839 qd(ix^d,4)=minq
840 else if(qdd(ix1-1,ix2-1,ix3)>maxq) then
841 qd(ix^d,4)=maxq
842 else
843 qd(ix^d,4)=qdd(ix1-1,ix2-1,ix3)
844 end if
845 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)&
846 +bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2-1,ix3,idims)**2*qd(ix^d,4))
847 if(fl%tc_perpendicular) &
848 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))
849 {end do\}
850 end if
851 }
852 {^iftwod
853 if(idims==1) then
854 {do ix^db=ixamin^db,ixamax^db\}
855 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
856 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
857 if(qdd(ix^d)<minq) then
858 qd(ix^d,1)=minq
859 else if(qdd(ix^d)>maxq) then
860 qd(ix^d,1)=maxq
861 else
862 qd(ix^d,1)=qdd(ix^d)
863 end if
864 if(qdd(ix1,ix2-1)<minq) then
865 qd(ix^d,2)=minq
866 else if(qdd(ix1,ix2-1)>maxq) then
867 qd(ix^d,2)=maxq
868 else
869 qd(ix^d,2)=qdd(ix1,ix2-1)
870 end if
871 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))
872 if(fl%tc_perpendicular) &
873 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
874 {end do\}
875 else
876 {do ix^db=ixamin^db,ixamax^db\}
877 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
878 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
879 if(qdd(ix^d)<minq) then
880 qd(ix^d,1)=minq
881 else if(qdd(ix^d)>maxq) then
882 qd(ix^d,1)=maxq
883 else
884 qd(ix^d,1)=qdd(ix^d)
885 end if
886 if(qdd(ix1-1,ix2)<minq) then
887 qd(ix^d,2)=minq
888 else if(qdd(ix1-1,ix2)>maxq) then
889 qd(ix^d,2)=maxq
890 else
891 qd(ix^d,2)=qdd(ix1-1,ix2)
892 end if
893 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))
894 if(fl%tc_perpendicular) &
895 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
896 {end do\}
897 end if
898 }
899 ! calculate normal of magnetic field
900 ixb^l=ixa^l+kr(idims,^d);
901 bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
902 ! limited transverse component, eq (17)
903 ixbmin^d=ixamin^d;
904 ixbmax^d=ixamax^d+kr(idims,^d);
905 do idir=1,ndim
906 if(idir==idims) cycle
907 qdd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
908 qdd(ixi^s)=slope_limiter(qdd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
909 qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qdd(ixa^s)
910 end do
911 if(fl%tc_saturate) then
912 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
913 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
914 ixb^l=ixa^l+kr(idims,^d);
915 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))
916 {do ix^db=ixamin^db,ixamax^db\}
917 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
918 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
919 end if
920 {end do\}
921 end if
922 end do
923 end if
924 end subroutine set_source_tc_mhd
925
926 function slope_limiter(f,ixI^L,ixO^L,idims,pm,tc_slope_limiter) result(lf)
928 integer, intent(in) :: ixi^l, ixo^l, idims, pm
929 double precision, intent(in) :: f(ixi^s)
930 double precision :: lf(ixi^s)
931 integer, intent(in) :: tc_slope_limiter
932
933 double precision :: signf(ixi^s)
934 integer :: ixb^l
935
936 ixb^l=ixo^l+pm*kr(idims,^d);
937 signf(ixo^s)=sign(1.d0,f(ixo^s))
938 select case(tc_slope_limiter)
939 case(1)
940 ! 'MC' montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
941 lf(ixo^s)=two*signf(ixo^s)* &
942 max(zero,min(dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s),&
943 signf(ixo^s)*quarter*(f(ixb^s)+f(ixo^s))))
944 case(2)
945 ! 'minmod' limiter
946 lf(ixo^s)=signf(ixo^s)*max(0.d0,min(abs(f(ixo^s)),signf(ixo^s)*f(ixb^s)))
947 case(3)
948 ! 'superbee' Roes superbee limiter (eq.3.51i)
949 lf(ixo^s)=signf(ixo^s)* &
950 max(zero,min(two*dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s)),&
951 min(dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s)))
952 case(4)
953 ! 'koren' Barry Koren Right variant
954 lf(ixo^s)=signf(ixo^s)* &
955 max(zero,min(two*dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s),&
956 (two*f(ixb^s)*signf(ixo^s)+dabs(f(ixo^s)))*third))
957 case default
958 call mpistop("Unknown slope limiter for thermal conduction")
959 end select
960 end function slope_limiter
961
962 !> Get the explicit timestep for the TC (hd implementation)
963 function get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
964 ! Check diffusion time limit dt < dx_i**2 / ((gamma-1)*tc_k_para_i/rho)
966
967 integer, intent(in) :: ixi^l, ixo^l
968 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
969 double precision, intent(in) :: w(ixi^s,1:nw)
970 type(tc_fluid), intent(in) :: fl
971 double precision :: dtnew
972
973 double precision :: tmp(ixo^s),tmp2(ixo^s),te(ixi^s),rho(ixi^s),hfs(ixo^s),gradt(ixi^s)
974 double precision :: dtdiff_tcond,maxtmp2
975 integer :: idim
976
977 call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
978 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
979
980 if(fl%tc_saturate) then
981 ! Kannan 2016 MN 458, 410
982 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
983 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
984 tmp2(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
985 hfs=0.d0
986 do idim=1,ndim
987 call gradient(te,ixi^l,ixo^l,idim,gradt)
988 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)**2
989 end do
990 ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT|))
991 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)))
992 else
993 tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/rho(ixo^s)
994 end if
995 dtnew = bigdouble
996
997 if(slab_uniform) then
998 do idim=1,ndim
999 ! approximate thermal conduction flux: tc_k_para_i/rho/dx
1000 tmp2(ixo^s)=tmp(ixo^s)/dxlevel(idim)
1001 maxtmp2=maxval(tmp2(ixo^s))
1002 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho)
1003 dtdiff_tcond=dxlevel(idim)/(tc_gamma_1*maxtmp2+smalldouble)
1004 ! limit the time step
1005 dtnew=min(dtnew,dtdiff_tcond)
1006 end do
1007 else
1008 do idim=1,ndim
1009 ! approximate thermal conduction flux: tc_k_para_i/rho/dx
1010 tmp2(ixo^s)=tmp(ixo^s)/block%ds(ixo^s,idim)
1011 maxtmp2=maxval(tmp2(ixo^s)/block%ds(ixo^s,idim))
1012 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
1013 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
1014 ! limit the time step
1015 dtnew=min(dtnew,dtdiff_tcond)
1016 end do
1017 end if
1018 dtnew=dtnew/dble(ndim)
1019 end function get_tc_dt_hd
1020
1021 subroutine sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
1024
1025 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1026 double precision, intent(in) :: x(ixi^s,1:ndim)
1027 double precision, intent(in) :: w(ixi^s,1:nw)
1028 double precision, intent(inout) :: wres(ixi^s,1:nw)
1029 double precision, intent(in) :: my_dt
1030 logical, intent(in) :: fix_conserve_at_step
1031 type(tc_fluid), intent(in) :: fl
1032
1033 double precision :: te(ixi^s),rho(ixi^s)
1034 double precision :: qvec(ixi^s,1:ndim),qd(ixi^s)
1035 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
1036 double precision, allocatable, dimension(:^D&,:,:) :: fluxall
1037
1038 double precision :: dxinv(ndim)
1039 integer :: idims,ix^l,ixb^l
1040
1041 ix^l=ixo^l^ladd1;
1042
1043 dxinv=1.d0/dxlevel
1044
1045 !calculate Te in whole domain (+ghosts)
1046 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te)
1047 call fl%get_rho(w, x, ixi^l, ixi^l, rho)
1048 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
1049 if(fl%has_equi) then
1050 allocate(qvec_equi(ixi^s,1:ndim))
1051 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
1052 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
1053 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
1054 do idims=1,ndim
1055 qvec(ix^s,idims)=qvec(ix^s,idims) - qvec_equi(ix^s,idims)
1056 end do
1057 deallocate(qvec_equi)
1058 endif
1059
1060 qd=0.d0
1061 if(slab_uniform) then
1062 do idims=1,ndim
1063 qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
1064 ixb^l=ixo^l-kr(idims,^d);
1065 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1066 end do
1067 else
1068 do idims=1,ndim
1069 qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
1070 ixb^l=ixo^l-kr(idims,^d);
1071 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
1072 end do
1073 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
1074 end if
1075
1076 if(fix_conserve_at_step) then
1077 allocate(fluxall(ixi^s,1,1:ndim))
1078 fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
1079 call store_flux(igrid,fluxall,1,ndim,nflux)
1080 deallocate(fluxall)
1081 end if
1082 wres(ixo^s,fl%e_)=qd(ixo^s)
1083 end subroutine sts_set_source_tc_hd
1084
1085 subroutine set_source_tc_hd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
1087 integer, intent(in) :: ixI^L, ixO^L
1088 double precision, intent(in) :: x(ixI^S,1:ndim)
1089 double precision, intent(in) :: w(ixI^S,1:nw)
1090 type(tc_fluid), intent(in) :: fl
1091 double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
1092 double precision, intent(out) :: qvec(ixI^S,1:ndim)
1093 double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
1094 integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L,ixD^L
1095
1096 ix^l=ixo^l^ladd1;
1097 ! ixC is cell-corner index
1098 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1099
1100 ! calculate thermal conduction flux with symmetric scheme
1101 ! T gradient (central difference) at cell corners
1102 do idims=1,ndim
1103 ixbmin^d=ixmin^d;
1104 ixbmax^d=ixmax^d-kr(idims,^d);
1105 call gradientf(te,x,ixi^l,ixb^l,idims,ke)
1106 {^ifthreed
1107 if(idims==1) then
1108 {do ix^db=ixcmin^db,ixcmax^db\}
1109 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2+1,ix3)&
1110 +ke(ix1,ix2,ix3+1)+ke(ix1,ix2+1,ix3+1))
1111 {end do\}
1112 else if(idims==2) then
1113 {do ix^db=ixcmin^db,ixcmax^db\}
1114 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1+1,ix2,ix3)&
1115 +ke(ix1,ix2,ix3+1)+ke(ix1+1,ix2,ix3+1))
1116 {end do\}
1117 else
1118 {do ix^db=ixcmin^db,ixcmax^db\}
1119 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1+1,ix2,ix3)&
1120 +ke(ix1,ix2+1,ix3)+ke(ix1+1,ix2+1,ix3))
1121 {end do\}
1122 end if
1123 }
1124 {^iftwod
1125 if(idims==1) then
1126 {do ix^db=ixcmin^db,ixcmax^db\}
1127 qvec(ix^d,idims)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2+1))
1128 {end do\}
1129 else
1130 {do ix^db=ixcmin^db,ixcmax^db\}
1131 qvec(ix^d,idims)=0.5d0*(ke(ix1,ix2)+ke(ix1+1,ix2))
1132 {end do\}
1133 end if
1134 }
1135 {^ifoned
1136 do ix1=ixcmin1,ixcmax1
1137 qvec(ix1,idims)=ke(ix1)
1138 end do
1139 }
1140 end do
1141 ! conductivity at cell center
1142 if(phys_trac) then
1143 {do ix^db=ixmin^db,ixmax^db\}
1144 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
1145 qd(ix^d)=fl%tc_k_para*sqrt(block%wextra(ix^d,fl%Tcoff_)**5)
1146 else
1147 qd(ix^d)=fl%tc_k_para*sqrt(te(ix^d)**5)
1148 end if
1149 {end do\}
1150 else
1151 qd(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
1152 end if
1153 ! conductivity at cell corner
1154 {^ifthreed
1155 {do ix^db=ixcmin^db,ixcmax^db\}
1156 ke(ix^d)=0.125d0*(qd(ix1,ix2,ix3)+qd(ix1+1,ix2,ix3)&
1157 +qd(ix1,ix2+1,ix3)+qd(ix1+1,ix2+1,ix3)&
1158 +qd(ix1,ix2,ix3+1)+qd(ix1+1,ix2,ix3+1)&
1159 +qd(ix1,ix2+1,ix3+1)+qd(ix1+1,ix2+1,ix3+1))
1160 {end do\}
1161 }
1162 {^iftwod
1163 {do ix^db=ixcmin^db,ixcmax^db\}
1164 ke(ix^d)=0.25d0*(qd(ix1,ix2)+qd(ix1+1,ix2)+qd(ix1,ix2+1)+qd(ix1+1,ix2+1))
1165 {end do\}
1166 }
1167 {^ifoned
1168 do ix1=ixcmin1,ixcmax1
1169 ke(ix1)=0.5d0*(qd(ix1)+qd(ix1+1))
1170 end do
1171 }
1172 ! cell corner conduction flux
1173 do idims=1,ndim
1174 gradt(ixc^s,idims)=ke(ixc^s)*qvec(ixc^s,idims)
1175 end do
1176
1177 if(fl%tc_saturate) then
1178 ! consider saturation with unsigned saturated TC flux = 5 phi rho c**3
1179 ! saturation flux at cell center
1180 qd(ix^s)=5.5d0*rho(ix^s)*dsqrt(te(ix^s)**3)
1181 !cell corner values of qd in ke
1182 {^ifthreed
1183 {do ix^db=ixcmin^db,ixcmax^db\}
1184 ke(ix^d)=0.125d0*(qd(ix1,ix2,ix3)+qd(ix1+1,ix2,ix3)&
1185 +qd(ix1,ix2+1,ix3)+qd(ix1+1,ix2+1,ix3)&
1186 +qd(ix1,ix2,ix3+1)+qd(ix1+1,ix2,ix3+1)&
1187 +qd(ix1,ix2+1,ix3+1)+qd(ix1+1,ix2+1,ix3+1))
1188 {end do\}
1189 }
1190 {^iftwod
1191 {do ix^db=ixcmin^db,ixcmax^db\}
1192 ke(ix^d)=0.25d0*(qd(ix1,ix2)+qd(ix1+1,ix2)+qd(ix1,ix2+1)+qd(ix1+1,ix2+1))
1193 {end do\}
1194 }
1195 {^ifoned
1196 do ix1=ixcmin1,ixcmax1
1197 ke(ix1)=0.5d0*(qd(ix1)+qd(ix1+1))
1198 end do
1199 }
1200 ! magnitude of cell corner conduction flux
1201 qd(ixc^s)=norm2(gradt(ixc^s,:),dim=ndim+1)
1202 {do ix^db=ixcmin^db,ixcmax^db\}
1203 if(qd(ix^d)>ke(ix^d)) then
1204 ke(ix^d)=ke(ix^d)/(qd(ix^d)+smalldouble)
1205 ^d&gradt({ix^d},^d)=ke({ix^d})*gradt({ix^d},^d)\
1206 end if
1207 {end do\}
1208 end if
1209
1210 ! conduction flux at cell face
1211 qvec=0.d0
1212 do idims=1,ndim
1213 ixb^l=ixo^l-kr(idims,^d);
1214 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1215 {^ifthreed
1216 if(idims==1) then
1217 {do ix^db=ixamin^db,ixamax^db\}
1218 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1219 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1,ix2-1,ix3-1,idims))
1220 {end do\}
1221 else if(idims==2) then
1222 {do ix^db=ixamin^db,ixamax^db\}
1223 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1-1,ix2,ix3,idims)&
1224 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1-1,ix2,ix3-1,idims))
1225 {end do\}
1226 else
1227 {do ix^db=ixamin^db,ixamax^db\}
1228 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1229 +gradt(ix1-1,ix2,ix3,idims)+gradt(ix1-1,ix2-1,ix3,idims))
1230 {end do\}
1231 end if
1232 }
1233 {^iftwod
1234 if(idims==1) then
1235 {do ix^db=ixamin^db,ixamax^db\}
1236 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2-1,idims))
1237 {end do\}
1238 else
1239 {do ix^db=ixamin^db,ixamax^db\}
1240 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1-1,ix2,idims))
1241 {end do\}
1242 end if
1243 }
1244 {^ifoned
1245 do ix1=ixamin1,ixamax1
1246 qvec(ix1,idims)=gradt(ix1,idims)
1247 end do
1248 }
1249 end do
1250 end subroutine set_source_tc_hd
1251end module mod_thermal_conduction
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
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.
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.
double precision, dimension(:), allocatable, parameter d
logical b0field
split magnetic field as background B0 field
double precision unit_temperature
Physical scaling factor for temperature.
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
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 explicut timestep for the TC (mhd implementation)
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation)
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...
double precision tc_gamma_1
The adiabatic index.
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
double precision function, dimension(ixi^s) slope_limiter(f, ixil, ixol, idims, pm, tc_slope_limiter)
subroutine set_source_tc_hd(ixil, ixol, w, x, fl, qvec, rho, te)
subroutine set_source_tc_mhd(ixil, ixol, w, x, fl, qvec, rho, te, alpha)