MPI-AMRVAC 3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
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)
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 {do ix^db=ixomin^db,ixomax^db\}
210 if(b0field) then
211 ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
212 else
213 ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))\
214 end if
215 ! Bsquared
216 tmp(ix^d)=(^d&mf({ix^d},^d)**2+)
217 ! B_i**2/B**2
218 if(tmp(ix^d)/=0.d0) then
219 ^d&mf({ix^d},^d)=mf({ix^d},^d)**2/tmp({ix^d})\
220 else
221 ^d&mf({ix^d},^d)=1.d0\
222 end if
223 {end do\}
224 else
225 mf(ixo^s,1:ndim)=block%B0(ixo^s,1:ndim,0)**2
226 endif
227
228 dtnew=bigdouble
229 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
230
231 !tc_k_para_i
232 if(fl%tc_constant) then
233 tmp(ixo^s)=fl%tc_k_para
234 else
235 if(fl%tc_saturate) then
236 ! Kannan 2016 MN 458, 410
237 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
238 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
239 tmp(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
240 do idims=1,ndim
241 call gradient(te,ixi^l,ixo^l,idims,gradt)
242 if(idims==1) then
243 hfs(ixo^s)=gradt(ixo^s)*sqrt(mf(ixo^s,idims))
244 else
245 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)*sqrt(mf(ixo^s,idims))
246 end if
247 end do
248 ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT.b|))
249 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))
250 else
251 ! kappa=kappa_Spizer
252 tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)
253 end if
254 end if
255
256 if(slab_uniform) then
257 do idims=1,ndim
258 ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
259 maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*dxlevel(idims)))
260 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
261 dtdiff_tcond=dxlevel(idims)/(tc_gamma_1*maxtmp2+smalldouble)
262 ! limit the time step
263 dtnew=min(dtnew,dtdiff_tcond)
264 end do
265 else
266 do idims=1,ndim
267 ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
268 maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)/(rho(ixo^s)*block%ds(ixo^s,idims)**2))
269 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
270 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
271 ! limit the time step
272 dtnew=min(dtnew,dtdiff_tcond)
273 end do
274 end if
275 dtnew=dtnew/dble(ndim)
276 end function get_tc_dt_mhd
277
278 !> anisotropic thermal conduction with slope limited symmetric scheme
279 !> Sharma 2007 Journal of Computational Physics 227, 123
280 subroutine sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
283 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
284 double precision, intent(in) :: x(ixi^s,1:ndim)
285 double precision, intent(in) :: w(ixi^s,1:nw)
286 double precision, intent(inout) :: wres(ixi^s,1:nw)
287 double precision, intent(in) :: my_dt
288 logical, intent(in) :: fix_conserve_at_step
289 type(tc_fluid), intent(in) :: fl
290
291 !! qd store the heat conduction energy changing rate
292 double precision :: qd(ixo^s)
293 double precision :: rho(ixi^s),te(ixi^s)
294 double precision :: qvec(ixi^s,1:ndim)
295 double precision :: fluxall(ixi^s,1,1:ndim)
296 double precision :: alpha,dxinv(ndim)
297 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
298 integer :: idims,ixa^l
299
300 ! coefficient of limiting on normal component
301 if(ndim<3) then
302 alpha=0.75d0
303 else
304 alpha=0.85d0
305 end if
306
307 dxinv=1.d0/dxlevel
308
309 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
310 call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
311 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
312 if(fl%has_equi) then
313 allocate(qvec_equi(ixi^s,1:ndim))
314 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
315 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
316 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
317 do idims=1,ndim
318 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
319 qvec(ixa^s,idims)=qvec(ixa^s,idims)-qvec_equi(ixa^s,idims)
320 end do
321 deallocate(qvec_equi)
322 end if
323
324 if(slab_uniform) then
325 do idims=1,ndim
326 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
327 qvec(ixa^s,idims)=dxinv(idims)*qvec(ixa^s,idims)
328 ixa^l=ixo^l-kr(idims,^d);
329 if(idims==1) then
330 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
331 else
332 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
333 end if
334 end do
335 else
336 do idims=1,ndim
337 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
338 qvec(ixa^s,idims)=qvec(ixa^s,idims)*block%surfaceC(ixa^s,idims)
339 ixa^l=ixo^l-kr(idims,^d);
340 if(idims==1) then
341 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
342 else
343 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
344 end if
345 end do
346 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
347 end if
348
349 if(fix_conserve_at_step) then
350 do idims=1,ndim
351 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
352 fluxall(ixa^s,1,idims)=my_dt*qvec(ixa^s,idims)
353 end do
354 call store_flux(igrid,fluxall,1,ndim,nflux)
355 end if
356
357 wres(ixo^s,fl%e_)=qd(ixo^s)
358 end subroutine sts_set_source_tc_mhd
359
360 subroutine set_source_tc_mhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
362 integer, intent(in) :: ixI^L, ixO^L
363 double precision, intent(in) :: x(ixI^S,1:ndim)
364 double precision, intent(in) :: w(ixI^S,1:nw)
365 type(tc_fluid), intent(in) :: fl
366 double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
367 double precision, intent(in) :: alpha
368 double precision, intent(out) :: qvec(ixI^S,1:ndim)
369
370 !! qdd store the heat conduction energy changing rate
371 double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf,gradT
372 double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,Bnorm
373 double precision :: minq,maxq,qd(ixI^S,2**(ndim-1))
374 integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
375
376 ix^l=ixo^l^ladd1;
377
378 ! T gradient at cell faces
379 ! B vector
380 if(allocated(iw_mag)) then
381 if(b0field) then
382 {do ix^db=ixmin^db,ixmax^db\}
383 ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
384 ! |B|
385 bnorm(ix^d)=dsqrt(^d&mf({ix^d},^d)**2+)
386 if(bnorm(ix^d)/=0.d0) then
387 bnorm(ix^d)=1.d0/bnorm(ix^d)
388 else
389 bnorm(ix^d)=bigdouble
390 end if
391 ! b unit vector: magnetic field direction vector
392 ^d&mf({ix^d},^d)=mf({ix^d},^d)*bnorm({ix^d})\
393 {end do\}
394 else
395 {do ix^db=ixmin^db,ixmax^db\}
396 ! |B|
397 bnorm(ix^d)=dsqrt(^d&w({ix^d},iw_mag(^d))**2+)
398 if(bnorm(ix^d)/=0.d0) then
399 bnorm(ix^d)=1.d0/bnorm(ix^d)
400 else
401 bnorm(ix^d)=bigdouble
402 end if
403 ! b unit vector: magnetic field direction vector
404 ^d&mf({ix^d},^d)=w({ix^d},iw_mag(^d))*bnorm({ix^d})\
405 {end do\}
406 end if
407 else
408 mf(ix^s,1:ndim)=block%B0(ix^s,1:ndim,0)
409 endif
410 ! ixC is cell-corner index
411 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
412 ! b unit vector at cell corner
413 {^ifthreed
414 do idims=1,3
415 {do ix^db=ixcmin^db,ixcmax^db\}
416 bc(ix^d,idims)=0.125d0*(mf(ix1,ix2,ix3,idims)+mf(ix1+1,ix2,ix3,idims)&
417 +mf(ix1,ix2+1,ix3,idims)+mf(ix1+1,ix2+1,ix3,idims)&
418 +mf(ix1,ix2,ix3+1,idims)+mf(ix1+1,ix2,ix3+1,idims)&
419 +mf(ix1,ix2+1,ix3+1,idims)+mf(ix1+1,ix2+1,ix3+1,idims))
420 {end do\}
421 end do
422 }
423 {^iftwod
424 do idims=1,2
425 {do ix^db=ixcmin^db,ixcmax^db\}
426 bc(ix^d,idims)=0.25d0*(mf(ix1,ix2,idims)+mf(ix1+1,ix2,idims)&
427 +mf(ix1,ix2+1,idims)+mf(ix1+1,ix2+1,idims))
428 {end do\}
429 end do
430 }
431 ! T gradient at cell faces
432 do idims=1,ndim
433 ixbmin^d=ixmin^d;
434 ixbmax^d=ixmax^d-kr(idims,^d);
435 call gradientf(te,x,ixi^l,ixb^l,idims,gradt(ixi^s,idims))
436 end do
437 if(fl%tc_constant) then
438 if(fl%tc_perpendicular) then
439 ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
440 ke(ixc^s)=fl%tc_k_perp
441 else
442 ka(ixc^s)=fl%tc_k_para
443 end if
444 else
445 ! conductivity at cell center
446 if(phys_trac) then
447 {do ix^db=ixmin^db,ixmax^db\}
448 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
449 qdd(ix^d)=fl%tc_k_para*sqrt(block%wextra(ix^d,fl%Tcoff_)**5)
450 else
451 qdd(ix^d)=fl%tc_k_para*sqrt(te(ix^d)**5)
452 end if
453 {end do\}
454 else
455 qdd(ix^s)=fl%tc_k_para*sqrt(te(ix^s)**5)
456 end if
457 ! cell corner parallel conductivity in ka
458 {^ifthreed
459 {do ix^db=ixcmin^db,ixcmax^db\}
460 ka(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
461 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
462 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
463 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
464 {end do\}
465 }
466 {^iftwod
467 {do ix^db=ixcmin^db,ixcmax^db\}
468 ka(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
469 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
470 {end do\}
471 }
472 ! compensate with perpendicular conductivity
473 if(fl%tc_perpendicular) then
474 qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2*bnorm(ix^s)**2/dsqrt(te(ix^s))
475 {^ifthreed
476 {do ix^db=ixcmin^db,ixcmax^db\}
477 ke(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
478 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
479 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
480 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
481 if(ke(ix^d)<ka(ix^d)) then
482 ka(ix^d)=ka(ix^d)-ke(ix^d)
483 else
484 ke(ix^d)=ka(ix^d)
485 ka(ix^d)=0.d0
486 end if
487 {end do\}
488 }
489 {^iftwod
490 {do ix^db=ixcmin^db,ixcmax^db\}
491 ke(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
492 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
493 if(ke(ix^d)<ka(ix^d)) then
494 ka(ix^d)=ka(ix^d)-ke(ix^d)
495 else
496 ke(ix^d)=ka(ix^d)
497 ka(ix^d)=0.d0
498 end if
499 {end do\}
500 }
501 end if
502 end if
503 if(fl%tc_slope_limiter==0) then
504 ! calculate thermal conduction flux with symmetric scheme
505 do idims=1,ndim
506 !qdd corner values
507 qdd=0.d0
508 {do ix^db=0,1 \}
509 if({ ix^d==0 .and. ^d==idims | .or.}) then
510 ixbmin^d=ixcmin^d+ix^d;
511 ixbmax^d=ixcmax^d+ix^d;
512 qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
513 end if
514 {end do\}
515 ! temperature gradient at cell corner
516 qvec(ixc^s,idims)=qdd(ixc^s)*0.5d0**(ndim-1)
517 end do
518 ! b grad T at cell corner
519 qdd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
520 do idims=1,ndim
521 ! TC flux at cell corner
522 gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qdd(ixc^s)
523 if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
524 end do
525 ! TC flux at cell face
526 qvec=0.d0
527 do idims=1,ndim
528 ixb^l=ixo^l-kr(idims,^d);
529 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
530 {do ix^db=0,1 \}
531 if({ ix^d==0 .and. ^d==idims | .or.}) then
532 ixbmin^d=ixamin^d-ix^d;
533 ixbmax^d=ixamax^d-ix^d;
534 qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
535 end if
536 {end do\}
537 qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
538 if(fl%tc_saturate) then
539 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
540 ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
541 bcf=0.d0
542 {do ix^db=0,1 \}
543 if({ ix^d==0 .and. ^d==idims | .or.}) then
544 ixbmin^d=ixamin^d-ix^d;
545 ixbmax^d=ixamax^d-ix^d;
546 bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
547 end if
548 {end do\}
549 ! averaged b at face centers
550 bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
551 ixb^l=ixa^l+kr(idims,^d);
552 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))
553 {do ix^db=ixamin^db,ixamax^db\}
554 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
555 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
556 end if
557 {end do\}
558 end if
559 end do
560 else
561 ! calculate thermal conduction flux with slope-limited symmetric scheme
562 do idims=1,ndim
563 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
564 {^ifthreed
565 if(idims==1) then
566 {do ix^db=ixamin^db,ixamax^db\}
567 ! averaged b at face centers
568 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
569 +bc(ix1,ix2,ix3-1,^d)+bc(ix1,ix2-1,ix3-1,^d))\
570 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
571 +ka(ix1,ix2,ix3-1)+ka(ix1,ix2-1,ix3-1))
572 ! averaged thermal conductivity at face centers
573 if(fl%tc_perpendicular) &
574 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
575 +ke(ix1,ix2,ix3-1)+ke(ix1,ix2-1,ix3-1))
576 {end do\}
577 else if(idims==2) then
578 {do ix^db=ixamin^db,ixamax^db\}
579 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1-1,ix2,ix3,^d)&
580 +bc(ix1,ix2,ix3-1,^d)+bc(ix1-1,ix2,ix3-1,^d))\
581 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1-1,ix2,ix3)&
582 +ka(ix1,ix2,ix3-1)+ka(ix1-1,ix2,ix3-1))
583 if(fl%tc_perpendicular) &
584 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1-1,ix2,ix3)&
585 +ke(ix1,ix2,ix3-1)+ke(ix1-1,ix2,ix3-1))
586 {end do\}
587 else
588 {do ix^db=ixamin^db,ixamax^db\}
589 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
590 +bc(ix1-1,ix2,ix3,^d)+bc(ix1-1,ix2-1,ix3,^d))\
591 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
592 +ka(ix1-1,ix2,ix3)+ka(ix1-1,ix2-1,ix3))
593 if(fl%tc_perpendicular) &
594 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
595 +ke(ix1-1,ix2,ix3)+ke(ix1-1,ix2-1,ix3))
596 {end do\}
597 end if
598 }
599 {^iftwod
600 if(idims==1) then
601 {do ix^db=ixamin^db,ixamax^db\}
602 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1,ix2-1,^d))\
603 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1,ix2-1))
604 if(fl%tc_perpendicular) &
605 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2-1))
606 {end do\}
607 else
608 {do ix^db=ixamin^db,ixamax^db\}
609 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1-1,ix2,^d))\
610 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1-1,ix2))
611 if(fl%tc_perpendicular) &
612 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1-1,ix2))
613 {end do\}
614 end if
615 }
616 ! eq (19)
617 ! temperature gradient at cell corner
618 {^ifthreed
619 if(idims==1) then
620 {do ix^db=ixcmin^db,ixcmax^db\}
621 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2+1,ix3,idims)&
622 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1,ix2+1,ix3+1,idims))
623 {end do\}
624 else if(idims==2) then
625 {do ix^db=ixcmin^db,ixcmax^db\}
626 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
627 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1+1,ix2,ix3+1,idims))
628 {end do\}
629 else
630 {do ix^db=ixcmin^db,ixcmax^db\}
631 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
632 +gradt(ix1,ix2+1,ix3,idims)+gradt(ix1+1,ix2+1,ix3,idims))
633 {end do\}
634 end if
635 }
636 {^iftwod
637 if(idims==1) then
638 {do ix^db=ixcmin^db,ixcmax^db\}
639 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2+1,idims))
640 {end do\}
641 else
642 {do ix^db=ixcmin^db,ixcmax^db\}
643 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1+1,ix2,idims))
644 {end do\}
645 end if
646 }
647 ! eq (21)
648 {^ifthreed
649 if(idims==1) then
650 {do ix^db=ixamin^db,ixamax^db\}
651 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
652 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
653 if(qdd(ix^d)<minq) then
654 qd(ix^d,1)=minq
655 else if(qdd(ix^d)>maxq) then
656 qd(ix^d,1)=maxq
657 else
658 qd(ix^d,1)=qdd(ix^d)
659 end if
660 if(qdd(ix1,ix2-1,ix3)<minq) then
661 qd(ix^d,2)=minq
662 else if(qdd(ix1,ix2-1,ix3)>maxq) then
663 qd(ix^d,2)=maxq
664 else
665 qd(ix^d,2)=qdd(ix1,ix2-1,ix3)
666 end if
667 if(qdd(ix1,ix2,ix3-1)<minq) then
668 qd(ix^d,3)=minq
669 else if(qdd(ix1,ix2,ix3-1)>maxq) then
670 qd(ix^d,3)=maxq
671 else
672 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
673 end if
674 if(qdd(ix1,ix2-1,ix3-1)<minq) then
675 qd(ix^d,4)=minq
676 else if(qdd(ix1,ix2-1,ix3-1)>maxq) then
677 qd(ix^d,4)=maxq
678 else
679 qd(ix^d,4)=qdd(ix1,ix2-1,ix3-1)
680 end if
681 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)&
682 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1,ix2-1,ix3-1,idims)**2*qd(ix^d,4))
683 if(fl%tc_perpendicular) &
684 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))
685 {end do\}
686 else if(idims==2) then
687 {do ix^db=ixamin^db,ixamax^db\}
688 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
689 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
690 if(qdd(ix^d)<minq) then
691 qd(ix^d,1)=minq
692 else if(qdd(ix^d)>maxq) then
693 qd(ix^d,1)=maxq
694 else
695 qd(ix^d,1)=qdd(ix^d)
696 end if
697 if(qdd(ix1-1,ix2,ix3)<minq) then
698 qd(ix^d,2)=minq
699 else if(qdd(ix1-1,ix2,ix3)>maxq) then
700 qd(ix^d,2)=maxq
701 else
702 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
703 end if
704 if(qdd(ix1,ix2,ix3-1)<minq) then
705 qd(ix^d,3)=minq
706 else if(qdd(ix1,ix2,ix3-1)>maxq) then
707 qd(ix^d,3)=maxq
708 else
709 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
710 end if
711 if(qdd(ix1-1,ix2,ix3-1)<minq) then
712 qd(ix^d,4)=minq
713 else if(qdd(ix1-1,ix2,ix3-1)>maxq) then
714 qd(ix^d,4)=maxq
715 else
716 qd(ix^d,4)=qdd(ix1-1,ix2,ix3-1)
717 end if
718 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)&
719 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2,ix3-1,idims)**2*qd(ix^d,4))
720 if(fl%tc_perpendicular) &
721 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))
722 {end do\}
723 else
724 {do ix^db=ixamin^db,ixamax^db\}
725 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
726 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
727 if(qdd(ix^d)<minq) then
728 qd(ix^d,1)=minq
729 else if(qdd(ix^d)>maxq) then
730 qd(ix^d,1)=maxq
731 else
732 qd(ix^d,1)=qdd(ix^d)
733 end if
734 if(qdd(ix1-1,ix2,ix3)<minq) then
735 qd(ix^d,2)=minq
736 else if(qdd(ix1-1,ix2,ix3)>maxq) then
737 qd(ix^d,2)=maxq
738 else
739 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
740 end if
741 if(qdd(ix1,ix2-1,ix3)<minq) then
742 qd(ix^d,3)=minq
743 else if(qdd(ix1,ix2-1,ix3)>maxq) then
744 qd(ix^d,3)=maxq
745 else
746 qd(ix^d,3)=qdd(ix1,ix2-1,ix3)
747 end if
748 if(qdd(ix1-1,ix2-1,ix3)<minq) then
749 qd(ix^d,4)=minq
750 else if(qdd(ix1-1,ix2-1,ix3)>maxq) then
751 qd(ix^d,4)=maxq
752 else
753 qd(ix^d,4)=qdd(ix1-1,ix2-1,ix3)
754 end if
755 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)&
756 +bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2-1,ix3,idims)**2*qd(ix^d,4))
757 if(fl%tc_perpendicular) &
758 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))
759 {end do\}
760 end if
761 }
762 {^iftwod
763 if(idims==1) then
764 {do ix^db=ixamin^db,ixamax^db\}
765 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
766 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
767 if(qdd(ix^d)<minq) then
768 qd(ix^d,1)=minq
769 else if(qdd(ix^d)>maxq) then
770 qd(ix^d,1)=maxq
771 else
772 qd(ix^d,1)=qdd(ix^d)
773 end if
774 if(qdd(ix1,ix2-1)<minq) then
775 qd(ix^d,2)=minq
776 else if(qdd(ix1,ix2-1)>maxq) then
777 qd(ix^d,2)=maxq
778 else
779 qd(ix^d,2)=qdd(ix1,ix2-1)
780 end if
781 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))
782 if(fl%tc_perpendicular) &
783 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
784 {end do\}
785 else
786 {do ix^db=ixamin^db,ixamax^db\}
787 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
788 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
789 if(qdd(ix^d)<minq) then
790 qd(ix^d,1)=minq
791 else if(qdd(ix^d)>maxq) then
792 qd(ix^d,1)=maxq
793 else
794 qd(ix^d,1)=qdd(ix^d)
795 end if
796 if(qdd(ix1-1,ix2)<minq) then
797 qd(ix^d,2)=minq
798 else if(qdd(ix1-1,ix2)>maxq) then
799 qd(ix^d,2)=maxq
800 else
801 qd(ix^d,2)=qdd(ix1-1,ix2)
802 end if
803 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))
804 if(fl%tc_perpendicular) &
805 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
806 {end do\}
807 end if
808 }
809 ! calculate normal of magnetic field
810 ixb^l=ixa^l+kr(idims,^d);
811 bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
812 ! limited transverse component, eq (17)
813 ixbmin^d=ixamin^d;
814 ixbmax^d=ixamax^d+kr(idims,^d);
815 do idir=1,ndim
816 if(idir==idims) cycle
817 qdd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
818 qdd(ixi^s)=slope_limiter(qdd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
819 qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qdd(ixa^s)
820 end do
821 if(fl%tc_saturate) then
822 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
823 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
824 ixb^l=ixa^l+kr(idims,^d);
825 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))
826 {do ix^db=ixamin^db,ixamax^db\}
827 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
828 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
829 end if
830 {end do\}
831 end if
832 end do
833 end if
834 end subroutine set_source_tc_mhd
835
836 function slope_limiter(f,ixI^L,ixO^L,idims,pm,tc_slope_limiter) result(lf)
838 integer, intent(in) :: ixi^l, ixo^l, idims, pm
839 double precision, intent(in) :: f(ixi^s)
840 double precision :: lf(ixi^s)
841 integer, intent(in) :: tc_slope_limiter
842
843 double precision :: signf(ixi^s)
844 integer :: ixb^l
845
846 ixb^l=ixo^l+pm*kr(idims,^d);
847 signf(ixo^s)=sign(1.d0,f(ixo^s))
848 select case(tc_slope_limiter)
849 case(1)
850 ! 'MC' montonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
851 lf(ixo^s)=two*signf(ixo^s)* &
852 max(zero,min(dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s),&
853 signf(ixo^s)*quarter*(f(ixb^s)+f(ixo^s))))
854 case(2)
855 ! 'minmod' limiter
856 lf(ixo^s)=signf(ixo^s)*max(0.d0,min(abs(f(ixo^s)),signf(ixo^s)*f(ixb^s)))
857 case(3)
858 ! 'superbee' Roes superbee limiter (eq.3.51i)
859 lf(ixo^s)=signf(ixo^s)* &
860 max(zero,min(two*dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s)),&
861 min(dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s)))
862 case(4)
863 ! 'koren' Barry Koren Right variant
864 lf(ixo^s)=signf(ixo^s)* &
865 max(zero,min(two*dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s),&
866 (two*f(ixb^s)*signf(ixo^s)+dabs(f(ixo^s)))*third))
867 case default
868 call mpistop("Unknown slope limiter for thermal conduction")
869 end select
870 end function slope_limiter
871
872 !> Get the explicit timestep for the TC (hd implementation)
873 function get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
874 ! Check diffusion time limit dt < dx_i**2 / ((gamma-1)*tc_k_para_i/rho)
876
877 integer, intent(in) :: ixi^l, ixo^l
878 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
879 double precision, intent(in) :: w(ixi^s,1:nw)
880 type(tc_fluid), intent(in) :: fl
881 double precision :: dtnew
882
883 double precision :: tmp(ixo^s),tmp2(ixo^s),te(ixi^s),rho(ixi^s),hfs(ixo^s),gradt(ixi^s)
884 double precision :: dtdiff_tcond,maxtmp2
885 integer :: idim
886
887 call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
888 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
889
890 if(fl%tc_saturate) then
891 ! Kannan 2016 MN 458, 410
892 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
893 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
894 tmp2(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
895 hfs=0.d0
896 do idim=1,ndim
897 call gradient(te,ixi^l,ixo^l,idim,gradt)
898 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)**2
899 end do
900 ! kappa=kappa_Spizer/(1+4.2*l_mfpe/(T/|gradT|))
901 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)))
902 else
903 tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/rho(ixo^s)
904 end if
905 dtnew = bigdouble
906
907 if(slab_uniform) then
908 do idim=1,ndim
909 ! approximate thermal conduction flux: tc_k_para_i/rho/dx
910 tmp2(ixo^s)=tmp(ixo^s)/dxlevel(idim)
911 maxtmp2=maxval(tmp2(ixo^s))
912 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho)
913 dtdiff_tcond=dxlevel(idim)/(tc_gamma_1*maxtmp2+smalldouble)
914 ! limit the time step
915 dtnew=min(dtnew,dtdiff_tcond)
916 end do
917 else
918 do idim=1,ndim
919 ! approximate thermal conduction flux: tc_k_para_i/rho/dx
920 tmp2(ixo^s)=tmp(ixo^s)/block%ds(ixo^s,idim)
921 maxtmp2=maxval(tmp2(ixo^s)/block%ds(ixo^s,idim))
922 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
923 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
924 ! limit the time step
925 dtnew=min(dtnew,dtdiff_tcond)
926 end do
927 end if
928 dtnew=dtnew/dble(ndim)
929 end function get_tc_dt_hd
930
931 subroutine sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
934
935 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
936 double precision, intent(in) :: x(ixi^s,1:ndim)
937 double precision, intent(in) :: w(ixi^s,1:nw)
938 double precision, intent(inout) :: wres(ixi^s,1:nw)
939 double precision, intent(in) :: my_dt
940 logical, intent(in) :: fix_conserve_at_step
941 type(tc_fluid), intent(in) :: fl
942
943 double precision :: te(ixi^s),rho(ixi^s)
944 double precision :: qvec(ixi^s,1:ndim),qd(ixi^s)
945 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
946 double precision, allocatable, dimension(:^D&,:,:) :: fluxall
947
948 double precision :: dxinv(ndim)
949 integer :: idims,ix^l,ixb^l
950
951 ix^l=ixo^l^ladd1;
952
953 dxinv=1.d0/dxlevel
954
955 !calculate Te in whole domain (+ghosts)
956 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te)
957 call fl%get_rho(w, x, ixi^l, ixi^l, rho)
958 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
959 if(fl%has_equi) then
960 allocate(qvec_equi(ixi^s,1:ndim))
961 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
962 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
963 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
964 do idims=1,ndim
965 qvec(ix^s,idims)=qvec(ix^s,idims) - qvec_equi(ix^s,idims)
966 end do
967 deallocate(qvec_equi)
968 endif
969
970 qd=0.d0
971 if(slab_uniform) then
972 do idims=1,ndim
973 qvec(ix^s,idims)=dxinv(idims)*qvec(ix^s,idims)
974 ixb^l=ixo^l-kr(idims,^d);
975 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
976 end do
977 else
978 do idims=1,ndim
979 qvec(ix^s,idims)=qvec(ix^s,idims)*block%surfaceC(ix^s,idims)
980 ixb^l=ixo^l-kr(idims,^d);
981 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixb^s,idims)
982 end do
983 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
984 end if
985
986 if(fix_conserve_at_step) then
987 allocate(fluxall(ixi^s,1,1:ndim))
988 fluxall(ixi^s,1,1:ndim)=my_dt*qvec(ixi^s,1:ndim)
989 call store_flux(igrid,fluxall,1,ndim,nflux)
990 deallocate(fluxall)
991 end if
992 wres(ixo^s,fl%e_)=qd(ixo^s)
993 end subroutine sts_set_source_tc_hd
994
995 subroutine set_source_tc_hd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
997 integer, intent(in) :: ixI^L, ixO^L
998 double precision, intent(in) :: x(ixI^S,1:ndim)
999 double precision, intent(in) :: w(ixI^S,1:nw)
1000 type(tc_fluid), intent(in) :: fl
1001 double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
1002 double precision, intent(out) :: qvec(ixI^S,1:ndim)
1003 double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
1004 integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L,ixD^L
1005
1006 ix^l=ixo^l^ladd1;
1007 ! ixC is cell-corner index
1008 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1009
1010 ! calculate thermal conduction flux with symmetric scheme
1011 ! T gradient (central difference) at cell corners
1012 do idims=1,ndim
1013 ixbmin^d=ixmin^d;
1014 ixbmax^d=ixmax^d-kr(idims,^d);
1015 call gradientf(te,x,ixi^l,ixb^l,idims,ke)
1016 qd=0.d0
1017 {do ix^db=0,1 \}
1018 if({ix^d==0 .and. ^d==idims |.or. }) then
1019 ixbmin^d=ixcmin^d+ix^d;
1020 ixbmax^d=ixcmax^d+ix^d;
1021 qd(ixc^s)=qd(ixc^s)+ke(ixb^s)
1022 end if
1023 {end do\}
1024 ! temperature gradient at cell corner
1025 qvec(ixc^s,idims)=qd(ixc^s)*0.5d0**(ndim-1)
1026 end do
1027 ! conductivity at cell center
1028 if(phys_trac) then
1029 ! transition region adaptive conduction
1030 where(te(ix^s) < block%wextra(ix^s,fl%Tcoff_))
1031 qd(ix^s)=fl%tc_k_para*dsqrt(block%wextra(ix^s,fl%Tcoff_))**5
1032 else where
1033 qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s))**5
1034 end where
1035 else
1036 qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s))**5
1037 end if
1038 ke=0.d0
1039 {do ix^db=0,1\}
1040 ixbmin^d=ixcmin^d+ix^d;
1041 ixbmax^d=ixcmax^d+ix^d;
1042 ke(ixc^s)=ke(ixc^s)+qd(ixb^s)
1043 {end do\}
1044 ! cell corner conductivity
1045 ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
1046 ! cell corner conduction flux
1047 do idims=1,ndim
1048 gradt(ixc^s,idims)=ke(ixc^s)*qvec(ixc^s,idims)
1049 end do
1050
1051 if(fl%tc_saturate) then
1052 ! consider saturation with unsigned saturated TC flux = 5 phi rho c**3
1053 ! saturation flux at cell center
1054 qd(ix^s)=5.5d0*rho(ix^s)*dsqrt(te(ix^s)**3)
1055 !cell corner values of qd in ke
1056 ke=0.d0
1057 {do ix^db=0,1\}
1058 ixbmin^d=ixcmin^d+ix^d;
1059 ixbmax^d=ixcmax^d+ix^d;
1060 ke(ixc^s)=ke(ixc^s)+qd(ixb^s)
1061 {end do\}
1062 ! cell corner saturation flux
1063 ke(ixc^s)=0.5d0**ndim*ke(ixc^s)
1064 ! magnitude of cell corner conduction flux
1065 qd(ixc^s)=norm2(gradt(ixc^s,:),dim=ndim+1)
1066 {do ix^db=ixcmin^db,ixcmax^db\}
1067 if(qd(ix^d)>ke(ix^d)) then
1068 ke(ix^d)=ke(ix^d)/(qd(ix^d)+smalldouble)
1069 ^d&gradt({ix^d},^d)=ke({ix^d})*gradt({ix^d},^d)\
1070 end if
1071 {end do\}
1072 end if
1073
1074 ! conduction flux at cell face
1075 qvec=0.d0
1076 do idims=1,ndim
1077 ixb^l=ixo^l-kr(idims,^d);
1078 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1079 {do ix^db=0,1 \}
1080 if({ ix^d==0 .and. ^d==idims | .or.}) then
1081 ixbmin^d=ixamin^d-ix^d;
1082 ixbmax^d=ixamax^d-ix^d;
1083 qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
1084 end if
1085 {end do\}
1086 qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
1087 end do
1088 end subroutine set_source_tc_hd
1089end 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
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
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
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)