MPI-AMRVAC 3.2
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!> 30.11.2025 Minor cleanup (for consistency between hd and mhd)
22!>
23!> PURPOSE:
24!> IN MHD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
25!> S=DIV(KAPPA_i,j . GRAD_j T)
26!> where KAPPA_i,j = tc_k_para b_i b_j + tc_k_perp (I - b_i b_j)
27!> b_i b_j = B_i B_j / B**2, I is the unit matrix, and i, j= 1, 2, 3 for 3D
28!> IN HD ADD THE HEAT CONDUCTION SOURCE TO THE ENERGY EQUATION
29!> S=DIV(tc_k_para . GRAD T)
30!> USAGE:
31!> 1. in mod_usr.t -> subroutine usr_init(), add
32!> unit_length=your length unit
33!> unit_numberdensity=your number density unit
34!> unit_velocity=your velocity unit
35!> unit_temperature=your temperature unit
36!> before call (m)hd_activate()
37!> 2. to switch on thermal conduction in the (r)(m)hd_list of amrvac.par add:
38!> (r)(m)hd_thermal_conduction=.true.
39!> 3. in the tc_list of amrvac.par :
40!> tc_perpendicular=.true. ! (default .false.) turn on thermal conduction perpendicular to magnetic field
41!> tc_saturate=.true. ! (default .false. ) turn on thermal conduction saturate effect
42!> tc_slope_limiter='MC' ! choose limiter for slope-limited anisotropic thermal conduction in MHD
43!> note: twofl_list incorporates instances for charges and neutrals
44
46 use mod_global_parameters, only: std_len
47 use mod_geometry
48 use mod_comm_lib, only: mpistop
49 implicit none
50
51 !> The adiabatic index
52 double precision :: tc_gamma_1
53
54 abstract interface
55 subroutine get_var_subr(w,x,ixI^L,ixO^L,res)
57 integer, intent(in) :: ixI^L, ixO^L
58 double precision, intent(in) :: w(ixI^S,nw)
59 double precision, intent(in) :: x(ixI^S,1:ndim)
60 double precision, intent(out):: res(ixI^S)
61 end subroutine get_var_subr
62 end interface
63
65
66 ! BEGIN the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
67 !> Coefficient of thermal conductivity (parallel to magnetic field)
68 double precision :: tc_k_para
69
70 !> Coefficient of thermal conductivity perpendicular to magnetic field
71 double precision :: tc_k_perp
72
73 !> Indices of the variables
74 integer :: e_=-1
75 !> Index of cut off temperature for TRAC
76 integer :: tcoff_
77 !> Name of slope limiter for transverse component of thermal flux
78 integer :: tc_slope_limiter
79
80 ! if has_equi = .true. get_temperature_equi and get_rho_equi have to be set
81 logical :: has_equi=.false.
82
83 !> Logical switch for test constant conductivity
84 logical :: tc_constant=.false.
85
86 !> Calculate thermal conduction perpendicular to magnetic field (.true.) or not (.false.)
87 logical :: tc_perpendicular=.false.
88
89 !> Consider thermal conduction saturation effect (.true.) or not (.false.)
90 logical :: tc_saturate=.false.
91 ! END the following are read from param file or set in tc_read_hd_params or tc_read_mhd_params
92 procedure(get_var_subr), pointer, nopass :: get_rho => null()
93 procedure(get_var_subr), pointer, nopass :: get_rho_equi => null()
94 procedure(get_var_subr), pointer,nopass :: get_temperature_from_eint => null()
95 procedure(get_var_subr), pointer,nopass :: get_temperature_from_conserved => null()
96 procedure(get_var_subr), pointer,nopass :: get_temperature_equi => null()
97 end type tc_fluid
98
99 public :: tc_get_mhd_params
100 public :: tc_get_hd_params
101 public :: get_tc_dt_mhd
102 public :: get_tc_dt_hd
103 public :: sts_set_source_tc_mhd
104 public :: sts_set_source_tc_hd
105
106contains
107
108 subroutine tc_init_params(phys_gamma)
110 double precision, intent(in) :: phys_gamma
111
112 tc_gamma_1=phys_gamma-1d0
113 end subroutine tc_init_params
114
115 !> Init TC coefficients: MHD case
116 subroutine tc_get_mhd_params(fl,read_mhd_params)
118
119 interface
120 subroutine read_mhd_params(fl)
122 import tc_fluid
123 type(tc_fluid), intent(inout) :: fl
124
125 end subroutine read_mhd_params
126 end interface
127 type(tc_fluid), intent(inout) :: fl
128
129 fl%tc_slope_limiter=1
130 fl%tc_k_para=0.d0
131 fl%tc_k_perp=0.d0
132
133 !> Read tc module parameters from par file: MHD case
134 call read_mhd_params(fl)
135
136 if(fl%tc_k_para==0.d0 .and. fl%tc_k_perp==0.d0) then
137 if(si_unit) then
138 ! Spitzer thermal conductivity with SI units
139 fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
140 ! thermal conductivity perpendicular to magnetic field
141 fl%tc_k_perp=4.d-30*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
142 else
143 ! Spitzer thermal conductivity with cgs units
144 fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
145 ! thermal conductivity perpendicular to magnetic field
146 fl%tc_k_perp=4.d-10*unit_numberdensity**2/unit_magneticfield**2/unit_temperature**3*fl%tc_k_para
147 end if
148 if(mype .eq. 0) print*, "Spitzer MHD: par: ",fl%tc_k_para, &
149 " ,perp: ",fl%tc_k_perp
150 else
151 fl%tc_constant=.true.
152 if(mype .eq. 0) print*, "Constant thermal conduction coefficients with values: ",fl%tc_k_para,fl%tc_k_perp
153 end if
154 end subroutine tc_get_mhd_params
155
156 !> Init TC coefficients: HD case
157 subroutine tc_get_hd_params(fl,read_hd_params)
159
160 interface
161 subroutine read_hd_params(fl)
163 import tc_fluid
164 type(tc_fluid), intent(inout) :: fl
165
166 end subroutine read_hd_params
167 end interface
168 type(tc_fluid), intent(inout) :: fl
169
170 fl%tc_k_para=0.d0
171
172 !> Read tc parameters from par file: HD case
173 call read_hd_params(fl)
174
175 if(fl%tc_k_para==0.d0) then
176 if(si_unit) then
177 ! Spitzer thermal conductivity with SI units
178 fl%tc_k_para=8.d-12*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
179 else
180 ! Spitzer thermal conductivity with cgs units
181 fl%tc_k_para=8.d-7*unit_temperature**3.5d0/unit_length/unit_density/unit_velocity**3
182 end if
183 if(mype .eq. 0) print*, "Spitzer HD par: ",fl%tc_k_para
184 else
185 fl%tc_constant=.true.
186 if(mype .eq. 0) print*, "Constant thermal conduction coefficient at value: ",fl%tc_k_para
187 end if
188
189 end subroutine tc_get_hd_params
190
191 !> Get the explicit timestep for the TC (mhd implementation)
192 !> Note: for multi-D MHD (1D MHD will use HD fall-back)
193 function get_tc_dt_mhd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
194 !Check diffusion time limit dt < dx_i**2/((gamma-1)*tc_k_para_i/rho)
195 !where tc_k_para_i=tc_k_para*B_i**2/B**2
196 !and T=p/rho
198
199 type(tc_fluid), intent(in) :: fl
200 integer, intent(in) :: ixi^l, ixo^l
201 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
202 double precision, intent(in) :: w(ixi^s,1:nw)
203 double precision :: dtnew
204
205 double precision :: mf(ixo^s,1:ndim),te(ixi^s),rho(ixi^s),gradt(ixi^s)
206 double precision :: tmp(ixo^s),hfs(ixo^s),blocal(1:ndim)
207 double precision :: dtdiff_tcond,maxtmp2
208 integer :: idims,ix^d
209
210
211 ! B
212 if(allocated(iw_mag)) then
213 if(b0field) then
214 {do ix^db=ixomin^db,ixomax^db\}
215 ^d&blocal(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
216 {^iftwod
217 if(blocal(1)/=0.d0) then
218 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2)
219 else
220 mf(ix^d,1)=0.d0
221 end if
222 if(blocal(2)/=0.d0) then
223 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2)
224 else
225 mf(ix^d,2)=0.d0
226 end if
227 }
228 {^ifthreed
229 if(blocal(1)/=0.d0) then
230 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2+(blocal(3)/blocal(1))**2)
231 else
232 mf(ix^d,1)=0.d0
233 end if
234 if(blocal(2)/=0.d0) then
235 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2+(blocal(3)/blocal(2))**2)
236 else
237 mf(ix^d,2)=0.d0
238 end if
239 if(blocal(3)/=0.d0) then
240 mf(ix^d,3)=sign(1.d0,blocal(3))/dsqrt(1.d0+(blocal(1)/blocal(3))**2+(blocal(2)/blocal(3))**2)
241 else
242 mf(ix^d,3)=0.d0
243 end if
244 }
245 {end do\}
246 else
247 {do ix^db=ixomin^db,ixomax^db\}
248 {^iftwod
249 if(w(ix^d,iw_mag(1))/=0.d0) then
250 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)
251 else
252 mf(ix^d,1)=0.d0
253 end if
254 if(w(ix^d,iw_mag(2))/=0.d0) then
255 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)
256 else
257 mf(ix^d,2)=0.d0
258 end if
259 }
260 {^ifthreed
261 if(w(ix^d,iw_mag(1))/=0.d0) then
262 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+&
263 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
264 else
265 mf(ix^d,1)=0.d0
266 end if
267 if(w(ix^d,iw_mag(2))/=0.d0) then
268 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+&
269 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
270 else
271 mf(ix^d,2)=0.d0
272 end if
273 if(w(ix^d,iw_mag(3))/=0.d0) then
274 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+&
275 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
276 else
277 mf(ix^d,3)=0.d0
278 end if
279 }
280 {end do\}
281 end if
282 else
283 ! this if for ffhd or other physics modules without B components
284 mf(ixo^s,1:ndim)=block%B0(ixo^s,1:ndim,0)
285 end if
286
287 !temperature
288 call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
289 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
290
291 !tc_k_para_i
292 if(fl%tc_constant) then
293 tmp(ixo^s)=fl%tc_k_para
294 else
295 if(fl%tc_saturate) then
296 ! Kannan 2016 MN 458, 410
297 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
298 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
299 if(si_unit) call mpistop("needs adjusting in get_tc_dt_mhd")
300 tmp(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
301 do idims=1,ndim
302 call gradient(te,ixi^l,ixo^l,idims,gradt)
303 if(idims==1) then
304 hfs(ixo^s)=gradt(ixo^s)*mf(ixo^s,idims)
305 else
306 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)*mf(ixo^s,idims)
307 end if
308 end do
309 ! kappa=kappa_Spitzer/(1+4.2*l_mfpe/(T/|gradT.b|))
310 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))
311 else
312 ! kappa=kappa_Spitzer
313 tmp(ixo^s)=fl%tc_k_para*dsqrt(te(ixo^s)**5)
314 end if
315 end if
316
317 dtnew=bigdouble
318 do idims=1,ndim
319 ! approximate thermal conduction flux: tc_k_para_i/rho/dx*B_i**2/B**2
320 maxtmp2=maxval(tmp(ixo^s)*mf(ixo^s,idims)**2/(rho(ixo^s)*block%ds(ixo^s,idims)**2))
321 ! dt< dx_idim**2/((gamma-1)*tc_k_para_i/rho*B_i**2/B**2)
322 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
323 ! limit the time step
324 dtnew=min(dtnew,dtdiff_tcond)
325 end do
326 dtnew=dtnew/dble(ndim)
327 end function get_tc_dt_mhd
328
329 !> anisotropic thermal conduction with slope limited symmetric scheme
330 !> Sharma 2007 Journal of Computational Physics 227, 123
331 subroutine sts_set_source_tc_mhd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
334 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
335 double precision, intent(in) :: x(ixi^s,1:ndim)
336 double precision, intent(in) :: w(ixi^s,1:nw)
337 double precision, intent(inout) :: wres(ixi^s,1:nw)
338 double precision, intent(in) :: my_dt
339 logical, intent(in) :: fix_conserve_at_step
340 type(tc_fluid), intent(in) :: fl
341
342 !! qd store the heat conduction energy changing rate
343 double precision :: qd(ixo^s)
344 double precision :: rho(ixi^s),te(ixi^s)
345 double precision :: qvec(ixi^s,1:ndim)
346 double precision :: fluxall(ixi^s,1,1:ndim)
347 double precision :: alpha,dxinv(ndim)
348 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
349 integer :: idims,ixa^l
350
351 ! coefficient of limiting on normal component
352 if(ndim<3) then
353 alpha=0.75d0
354 else
355 alpha=0.85d0
356 end if
357
358 dxinv=1.d0/dxlevel
359
360 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
361 call fl%get_rho(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
362 if(slab_uniform) then
363 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
364 else
365 call set_source_tc_mhd_geo(ixi^l,ixo^l,w,x,fl,qvec,rho,te,alpha)
366 end if
367 if(fl%has_equi) then
368 allocate(qvec_equi(ixi^s,1:ndim))
369 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
370 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
371 if(slab_uniform) then
372 call set_source_tc_mhd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
373 else
374 call set_source_tc_mhd_geo(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te,alpha)
375 end if
376 do idims=1,ndim
377 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
378 qvec(ixa^s,idims)=qvec(ixa^s,idims)-qvec_equi(ixa^s,idims)
379 end do
380 deallocate(qvec_equi)
381 end if
382
383 if(slab_uniform) then
384 do idims=1,ndim
385 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
386 qvec(ixa^s,idims)=dxinv(idims)*qvec(ixa^s,idims)
387 ixa^l=ixo^l-kr(idims,^d);
388 if(idims==1) then
389 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
390 else
391 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
392 end if
393 end do
394 else
395 do idims=1,ndim
396 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
397 qvec(ixa^s,idims)=qvec(ixa^s,idims)*block%surfaceC(ixa^s,idims)
398 ixa^l=ixo^l-kr(idims,^d);
399 if(idims==1) then
400 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
401 else
402 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
403 end if
404 end do
405 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
406 end if
407
408 if(fix_conserve_at_step) then
409 do idims=1,ndim
410 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
411 fluxall(ixa^s,1,idims)=my_dt*qvec(ixa^s,idims)
412 end do
413 call store_flux(igrid,fluxall,1,ndim,nflux)
414 end if
415
416 wres(ixo^s,fl%e_)=qd(ixo^s)
417 end subroutine sts_set_source_tc_mhd
418
419 subroutine set_source_tc_mhd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
421 integer, intent(in) :: ixI^L, ixO^L
422 double precision, intent(in) :: x(ixI^S,1:ndim)
423 double precision, intent(in) :: w(ixI^S,1:nw)
424 type(tc_fluid), intent(in) :: fl
425 double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
426 double precision, intent(in) :: alpha
427 double precision, intent(out) :: qvec(ixI^S,1:ndim)
428
429 !! qdd store the heat conduction energy changing rate
430 double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf,gradT
431 double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,Bnorm
432 double precision :: minq,maxq,qd(ixI^S,2**(ndim-1)), blocal(ndim)
433 integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
434
435 ix^l=ixo^l^ladd1;
436
437 ! T gradient at cell faces
438 ! b unit vector mf: magnetic field direction vector
439 if(allocated(iw_mag)) then
440 if(b0field) then
441 {do ix^db=ixmin^db,ixmax^db\}
442 ^d&blocal(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
443 {^iftwod
444 if(blocal(1)/=0.d0) then
445 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2)
446 else
447 mf(ix^d,1)=0.d0
448 end if
449 if(blocal(2)/=0.d0) then
450 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2)
451 else
452 mf(ix^d,2)=0.d0
453 end if
454 }
455 {^ifthreed
456 if(blocal(1)/=0.d0) then
457 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2+(blocal(3)/blocal(1))**2)
458 else
459 mf(ix^d,1)=0.d0
460 end if
461 if(blocal(2)/=0.d0) then
462 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2+(blocal(3)/blocal(2))**2)
463 else
464 mf(ix^d,2)=0.d0
465 end if
466 if(blocal(3)/=0.d0) then
467 mf(ix^d,3)=sign(1.d0,blocal(3))/dsqrt(1.d0+(blocal(1)/blocal(3))**2+(blocal(2)/blocal(3))**2)
468 else
469 mf(ix^d,3)=0.d0
470 end if
471 }
472 {end do\}
473 else
474 {do ix^db=ixmin^db,ixmax^db\}
475 {^iftwod
476 if(w(ix^d,iw_mag(1))/=0.d0) then
477 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)
478 else
479 mf(ix^d,1)=0.d0
480 end if
481 if(w(ix^d,iw_mag(2))/=0.d0) then
482 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)
483 else
484 mf(ix^d,2)=0.d0
485 end if
486 }
487 {^ifthreed
488 if(w(ix^d,iw_mag(1))/=0.d0) then
489 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+&
490 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
491 else
492 mf(ix^d,1)=0.d0
493 end if
494 if(w(ix^d,iw_mag(2))/=0.d0) then
495 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+&
496 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
497 else
498 mf(ix^d,2)=0.d0
499 end if
500 if(w(ix^d,iw_mag(3))/=0.d0) then
501 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+&
502 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
503 else
504 mf(ix^d,3)=0.d0
505 end if
506 }
507 {end do\}
508 end if
509 else
510 mf(ix^s,1:ndim)=block%B0(ix^s,1:ndim,0)
511 endif
512 ! ixC is cell-corner index
513 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
514 ! b unit vector at cell corner
515 {^ifthreed
516 do idims=1,3
517 {do ix^db=ixcmin^db,ixcmax^db\}
518 bc(ix^d,idims)=0.125d0*(mf(ix1,ix2,ix3,idims)+mf(ix1+1,ix2,ix3,idims)&
519 +mf(ix1,ix2+1,ix3,idims)+mf(ix1+1,ix2+1,ix3,idims)&
520 +mf(ix1,ix2,ix3+1,idims)+mf(ix1+1,ix2,ix3+1,idims)&
521 +mf(ix1,ix2+1,ix3+1,idims)+mf(ix1+1,ix2+1,ix3+1,idims))
522 {end do\}
523 end do
524 }
525 {^iftwod
526 do idims=1,2
527 {do ix^db=ixcmin^db,ixcmax^db\}
528 bc(ix^d,idims)=0.25d0*(mf(ix1,ix2,idims)+mf(ix1+1,ix2,idims)&
529 +mf(ix1,ix2+1,idims)+mf(ix1+1,ix2+1,idims))
530 {end do\}
531 end do
532 }
533 ! T gradient at cell faces
534 do idims=1,ndim
535 ixbmin^d=ixmin^d;
536 ixbmax^d=ixmax^d-kr(idims,^d);
537 call gradientf(te,x,ixi^l,ixb^l,idims,gradt(ixi^s,idims))
538 end do
539 if(fl%tc_constant) then
540 if(fl%tc_perpendicular) then
541 ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
542 ke(ixc^s)=fl%tc_k_perp
543 else
544 ka(ixc^s)=fl%tc_k_para
545 end if
546 else
547 ! conductivity at cell center
548 if(phys_trac) then
549 {do ix^db=ixmin^db,ixmax^db\}
550 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
551 qdd(ix^d)=fl%tc_k_para*dsqrt(block%wextra(ix^d,fl%Tcoff_)**5)
552 else
553 qdd(ix^d)=fl%tc_k_para*dsqrt(te(ix^d)**5)
554 end if
555 {end do\}
556 else
557 qdd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s)**5)
558 end if
559 ! cell corner parallel conductivity in ka
560 {^ifthreed
561 {do ix^db=ixcmin^db,ixcmax^db\}
562 ka(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
563 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
564 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
565 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
566 {end do\}
567 }
568 {^iftwod
569 {do ix^db=ixcmin^db,ixcmax^db\}
570 ka(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
571 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
572 {end do\}
573 }
574 ! compensate with perpendicular conductivity
575 if(fl%tc_perpendicular) then
576 if(b0field) then
577 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)
578 else
579 qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2/((^d&w(ix^s,iw_mag(^d))**2+)*dsqrt(te(ix^s))+smalldouble)
580 end if
581 {^ifthreed
582 {do ix^db=ixcmin^db,ixcmax^db\}
583 ke(ix^d)=0.125d0*(qdd(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)&
584 +qdd(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)&
585 +qdd(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)&
586 +qdd(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1))
587 if(ke(ix^d)<ka(ix^d)) then
588 ka(ix^d)=ka(ix^d)-ke(ix^d)
589 else
590 ke(ix^d)=ka(ix^d)
591 ka(ix^d)=0.d0
592 end if
593 {end do\}
594 }
595 {^iftwod
596 {do ix^db=ixcmin^db,ixcmax^db\}
597 ke(ix^d)=0.25d0*(qdd(ix1,ix2)+qdd(ix1+1,ix2)&
598 +qdd(ix1,ix2+1)+qdd(ix1+1,ix2+1))
599 if(ke(ix^d)<ka(ix^d)) then
600 ka(ix^d)=ka(ix^d)-ke(ix^d)
601 else
602 ke(ix^d)=ka(ix^d)
603 ka(ix^d)=0.d0
604 end if
605 {end do\}
606 }
607 end if
608 end if
609 if(fl%tc_slope_limiter==0) then
610 ! calculate thermal conduction flux with symmetric scheme
611 do idims=1,ndim
612 !qdd corner values
613 qdd=0.d0
614 {do ix^db=0,1 \}
615 if({ ix^d==0 .and. ^d==idims | .or.}) then
616 ixbmin^d=ixcmin^d+ix^d;
617 ixbmax^d=ixcmax^d+ix^d;
618 qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
619 end if
620 {end do\}
621 ! temperature gradient at cell corner
622 qvec(ixc^s,idims)=qdd(ixc^s)*0.5d0**(ndim-1)
623 end do
624 ! b grad T at cell corner
625 qdd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
626 do idims=1,ndim
627 ! TC flux at cell corner
628 gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qdd(ixc^s)
629 if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
630 end do
631 ! TC flux at cell face
632 qvec=0.d0
633 do idims=1,ndim
634 ixb^l=ixo^l-kr(idims,^d);
635 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
636 {do ix^db=0,1 \}
637 if({ ix^d==0 .and. ^d==idims | .or.}) then
638 ixbmin^d=ixamin^d-ix^d;
639 ixbmax^d=ixamax^d-ix^d;
640 qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
641 end if
642 {end do\}
643 qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
644 if(fl%tc_saturate) then
645 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
646 ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
647 bcf=0.d0
648 {do ix^db=0,1 \}
649 if({ ix^d==0 .and. ^d==idims | .or.}) then
650 ixbmin^d=ixamin^d-ix^d;
651 ixbmax^d=ixamax^d-ix^d;
652 bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
653 end if
654 {end do\}
655 ! averaged b at face centers
656 bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
657 ixb^l=ixa^l+kr(idims,^d);
658 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))
659 {do ix^db=ixamin^db,ixamax^db\}
660 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
661 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
662 end if
663 {end do\}
664 end if
665 end do
666 else
667 ! calculate thermal conduction flux with slope-limited symmetric scheme
668 do idims=1,ndim
669 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
670 {^ifthreed
671 if(idims==1) then
672 {do ix^db=ixamin^db,ixamax^db\}
673 ! averaged b at face centers
674 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
675 +bc(ix1,ix2,ix3-1,^d)+bc(ix1,ix2-1,ix3-1,^d))\
676 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
677 +ka(ix1,ix2,ix3-1)+ka(ix1,ix2-1,ix3-1))
678 ! averaged thermal conductivity at face centers
679 if(fl%tc_perpendicular) &
680 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
681 +ke(ix1,ix2,ix3-1)+ke(ix1,ix2-1,ix3-1))
682 {end do\}
683 else if(idims==2) then
684 {do ix^db=ixamin^db,ixamax^db\}
685 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1-1,ix2,ix3,^d)&
686 +bc(ix1,ix2,ix3-1,^d)+bc(ix1-1,ix2,ix3-1,^d))\
687 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1-1,ix2,ix3)&
688 +ka(ix1,ix2,ix3-1)+ka(ix1-1,ix2,ix3-1))
689 if(fl%tc_perpendicular) &
690 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1-1,ix2,ix3)&
691 +ke(ix1,ix2,ix3-1)+ke(ix1-1,ix2,ix3-1))
692 {end do\}
693 else
694 {do ix^db=ixamin^db,ixamax^db\}
695 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
696 +bc(ix1-1,ix2,ix3,^d)+bc(ix1-1,ix2-1,ix3,^d))\
697 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
698 +ka(ix1-1,ix2,ix3)+ka(ix1-1,ix2-1,ix3))
699 if(fl%tc_perpendicular) &
700 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
701 +ke(ix1-1,ix2,ix3)+ke(ix1-1,ix2-1,ix3))
702 {end do\}
703 end if
704 }
705 {^iftwod
706 if(idims==1) then
707 {do ix^db=ixamin^db,ixamax^db\}
708 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1,ix2-1,^d))\
709 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1,ix2-1))
710 if(fl%tc_perpendicular) &
711 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2-1))
712 {end do\}
713 else
714 {do ix^db=ixamin^db,ixamax^db\}
715 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1-1,ix2,^d))\
716 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1-1,ix2))
717 if(fl%tc_perpendicular) &
718 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1-1,ix2))
719 {end do\}
720 end if
721 }
722 ! eq (19)
723 ! temperature gradient at cell corner
724 {^ifthreed
725 if(idims==1) then
726 {do ix^db=ixcmin^db,ixcmax^db\}
727 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2+1,ix3,idims)&
728 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1,ix2+1,ix3+1,idims))
729 {end do\}
730 else if(idims==2) then
731 {do ix^db=ixcmin^db,ixcmax^db\}
732 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
733 +gradt(ix1,ix2,ix3+1,idims)+gradt(ix1+1,ix2,ix3+1,idims))
734 {end do\}
735 else
736 {do ix^db=ixcmin^db,ixcmax^db\}
737 qdd(ix^d)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1+1,ix2,ix3,idims)&
738 +gradt(ix1,ix2+1,ix3,idims)+gradt(ix1+1,ix2+1,ix3,idims))
739 {end do\}
740 end if
741 }
742 {^iftwod
743 if(idims==1) then
744 {do ix^db=ixcmin^db,ixcmax^db\}
745 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2+1,idims))
746 {end do\}
747 else
748 {do ix^db=ixcmin^db,ixcmax^db\}
749 qdd(ix^d)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1+1,ix2,idims))
750 {end do\}
751 end if
752 }
753 ! eq (21)
754 {^ifthreed
755 if(idims==1) then
756 {do ix^db=ixamin^db,ixamax^db\}
757 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
758 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
759 if(qdd(ix^d)<minq) then
760 qd(ix^d,1)=minq
761 else if(qdd(ix^d)>maxq) then
762 qd(ix^d,1)=maxq
763 else
764 qd(ix^d,1)=qdd(ix^d)
765 end if
766 if(qdd(ix1,ix2-1,ix3)<minq) then
767 qd(ix^d,2)=minq
768 else if(qdd(ix1,ix2-1,ix3)>maxq) then
769 qd(ix^d,2)=maxq
770 else
771 qd(ix^d,2)=qdd(ix1,ix2-1,ix3)
772 end if
773 if(qdd(ix1,ix2,ix3-1)<minq) then
774 qd(ix^d,3)=minq
775 else if(qdd(ix1,ix2,ix3-1)>maxq) then
776 qd(ix^d,3)=maxq
777 else
778 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
779 end if
780 if(qdd(ix1,ix2-1,ix3-1)<minq) then
781 qd(ix^d,4)=minq
782 else if(qdd(ix1,ix2-1,ix3-1)>maxq) then
783 qd(ix^d,4)=maxq
784 else
785 qd(ix^d,4)=qdd(ix1,ix2-1,ix3-1)
786 end if
787 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)&
788 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1,ix2-1,ix3-1,idims)**2*qd(ix^d,4))
789 if(fl%tc_perpendicular) &
790 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))
791 {end do\}
792 else if(idims==2) then
793 {do ix^db=ixamin^db,ixamax^db\}
794 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
795 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
796 if(qdd(ix^d)<minq) then
797 qd(ix^d,1)=minq
798 else if(qdd(ix^d)>maxq) then
799 qd(ix^d,1)=maxq
800 else
801 qd(ix^d,1)=qdd(ix^d)
802 end if
803 if(qdd(ix1-1,ix2,ix3)<minq) then
804 qd(ix^d,2)=minq
805 else if(qdd(ix1-1,ix2,ix3)>maxq) then
806 qd(ix^d,2)=maxq
807 else
808 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
809 end if
810 if(qdd(ix1,ix2,ix3-1)<minq) then
811 qd(ix^d,3)=minq
812 else if(qdd(ix1,ix2,ix3-1)>maxq) then
813 qd(ix^d,3)=maxq
814 else
815 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
816 end if
817 if(qdd(ix1-1,ix2,ix3-1)<minq) then
818 qd(ix^d,4)=minq
819 else if(qdd(ix1-1,ix2,ix3-1)>maxq) then
820 qd(ix^d,4)=maxq
821 else
822 qd(ix^d,4)=qdd(ix1-1,ix2,ix3-1)
823 end if
824 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)&
825 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2,ix3-1,idims)**2*qd(ix^d,4))
826 if(fl%tc_perpendicular) &
827 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))
828 {end do\}
829 else
830 {do ix^db=ixamin^db,ixamax^db\}
831 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
832 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
833 if(qdd(ix^d)<minq) then
834 qd(ix^d,1)=minq
835 else if(qdd(ix^d)>maxq) then
836 qd(ix^d,1)=maxq
837 else
838 qd(ix^d,1)=qdd(ix^d)
839 end if
840 if(qdd(ix1-1,ix2,ix3)<minq) then
841 qd(ix^d,2)=minq
842 else if(qdd(ix1-1,ix2,ix3)>maxq) then
843 qd(ix^d,2)=maxq
844 else
845 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
846 end if
847 if(qdd(ix1,ix2-1,ix3)<minq) then
848 qd(ix^d,3)=minq
849 else if(qdd(ix1,ix2-1,ix3)>maxq) then
850 qd(ix^d,3)=maxq
851 else
852 qd(ix^d,3)=qdd(ix1,ix2-1,ix3)
853 end if
854 if(qdd(ix1-1,ix2-1,ix3)<minq) then
855 qd(ix^d,4)=minq
856 else if(qdd(ix1-1,ix2-1,ix3)>maxq) then
857 qd(ix^d,4)=maxq
858 else
859 qd(ix^d,4)=qdd(ix1-1,ix2-1,ix3)
860 end if
861 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)&
862 +bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2-1,ix3,idims)**2*qd(ix^d,4))
863 if(fl%tc_perpendicular) &
864 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))
865 {end do\}
866 end if
867 }
868 {^iftwod
869 if(idims==1) then
870 {do ix^db=ixamin^db,ixamax^db\}
871 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
872 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
873 if(qdd(ix^d)<minq) then
874 qd(ix^d,1)=minq
875 else if(qdd(ix^d)>maxq) then
876 qd(ix^d,1)=maxq
877 else
878 qd(ix^d,1)=qdd(ix^d)
879 end if
880 if(qdd(ix1,ix2-1)<minq) then
881 qd(ix^d,2)=minq
882 else if(qdd(ix1,ix2-1)>maxq) then
883 qd(ix^d,2)=maxq
884 else
885 qd(ix^d,2)=qdd(ix1,ix2-1)
886 end if
887 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))
888 if(fl%tc_perpendicular) &
889 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
890 {end do\}
891 else
892 {do ix^db=ixamin^db,ixamax^db\}
893 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
894 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
895 if(qdd(ix^d)<minq) then
896 qd(ix^d,1)=minq
897 else if(qdd(ix^d)>maxq) then
898 qd(ix^d,1)=maxq
899 else
900 qd(ix^d,1)=qdd(ix^d)
901 end if
902 if(qdd(ix1-1,ix2)<minq) then
903 qd(ix^d,2)=minq
904 else if(qdd(ix1-1,ix2)>maxq) then
905 qd(ix^d,2)=maxq
906 else
907 qd(ix^d,2)=qdd(ix1-1,ix2)
908 end if
909 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))
910 if(fl%tc_perpendicular) &
911 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
912 {end do\}
913 end if
914 }
915 ! calculate normal of magnetic field
916 ixb^l=ixa^l+kr(idims,^d);
917 bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
918 ! limited transverse component, eq (17)
919 ixbmin^d=ixamin^d;
920 ixbmax^d=ixamax^d+kr(idims,^d);
921 do idir=1,ndim
922 if(idir==idims) cycle
923 qdd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
924 qdd(ixi^s)=slope_limiter(qdd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
925 qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qdd(ixa^s)
926 end do
927 if(fl%tc_saturate) then
928 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
929 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
930 ixb^l=ixa^l+kr(idims,^d);
931 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))
932 {do ix^db=ixamin^db,ixamax^db\}
933 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
934 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
935 end if
936 {end do\}
937 end if
938 end do
939 end if
940 end subroutine set_source_tc_mhd
941
942 subroutine set_source_tc_mhd_geo(ixI^L,ixO^L,w,x,fl,qvec,rho,Te,alpha)
944 integer, intent(in) :: ixI^L, ixO^L
945 double precision, intent(in) :: x(ixI^S,1:ndim)
946 double precision, intent(in) :: w(ixI^S,1:nw)
947 type(tc_fluid), intent(in) :: fl
948 double precision, intent(in) :: rho(ixI^S),Te(ixI^S)
949 double precision, intent(in) :: alpha
950 double precision, intent(out) :: qvec(ixI^S,1:ndim)
951
952 !! qdd store the heat conduction energy changing rate
953 double precision, dimension(ixI^S,1:ndim) :: mf,Bc,Bcf,gradT
954 double precision, dimension(ixI^S) :: ka,kaf,ke,kef,qdd,Bnorm
955 double precision :: minq,maxq,qd(ixI^S,2**(ndim-1)), blocal(ndim)
956 integer :: idims,idir,ix^D,ix^L,ixC^L,ixA^L,ixB^L
957
958 ix^l=ixo^l^ladd1;
959
960 ! T gradient at cell faces
961 ! b unit vector mf: magnetic field direction vector
962 if(allocated(iw_mag)) then
963 if(b0field) then
964 {do ix^db=ixmin^db,ixmax^db\}
965 ^d&blocal(^d)=w({ix^d},iw_mag(^d))+block%B0({ix^d},^d,0)\
966 {^iftwod
967 if(blocal(1)/=0.d0) then
968 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2)
969 else
970 mf(ix^d,1)=0.d0
971 end if
972 if(blocal(2)/=0.d0) then
973 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2)
974 else
975 mf(ix^d,2)=0.d0
976 end if
977 }
978 {^ifthreed
979 if(blocal(1)/=0.d0) then
980 mf(ix^d,1)=sign(1.d0,blocal(1))/dsqrt(1.d0+(blocal(2)/blocal(1))**2+(blocal(3)/blocal(1))**2)
981 else
982 mf(ix^d,1)=0.d0
983 end if
984 if(blocal(2)/=0.d0) then
985 mf(ix^d,2)=sign(1.d0,blocal(2))/dsqrt(1.d0+(blocal(1)/blocal(2))**2+(blocal(3)/blocal(2))**2)
986 else
987 mf(ix^d,2)=0.d0
988 end if
989 if(blocal(3)/=0.d0) then
990 mf(ix^d,3)=sign(1.d0,blocal(3))/dsqrt(1.d0+(blocal(1)/blocal(3))**2+(blocal(2)/blocal(3))**2)
991 else
992 mf(ix^d,3)=0.d0
993 end if
994 }
995 {end do\}
996 else
997 {do ix^db=ixmin^db,ixmax^db\}
998 {^iftwod
999 if(w(ix^d,iw_mag(1))/=0.d0) then
1000 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)
1001 else
1002 mf(ix^d,1)=0.d0
1003 end if
1004 if(w(ix^d,iw_mag(2))/=0.d0) then
1005 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)
1006 else
1007 mf(ix^d,2)=0.d0
1008 end if
1009 }
1010 {^ifthreed
1011 if(w(ix^d,iw_mag(1))/=0.d0) then
1012 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+&
1013 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(1)))**2)
1014 else
1015 mf(ix^d,1)=0.d0
1016 end if
1017 if(w(ix^d,iw_mag(2))/=0.d0) then
1018 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+&
1019 (w(ix^d,iw_mag(3))/w(ix^d,iw_mag(2)))**2)
1020 else
1021 mf(ix^d,2)=0.d0
1022 end if
1023 if(w(ix^d,iw_mag(3))/=0.d0) then
1024 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+&
1025 (w(ix^d,iw_mag(2))/w(ix^d,iw_mag(3)))**2)
1026 else
1027 mf(ix^d,3)=0.d0
1028 end if
1029 }
1030 {end do\}
1031 end if
1032 else
1033 mf(ix^s,1:ndim)=block%B0(ix^s,1:ndim,0)
1034 endif
1035 ! ixC is cell-corner index
1036 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1037 ! b unit vector at cell corner
1038 {^ifthreed
1039 do idims=1,3
1040 {do ix^db=ixcmin^db,ixcmax^db\}
1041 bc(ix^d,idims)=(mf(ix1,ix2,ix3,idims)*block%dvolume(ix1,ix2,ix3)+mf(ix1+1,ix2,ix3,idims)*block%dvolume(ix1+1,ix2,ix3)&
1042 +mf(ix1,ix2+1,ix3,idims)*block%dvolume(ix1,ix2+1,ix3)+mf(ix1+1,ix2+1,ix3,idims)*block%dvolume(ix1+1,ix2+1,ix3)&
1043 +mf(ix1,ix2,ix3+1,idims)*block%dvolume(ix1,ix2,ix3+1)+mf(ix1+1,ix2,ix3+1,idims)*block%dvolume(ix1+1,ix2,ix3+1)&
1044 +mf(ix1,ix2+1,ix3+1,idims)*block%dvolume(ix1,ix2+1,ix3+1)+mf(ix1+1,ix2+1,ix3+1,idims)*block%dvolume(ix1+1,ix2+1,ix3+1))&
1045 /(block%dvolume(ix1,ix2,ix3)+block%dvolume(ix1+1,ix2,ix3)+block%dvolume(ix1,ix2+1,ix3)+block%dvolume(ix1+1,ix2+1,ix3)&
1046 +block%dvolume(ix1,ix2,ix3+1)+block%dvolume(ix1+1,ix2,ix3+1)+block%dvolume(ix1,ix2+1,ix3+1)+block%dvolume(ix1+1,ix2+1,ix3+1))
1047 {end do\}
1048 end do
1049 }
1050 {^iftwod
1051 do idims=1,2
1052 {do ix^db=ixcmin^db,ixcmax^db\}
1053 bc(ix^d,idims)=(mf(ix1,ix2,idims)*block%dvolume(ix1,ix2)+mf(ix1+1,ix2,idims)*block%dvolume(ix1+1,ix2)&
1054 +mf(ix1,ix2+1,idims)*block%dvolume(ix1,ix2+1)+mf(ix1+1,ix2+1,idims)*block%dvolume(ix1+1,ix2+1))&
1055 /(block%dvolume(ix1,ix2)+block%dvolume(ix1+1,ix2)+block%dvolume(ix1,ix2+1)+block%dvolume(ix1+1,ix2+1))
1056 {end do\}
1057 end do
1058 }
1059 ! T gradient at cell faces
1060 do idims=1,ndim
1061 ixbmin^d=ixmin^d;
1062 ixbmax^d=ixmax^d-kr(idims,^d);
1063 call gradientf(te,x,ixi^l,ixb^l,idims,gradt(ixi^s,idims))
1064 end do
1065 if(fl%tc_constant) then
1066 if(fl%tc_perpendicular) then
1067 ka(ixc^s)=fl%tc_k_para-fl%tc_k_perp
1068 ke(ixc^s)=fl%tc_k_perp
1069 else
1070 ka(ixc^s)=fl%tc_k_para
1071 end if
1072 else
1073 ! conductivity at cell center
1074 if(phys_trac) then
1075 {do ix^db=ixmin^db,ixmax^db\}
1076 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
1077 qdd(ix^d)=fl%tc_k_para*dsqrt(block%wextra(ix^d,fl%Tcoff_)**5)
1078 else
1079 qdd(ix^d)=fl%tc_k_para*dsqrt(te(ix^d)**5)
1080 end if
1081 {end do\}
1082 else
1083 qdd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s)**5)
1084 end if
1085 ! cell corner parallel conductivity in ka
1086 {^ifthreed
1087 {do ix^db=ixcmin^db,ixcmax^db\}
1088 ka(ix^d)=(qdd(ix1,ix2,ix3)*block%dvolume(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)*block%dvolume(ix1+1,ix2,ix3)&
1089 +qdd(ix1,ix2+1,ix3)*block%dvolume(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)*block%dvolume(ix1+1,ix2+1,ix3)&
1090 +qdd(ix1,ix2,ix3+1)*block%dvolume(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)*block%dvolume(ix1+1,ix2,ix3+1)&
1091 +qdd(ix1,ix2+1,ix3+1)*block%dvolume(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1)*block%dvolume(ix1+1,ix2+1,ix3+1))&
1092 /(block%dvolume(ix1,ix2,ix3)+block%dvolume(ix1+1,ix2,ix3)+block%dvolume(ix1,ix2+1,ix3)+block%dvolume(ix1+1,ix2+1,ix3)&
1093 +block%dvolume(ix1,ix2,ix3+1)+block%dvolume(ix1+1,ix2,ix3+1)+block%dvolume(ix1,ix2+1,ix3+1)+block%dvolume(ix1+1,ix2+1,ix3+1))
1094 {end do\}
1095 }
1096 {^iftwod
1097 {do ix^db=ixcmin^db,ixcmax^db\}
1098 ka(ix^d)=(qdd(ix1,ix2)*block%dvolume(ix1,ix2)+qdd(ix1+1,ix2)*block%dvolume(ix1+1,ix2)&
1099 +qdd(ix1,ix2+1)*block%dvolume(ix1,ix2+1)+qdd(ix1+1,ix2+1)*block%dvolume(ix1+1,ix2+1))&
1100 /(block%dvolume(ix1,ix2)+block%dvolume(ix1+1,ix2)+block%dvolume(ix1,ix2+1)+block%dvolume(ix1+1,ix2+1))
1101 {end do\}
1102 }
1103 ! compensate with perpendicular conductivity
1104 if(fl%tc_perpendicular) then
1105 if(b0field) then
1106 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)
1107 else
1108 qdd(ix^s)=fl%tc_k_perp*rho(ix^s)**2/((^d&w(ix^s,iw_mag(^d))**2+)*dsqrt(te(ix^s))+smalldouble)
1109 end if
1110 {^ifthreed
1111 {do ix^db=ixcmin^db,ixcmax^db\}
1112 ke(ix^d)=(qdd(ix1,ix2,ix3)*block%dvolume(ix1,ix2,ix3)+qdd(ix1+1,ix2,ix3)*block%dvolume(ix1+1,ix2,ix3)&
1113 +qdd(ix1,ix2+1,ix3)*block%dvolume(ix1,ix2+1,ix3)+qdd(ix1+1,ix2+1,ix3)*block%dvolume(ix1+1,ix2+1,ix3)&
1114 +qdd(ix1,ix2,ix3+1)*block%dvolume(ix1,ix2,ix3+1)+qdd(ix1+1,ix2,ix3+1)*block%dvolume(ix1+1,ix2,ix3+1)&
1115 +qdd(ix1,ix2+1,ix3+1)*block%dvolume(ix1,ix2+1,ix3+1)+qdd(ix1+1,ix2+1,ix3+1)*block%dvolume(ix1+1,ix2+1,ix3+1))&
1116 /(block%dvolume(ix1,ix2,ix3)+block%dvolume(ix1+1,ix2,ix3)+block%dvolume(ix1,ix2+1,ix3)+block%dvolume(ix1+1,ix2+1,ix3)&
1117 +block%dvolume(ix1,ix2,ix3+1)+block%dvolume(ix1+1,ix2,ix3+1)+block%dvolume(ix1,ix2+1,ix3+1)+block%dvolume(ix1+1,ix2+1,ix3+1))
1118 if(ke(ix^d)<ka(ix^d)) then
1119 ka(ix^d)=ka(ix^d)-ke(ix^d)
1120 else
1121 ke(ix^d)=ka(ix^d)
1122 ka(ix^d)=0.d0
1123 end if
1124 {end do\}
1125 }
1126 {^iftwod
1127 {do ix^db=ixcmin^db,ixcmax^db\}
1128 ke(ix^d)=(qdd(ix1,ix2)*block%dvolume(ix1,ix2)+qdd(ix1+1,ix2)*block%dvolume(ix1+1,ix2)&
1129 +qdd(ix1,ix2+1)*block%dvolume(ix1,ix2+1)+qdd(ix1+1,ix2+1)*block%dvolume(ix1+1,ix2+1))&
1130 /(block%dvolume(ix1,ix2)+block%dvolume(ix1+1,ix2)+block%dvolume(ix1,ix2+1)+block%dvolume(ix1+1,ix2+1))
1131 if(ke(ix^d)<ka(ix^d)) then
1132 ka(ix^d)=ka(ix^d)-ke(ix^d)
1133 else
1134 ke(ix^d)=ka(ix^d)
1135 ka(ix^d)=0.d0
1136 end if
1137 {end do\}
1138 }
1139 end if
1140 end if
1141 if(fl%tc_slope_limiter==0) then
1142 ! calculate thermal conduction flux with symmetric scheme
1143 do idims=1,ndim
1144 !qdd corner values
1145 qdd=0.d0
1146 {do ix^db=0,1 \}
1147 if({ ix^d==0 .and. ^d==idims | .or.}) then
1148 ixbmin^d=ixcmin^d+ix^d;
1149 ixbmax^d=ixcmax^d+ix^d;
1150 qdd(ixc^s)=qdd(ixc^s)+gradt(ixb^s,idims)
1151 end if
1152 {end do\}
1153 ! temperature gradient at cell corner
1154 qvec(ixc^s,idims)=qdd(ixc^s)*0.5d0**(ndim-1)
1155 end do
1156 ! b grad T at cell corner
1157 qdd(ixc^s)=sum(qvec(ixc^s,1:ndim)*bc(ixc^s,1:ndim),dim=ndim+1)
1158 do idims=1,ndim
1159 ! TC flux at cell corner
1160 gradt(ixc^s,idims)=ka(ixc^s)*bc(ixc^s,idims)*qdd(ixc^s)
1161 if(fl%tc_perpendicular) gradt(ixc^s,idims)=gradt(ixc^s,idims)+ke(ixc^s)*qvec(ixc^s,idims)
1162 end do
1163 ! TC flux at cell face
1164 qvec=0.d0
1165 do idims=1,ndim
1166 ixb^l=ixo^l-kr(idims,^d);
1167 ixamax^d=ixomax^d; ixamin^d=ixbmin^d;
1168 {do ix^db=0,1 \}
1169 if({ ix^d==0 .and. ^d==idims | .or.}) then
1170 ixbmin^d=ixamin^d-ix^d;
1171 ixbmax^d=ixamax^d-ix^d;
1172 qvec(ixa^s,idims)=qvec(ixa^s,idims)+gradt(ixb^s,idims)
1173 end if
1174 {end do\}
1175 qvec(ixa^s,idims)=qvec(ixa^s,idims)*0.5d0**(ndim-1)
1176 if(fl%tc_saturate) then
1177 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1178 ! unsigned saturated TC flux = 5 phi rho c**3, c is isothermal sound speed
1179 bcf=0.d0
1180 {do ix^db=0,1 \}
1181 if({ ix^d==0 .and. ^d==idims | .or.}) then
1182 ixbmin^d=ixamin^d-ix^d;
1183 ixbmax^d=ixamax^d-ix^d;
1184 bcf(ixa^s,idims)=bcf(ixa^s,idims)+bc(ixb^s,idims)
1185 end if
1186 {end do\}
1187 ! averaged b at face centers
1188 bcf(ixa^s,idims)=bcf(ixa^s,idims)*0.5d0**(ndim-1)
1189 ixb^l=ixa^l+kr(idims,^d);
1190 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))
1191 {do ix^db=ixamin^db,ixamax^db\}
1192 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
1193 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
1194 end if
1195 {end do\}
1196 end if
1197 end do
1198 else
1199 ! calculate thermal conduction flux with slope-limited symmetric scheme
1200 do idims=1,ndim
1201 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1202 {^ifthreed
1203 if(idims==1) then
1204 {do ix^db=ixamin^db,ixamax^db\}
1205 ! averaged b at face centers
1206 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
1207 +bc(ix1,ix2,ix3-1,^d)+bc(ix1,ix2-1,ix3-1,^d))\
1208 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
1209 +ka(ix1,ix2,ix3-1)+ka(ix1,ix2-1,ix3-1))
1210 ! averaged thermal conductivity at face centers
1211 if(fl%tc_perpendicular) &
1212 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
1213 +ke(ix1,ix2,ix3-1)+ke(ix1,ix2-1,ix3-1))
1214 {end do\}
1215 else if(idims==2) then
1216 {do ix^db=ixamin^db,ixamax^db\}
1217 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1-1,ix2,ix3,^d)&
1218 +bc(ix1,ix2,ix3-1,^d)+bc(ix1-1,ix2,ix3-1,^d))\
1219 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1-1,ix2,ix3)&
1220 +ka(ix1,ix2,ix3-1)+ka(ix1-1,ix2,ix3-1))
1221 if(fl%tc_perpendicular) &
1222 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1-1,ix2,ix3)&
1223 +ke(ix1,ix2,ix3-1)+ke(ix1-1,ix2,ix3-1))
1224 {end do\}
1225 else
1226 {do ix^db=ixamin^db,ixamax^db\}
1227 ^d&bcf({ix^d},^d)=0.25d0*(bc({ix^d},^d)+bc(ix1,ix2-1,ix3,^d)&
1228 +bc(ix1-1,ix2,ix3,^d)+bc(ix1-1,ix2-1,ix3,^d))\
1229 kaf(ix^d)=0.25d0*(ka(ix1,ix2,ix3)+ka(ix1,ix2-1,ix3)&
1230 +ka(ix1-1,ix2,ix3)+ka(ix1-1,ix2-1,ix3))
1231 if(fl%tc_perpendicular) &
1232 kef(ix^d)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2-1,ix3)&
1233 +ke(ix1-1,ix2,ix3)+ke(ix1-1,ix2-1,ix3))
1234 {end do\}
1235 end if
1236 }
1237 {^iftwod
1238 if(idims==1) then
1239 {do ix^db=ixamin^db,ixamax^db\}
1240 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1,ix2-1,^d))\
1241 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1,ix2-1))
1242 if(fl%tc_perpendicular) &
1243 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2-1))
1244 {end do\}
1245 else
1246 {do ix^db=ixamin^db,ixamax^db\}
1247 ^d&bcf({ix^d},^d)=0.5d0*(bc(ix1,ix2,^d)+bc(ix1-1,ix2,^d))\
1248 kaf(ix^d)=0.5d0*(ka(ix1,ix2)+ka(ix1-1,ix2))
1249 if(fl%tc_perpendicular) &
1250 kef(ix^d)=0.5d0*(ke(ix1,ix2)+ke(ix1-1,ix2))
1251 {end do\}
1252 end if
1253 }
1254 ! eq (19)
1255 ! temperature gradient at cell corner
1256 {^ifthreed
1257 if(idims==1) then
1258 {do ix^db=ixcmin^db,ixcmax^db\}
1259 qdd(ix^d)=(gradt(ix1,ix2,ix3,idims)*block%surfaceC(ix1,ix2,ix3,1)&
1260 +gradt(ix1,ix2+1,ix3,idims)*block%surfaceC(ix1,ix2+1,ix3,1)&
1261 +gradt(ix1,ix2,ix3+1,idims)*block%surfaceC(ix1,ix2,ix3+1,1)&
1262 +gradt(ix1,ix2+1,ix3+1,idims)*block%surfaceC(ix1,ix2+1,ix3+1,1))/&
1263 (block%surfaceC(ix1,ix2,ix3,1)+block%surfaceC(ix1,ix2+1,ix3,1)&
1264 +block%surfaceC(ix1,ix2,ix3+1,1)+block%surfaceC(ix1,ix2+1,ix3+1,1))
1265 {end do\}
1266 else if(idims==2) then
1267 {do ix^db=ixcmin^db,ixcmax^db\}
1268 qdd(ix^d)=(gradt(ix1,ix2,ix3,idims)*block%surfaceC(ix1,ix2,ix3,2)&
1269 +gradt(ix1+1,ix2,ix3,idims)*block%surfaceC(ix1+1,ix2,ix3,2)&
1270 +gradt(ix1,ix2,ix3+1,idims)*block%surfaceC(ix1,ix2,ix3+1,2)&
1271 +gradt(ix1+1,ix2,ix3+1,idims)*block%surfaceC(ix1+1,ix2,ix3+1,2))/&
1272 (block%surfaceC(ix1,ix2,ix3,2)+block%surfaceC(ix1+1,ix2,ix3,2)&
1273 +block%surfaceC(ix1,ix2,ix3+1,2)+block%surfaceC(ix1+1,ix2,ix3+1,2)+1.d-300)
1274 {end do\}
1275 else
1276 {do ix^db=ixcmin^db,ixcmax^db\}
1277 qdd(ix^d)=(gradt(ix1,ix2,ix3,idims)*block%surfaceC(ix1,ix2,ix3,3)&
1278 +gradt(ix1+1,ix2,ix3,idims)*block%surfaceC(ix1+1,ix2,ix3,3)&
1279 +gradt(ix1,ix2+1,ix3,idims)*block%surfaceC(ix1,ix2+1,ix3,3)&
1280 +gradt(ix1+1,ix2+1,ix3,idims)*block%surfaceC(ix1+1,ix2+1,ix3,3))/&
1281 (block%surfaceC(ix1,ix2,ix3,3)+block%surfaceC(ix1+1,ix2,ix3,3)&
1282 +block%surfaceC(ix1,ix2+1,ix3,3)+block%surfaceC(ix1+1,ix2+1,ix3,3))
1283 {end do\}
1284 end if
1285 }
1286 {^iftwod
1287 if(idims==1) then
1288 {do ix^db=ixcmin^db,ixcmax^db\}
1289 qdd(ix^d)=(gradt(ix1,ix2,idims)*block%surfaceC(ix1,ix2,1)&
1290 +gradt(ix1,ix2+1,idims)*block%surfaceC(ix1,ix2+1,1))/&
1291 (block%surfaceC(ix1,ix2,1)+block%surfaceC(ix1,ix2+1,1))
1292 {end do\}
1293 else
1294 {do ix^db=ixcmin^db,ixcmax^db\}
1295 qdd(ix^d)=(gradt(ix1,ix2,idims)*block%surfaceC(ix1,ix2,2)&
1296 +gradt(ix1+1,ix2,idims)*block%surfaceC(ix1+1,ix2,2))/&
1297 (block%surfaceC(ix1,ix2,2)+block%surfaceC(ix1+1,ix2,2)+1.d-300)
1298 {end do\}
1299 end if
1300 }
1301 ! eq (21)
1302 {^ifthreed
1303 if(idims==1) then
1304 {do ix^db=ixamin^db,ixamax^db\}
1305 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1306 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1307 if(qdd(ix^d)<minq) then
1308 qd(ix^d,1)=minq
1309 else if(qdd(ix^d)>maxq) then
1310 qd(ix^d,1)=maxq
1311 else
1312 qd(ix^d,1)=qdd(ix^d)
1313 end if
1314 if(qdd(ix1,ix2-1,ix3)<minq) then
1315 qd(ix^d,2)=minq
1316 else if(qdd(ix1,ix2-1,ix3)>maxq) then
1317 qd(ix^d,2)=maxq
1318 else
1319 qd(ix^d,2)=qdd(ix1,ix2-1,ix3)
1320 end if
1321 if(qdd(ix1,ix2,ix3-1)<minq) then
1322 qd(ix^d,3)=minq
1323 else if(qdd(ix1,ix2,ix3-1)>maxq) then
1324 qd(ix^d,3)=maxq
1325 else
1326 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
1327 end if
1328 if(qdd(ix1,ix2-1,ix3-1)<minq) then
1329 qd(ix^d,4)=minq
1330 else if(qdd(ix1,ix2-1,ix3-1)>maxq) then
1331 qd(ix^d,4)=maxq
1332 else
1333 qd(ix^d,4)=qdd(ix1,ix2-1,ix3-1)
1334 end if
1335 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)&
1336 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1,ix2-1,ix3-1,idims)**2*qd(ix^d,4))
1337 if(fl%tc_perpendicular) &
1338 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))
1339 {end do\}
1340 else if(idims==2) then
1341 {do ix^db=ixamin^db,ixamax^db\}
1342 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1343 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1344 if(qdd(ix^d)<minq) then
1345 qd(ix^d,1)=minq
1346 else if(qdd(ix^d)>maxq) then
1347 qd(ix^d,1)=maxq
1348 else
1349 qd(ix^d,1)=qdd(ix^d)
1350 end if
1351 if(qdd(ix1-1,ix2,ix3)<minq) then
1352 qd(ix^d,2)=minq
1353 else if(qdd(ix1-1,ix2,ix3)>maxq) then
1354 qd(ix^d,2)=maxq
1355 else
1356 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
1357 end if
1358 if(qdd(ix1,ix2,ix3-1)<minq) then
1359 qd(ix^d,3)=minq
1360 else if(qdd(ix1,ix2,ix3-1)>maxq) then
1361 qd(ix^d,3)=maxq
1362 else
1363 qd(ix^d,3)=qdd(ix1,ix2,ix3-1)
1364 end if
1365 if(qdd(ix1-1,ix2,ix3-1)<minq) then
1366 qd(ix^d,4)=minq
1367 else if(qdd(ix1-1,ix2,ix3-1)>maxq) then
1368 qd(ix^d,4)=maxq
1369 else
1370 qd(ix^d,4)=qdd(ix1-1,ix2,ix3-1)
1371 end if
1372 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)&
1373 +bc(ix1,ix2,ix3-1,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2,ix3-1,idims)**2*qd(ix^d,4))
1374 if(fl%tc_perpendicular) &
1375 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))
1376 {end do\}
1377 else
1378 {do ix^db=ixamin^db,ixamax^db\}
1379 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1380 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1381 if(qdd(ix^d)<minq) then
1382 qd(ix^d,1)=minq
1383 else if(qdd(ix^d)>maxq) then
1384 qd(ix^d,1)=maxq
1385 else
1386 qd(ix^d,1)=qdd(ix^d)
1387 end if
1388 if(qdd(ix1-1,ix2,ix3)<minq) then
1389 qd(ix^d,2)=minq
1390 else if(qdd(ix1-1,ix2,ix3)>maxq) then
1391 qd(ix^d,2)=maxq
1392 else
1393 qd(ix^d,2)=qdd(ix1-1,ix2,ix3)
1394 end if
1395 if(qdd(ix1,ix2-1,ix3)<minq) then
1396 qd(ix^d,3)=minq
1397 else if(qdd(ix1,ix2-1,ix3)>maxq) then
1398 qd(ix^d,3)=maxq
1399 else
1400 qd(ix^d,3)=qdd(ix1,ix2-1,ix3)
1401 end if
1402 if(qdd(ix1-1,ix2-1,ix3)<minq) then
1403 qd(ix^d,4)=minq
1404 else if(qdd(ix1-1,ix2-1,ix3)>maxq) then
1405 qd(ix^d,4)=maxq
1406 else
1407 qd(ix^d,4)=qdd(ix1-1,ix2-1,ix3)
1408 end if
1409 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)&
1410 +bc(ix1,ix2-1,ix3,idims)**2*qd(ix^d,3)+bc(ix1-1,ix2-1,ix3,idims)**2*qd(ix^d,4))
1411 if(fl%tc_perpendicular) &
1412 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))
1413 {end do\}
1414 end if
1415 }
1416 {^iftwod
1417 if(idims==1) then
1418 {do ix^db=ixamin^db,ixamax^db\}
1419 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1420 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1421 if(qdd(ix^d)<minq) then
1422 qd(ix^d,1)=minq
1423 else if(qdd(ix^d)>maxq) then
1424 qd(ix^d,1)=maxq
1425 else
1426 qd(ix^d,1)=qdd(ix^d)
1427 end if
1428 if(qdd(ix1,ix2-1)<minq) then
1429 qd(ix^d,2)=minq
1430 else if(qdd(ix1,ix2-1)>maxq) then
1431 qd(ix^d,2)=maxq
1432 else
1433 qd(ix^d,2)=qdd(ix1,ix2-1)
1434 end if
1435 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))
1436 if(fl%tc_perpendicular) &
1437 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
1438 {end do\}
1439 else
1440 {do ix^db=ixamin^db,ixamax^db\}
1441 minq=min(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1442 maxq=max(alpha*gradt(ix^d,idims),gradt(ix^d,idims)/alpha)
1443 if(qdd(ix^d)<minq) then
1444 qd(ix^d,1)=minq
1445 else if(qdd(ix^d)>maxq) then
1446 qd(ix^d,1)=maxq
1447 else
1448 qd(ix^d,1)=qdd(ix^d)
1449 end if
1450 if(qdd(ix1-1,ix2)<minq) then
1451 qd(ix^d,2)=minq
1452 else if(qdd(ix1-1,ix2)>maxq) then
1453 qd(ix^d,2)=maxq
1454 else
1455 qd(ix^d,2)=qdd(ix1-1,ix2)
1456 end if
1457 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))
1458 if(fl%tc_perpendicular) &
1459 qvec(ix^d,idims)=qvec(ix^d,idims)+kef(ix^d)*0.5d0*(qd(ix^d,1)+qd(ix^d,2))
1460 {end do\}
1461 end if
1462 }
1463 ! calculate normal of magnetic field
1464 ixb^l=ixa^l+kr(idims,^d);
1465 bnorm(ixa^s)=0.5d0*(mf(ixa^s,idims)+mf(ixb^s,idims))
1466 ! limited transverse component, eq (17)
1467 ixbmin^d=ixamin^d;
1468 ixbmax^d=ixamax^d+kr(idims,^d);
1469 do idir=1,ndim
1470 if(idir==idims) cycle
1471 qdd(ixi^s)=slope_limiter(gradt(ixi^s,idir),ixi^l,ixb^l,idir,-1,fl%tc_slope_limiter)
1472 qdd(ixi^s)=slope_limiter(qdd,ixi^l,ixa^l,idims,1,fl%tc_slope_limiter)
1473 qvec(ixa^s,idims)=qvec(ixa^s,idims)+kaf(ixa^s)*bnorm(ixa^s)*bcf(ixa^s,idir)*qdd(ixa^s)
1474 end do
1475 if(fl%tc_saturate) then
1476 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1477 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
1478 ixb^l=ixa^l+kr(idims,^d);
1479 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))
1480 {do ix^db=ixamin^db,ixamax^db\}
1481 if(dabs(qvec(ix^d,idims))>qdd(ix^d)) then
1482 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qdd(ix^d)
1483 end if
1484 {end do\}
1485 end if
1486 end do
1487 end if
1488 end subroutine set_source_tc_mhd_geo
1489
1490 function slope_limiter(f,ixI^L,ixO^L,idims,pm,tc_slope_limiter) result(lf)
1492 integer, intent(in) :: ixi^l, ixo^l, idims, pm
1493 double precision, intent(in) :: f(ixi^s)
1494 double precision :: lf(ixi^s)
1495 integer, intent(in) :: tc_slope_limiter
1496
1497 double precision, parameter :: qsmall=1.d-12
1498 double precision :: signf(ixi^s)
1499 integer :: ixb^l
1500
1501 ixb^l=ixo^l+pm*kr(idims,^d);
1502 signf(ixo^s)=sign(1.d0,f(ixo^s))
1503 select case(tc_slope_limiter)
1504 case(1)
1505 ! 'MC' monotonized central limiter Woodward and Collela limiter (eq.3.51h), a factor of 2 is pulled out
1506 lf(ixo^s)=two*signf(ixo^s)* &
1507 max(zero,min(dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s),&
1508 signf(ixo^s)*quarter*(f(ixb^s)+f(ixo^s))))
1509 case(2)
1510 ! 'minmod' limiter
1511 lf(ixo^s)=signf(ixo^s)*max(0.d0,min(abs(f(ixo^s)),signf(ixo^s)*f(ixb^s)))
1512 case(3)
1513 ! 'superbee' Roe superbee limiter (eq.3.51i)
1514 lf(ixo^s)=signf(ixo^s)* &
1515 max(zero,min(two*dabs(f(ixo^s)),signf(ixo^s)*f(ixb^s)),&
1516 min(dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s)))
1517 case(4)
1518 ! 'koren' Barry Koren Right variant
1519 lf(ixo^s)=signf(ixo^s)* &
1520 max(zero,min(two*dabs(f(ixo^s)),two*signf(ixo^s)*f(ixb^s),&
1521 (two*f(ixb^s)*signf(ixo^s)+dabs(f(ixo^s)))*third))
1522 case(5)
1523 ! van Leer limiter
1524 lf(ixo^s)=two*max(f(ixb^s)*f(ixo^s),zero)/(f(ixo^s)+f(ixb^s)+qsmall)
1525 case default
1526 call mpistop("Unknown slope limiter for thermal conduction")
1527 end select
1528 end function slope_limiter
1529
1530 !> Get the explicit timestep for the TC (hd implementation)
1531 !> Note: also used in 1D MHD (or for neutrals in twofl)
1532 function get_tc_dt_hd(w,ixI^L,ixO^L,dx^D,x,fl) result(dtnew)
1533 ! Check diffusion time limit dt < dx_i**2 / ((gamma-1)*tc_k_para/rho)
1535
1536 integer, intent(in) :: ixi^l, ixo^l
1537 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim)
1538 double precision, intent(in) :: w(ixi^s,1:nw)
1539 type(tc_fluid), intent(in) :: fl
1540 double precision :: dtnew
1541
1542 double precision :: tmp(ixo^s),tmp2(ixo^s),te(ixi^s),rho(ixi^s),hfs(ixo^s),gradt(ixi^s)
1543 double precision :: dtdiff_tcond,maxtmp2
1544 integer :: idim
1545
1546 call fl%get_temperature_from_conserved(w,x,ixi^l,ixi^l,te)
1547 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1548
1549 if(fl%tc_constant) then
1550 tmp(ixo^s)=fl%tc_k_para/rho(ixo^s)
1551 else
1552 if(fl%tc_saturate) then
1553 ! Kannan 2016 MN 458, 410
1554 ! 3^1.5*kB^2/(4*sqrt(pi)*e^4)
1555 ! l_mfpe=3.d0**1.5d0*kB_cgs**2/(4.d0*sqrt(dpi)*e_cgs**4*37.d0)=7093.9239487765044d0
1556 if(si_unit) call mpistop("needs adjusting in get_tc_dt_hd")
1557 tmp2(ixo^s)=te(ixo^s)**2/rho(ixo^s)*7093.9239487765044d0*unit_temperature**2/(unit_numberdensity*unit_length)
1558 hfs=0.d0
1559 do idim=1,ndim
1560 call gradient(te,ixi^l,ixo^l,idim,gradt)
1561 hfs(ixo^s)=hfs(ixo^s)+gradt(ixo^s)**2
1562 end do
1563 ! kappa=kappa_Spitzer/(1+4.2*l_mfpe/(T/|gradT|))
1564 tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/(rho(ixo^s)*(1.d0+4.2d0*tmp2(ixo^s)*dsqrt(hfs(ixo^s))/te(ixo^s)))
1565 else
1566 tmp(ixo^s)=fl%tc_k_para*dsqrt((te(ixo^s))**5)/rho(ixo^s)
1567 end if
1568 end if
1569
1570 dtnew = bigdouble
1571 do idim=1,ndim
1572 ! approximate thermal conduction flux: tc_k_para/rho/dx**2
1573 maxtmp2=maxval(tmp(ixo^s)/(block%ds(ixo^s,idim)**2))
1574 ! dt< dx_idim**2/((gamma-1)*tc_k_para/rho)
1575 dtdiff_tcond=1.d0/(tc_gamma_1*maxtmp2+smalldouble)
1576 ! limit the time step
1577 dtnew=min(dtnew,dtdiff_tcond)
1578 end do
1579 dtnew=dtnew/dble(ndim)
1580 end function get_tc_dt_hd
1581
1582 subroutine sts_set_source_tc_hd(ixI^L,ixO^L,w,x,wres,fix_conserve_at_step,my_dt,igrid,nflux,fl)
1585
1586 integer, intent(in) :: ixi^l, ixo^l, igrid, nflux
1587 double precision, intent(in) :: x(ixi^s,1:ndim)
1588 double precision, intent(in) :: w(ixi^s,1:nw)
1589 double precision, intent(inout) :: wres(ixi^s,1:nw)
1590 double precision, intent(in) :: my_dt
1591 logical, intent(in) :: fix_conserve_at_step
1592 type(tc_fluid), intent(in) :: fl
1593
1594 double precision :: te(ixi^s),rho(ixi^s)
1595 double precision :: qvec(ixi^s,1:ndim),qd(ixi^s)
1596 double precision, allocatable, dimension(:^D&,:) :: qvec_equi
1597 double precision :: fluxall(ixi^s,1,1:ndim)
1598
1599 double precision :: dxinv(ndim)
1600 integer :: idims,ixa^l
1601
1602 dxinv=1.d0/dxlevel
1603
1604 !calculate Te in whole domain (+ghosts)
1605 call fl%get_temperature_from_eint(w, x, ixi^l, ixi^l, te)
1606 call fl%get_rho(w, x, ixi^l, ixi^l, rho)
1607 if(slab_uniform) then
1608 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
1609 else
1610 call set_source_tc_hd_geo(ixi^l,ixo^l,w,x,fl,qvec,rho,te)
1611 end if
1612 if(fl%has_equi) then
1613 allocate(qvec_equi(ixi^s,1:ndim))
1614 call fl%get_temperature_equi(w, x, ixi^l, ixi^l, te) !calculate Te in whole domain (+ghosts)
1615 call fl%get_rho_equi(w, x, ixi^l, ixi^l, rho) !calculate rho in whole domain (+ghosts)
1616 if(slab_uniform) then
1617 call set_source_tc_hd(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
1618 else
1619 call set_source_tc_hd_geo(ixi^l,ixo^l,w,x,fl,qvec_equi,rho,te)
1620 end if
1621 do idims=1,ndim
1622 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1623 qvec(ixa^s,idims)=qvec(ixa^s,idims)-qvec_equi(ixa^s,idims)
1624 end do
1625 deallocate(qvec_equi)
1626 endif
1627
1628 if(slab_uniform) then
1629 do idims=1,ndim
1630 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1631 qvec(ixa^s,idims)=dxinv(idims)*qvec(ixa^s,idims)
1632 ixa^l=ixo^l-kr(idims,^d);
1633 if(idims==1) then
1634 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
1635 else
1636 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
1637 end if
1638 end do
1639 else
1640 do idims=1,ndim
1641 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1642 qvec(ixa^s,idims)=qvec(ixa^s,idims)*block%surfaceC(ixa^s,idims)
1643 ixa^l=ixo^l-kr(idims,^d);
1644 if(idims==1) then
1645 qd(ixo^s)=qvec(ixo^s,idims)-qvec(ixa^s,idims)
1646 else
1647 qd(ixo^s)=qd(ixo^s)+qvec(ixo^s,idims)-qvec(ixa^s,idims)
1648 end if
1649 end do
1650 qd(ixo^s)=qd(ixo^s)/block%dvolume(ixo^s)
1651 end if
1652
1653 if(fix_conserve_at_step) then
1654 do idims=1,ndim
1655 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1656 fluxall(ixa^s,1,idims)=my_dt*qvec(ixa^s,idims)
1657 end do
1658 call store_flux(igrid,fluxall,1,ndim,nflux)
1659 end if
1660
1661 wres(ixo^s,fl%e_)=qd(ixo^s)
1662 end subroutine sts_set_source_tc_hd
1663
1664 !> get HD thermal conduction source and flux in uniform Cartesian grid
1665 subroutine set_source_tc_hd(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
1667 integer, intent(in) :: ixI^L, ixO^L
1668 double precision, intent(in) :: x(ixI^S,1:ndim)
1669 double precision, intent(in) :: w(ixI^S,1:nw)
1670 type(tc_fluid), intent(in) :: fl
1671 double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
1672 double precision, intent(out) :: qvec(ixI^S,1:ndim)
1673 double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
1674 integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L
1675
1676 ix^l=ixo^l^ladd1;
1677 ! ixC is cell-corner index
1678 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1679
1680 ! calculate thermal conduction flux with symmetric scheme
1681 ! T gradient (central difference) at cell corners
1682 do idims=1,ndim
1683 ixbmin^d=ixmin^d;
1684 ixbmax^d=ixmax^d-kr(idims,^d);
1685 call gradientf(te,x,ixi^l,ixb^l,idims,ke)
1686 {^ifthreed
1687 if(idims==1) then
1688 {do ix^db=ixcmin^db,ixcmax^db\}
1689 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1,ix2+1,ix3)&
1690 +ke(ix1,ix2,ix3+1)+ke(ix1,ix2+1,ix3+1))
1691 {end do\}
1692 else if(idims==2) then
1693 {do ix^db=ixcmin^db,ixcmax^db\}
1694 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1+1,ix2,ix3)&
1695 +ke(ix1,ix2,ix3+1)+ke(ix1+1,ix2,ix3+1))
1696 {end do\}
1697 else
1698 {do ix^db=ixcmin^db,ixcmax^db\}
1699 qvec(ix^d,idims)=0.25d0*(ke(ix1,ix2,ix3)+ke(ix1+1,ix2,ix3)&
1700 +ke(ix1,ix2+1,ix3)+ke(ix1+1,ix2+1,ix3))
1701 {end do\}
1702 end if
1703 }
1704 {^iftwod
1705 if(idims==1) then
1706 {do ix^db=ixcmin^db,ixcmax^db\}
1707 qvec(ix^d,idims)=0.5d0*(ke(ix1,ix2)+ke(ix1,ix2+1))
1708 {end do\}
1709 else
1710 {do ix^db=ixcmin^db,ixcmax^db\}
1711 qvec(ix^d,idims)=0.5d0*(ke(ix1,ix2)+ke(ix1+1,ix2))
1712 {end do\}
1713 end if
1714 }
1715 {^ifoned
1716 do ix1=ixcmin1,ixcmax1
1717 qvec(ix1,idims)=ke(ix1)
1718 end do
1719 }
1720 end do
1721 ! conductivity at cell center
1722 if(fl%tc_constant) then
1723 qd(ix^s)=fl%tc_k_para
1724 else
1725 if(phys_trac) then
1726 {do ix^db=ixmin^db,ixmax^db\}
1727 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
1728 qd(ix^d)=fl%tc_k_para*dsqrt(block%wextra(ix^d,fl%Tcoff_)**5)
1729 else
1730 qd(ix^d)=fl%tc_k_para*dsqrt(te(ix^d)**5)
1731 end if
1732 {end do\}
1733 else
1734 qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s)**5)
1735 end if
1736 end if
1737 ! conductivity Ke at cell corner
1738 ! cell corner conduction flux gradT
1739 {^ifthreed
1740 {do ix^db=ixcmin^db,ixcmax^db\}
1741 ke(ix^d)=0.125d0*(qd(ix1,ix2,ix3)+qd(ix1+1,ix2,ix3)&
1742 +qd(ix1,ix2+1,ix3)+qd(ix1+1,ix2+1,ix3)&
1743 +qd(ix1,ix2,ix3+1)+qd(ix1+1,ix2,ix3+1)&
1744 +qd(ix1,ix2+1,ix3+1)+qd(ix1+1,ix2+1,ix3+1))
1745 gradt(ix^d,1)=ke(ix^d)*qvec(ix^d,1)
1746 gradt(ix^d,2)=ke(ix^d)*qvec(ix^d,2)
1747 gradt(ix^d,3)=ke(ix^d)*qvec(ix^d,3)
1748 {end do\}
1749 }
1750 {^iftwod
1751 {do ix^db=ixcmin^db,ixcmax^db\}
1752 ke(ix^d)=0.25d0*(qd(ix1,ix2)+qd(ix1+1,ix2)+qd(ix1,ix2+1)+qd(ix1+1,ix2+1))
1753 gradt(ix^d,1)=ke(ix^d)*qvec(ix^d,1)
1754 gradt(ix^d,2)=ke(ix^d)*qvec(ix^d,2)
1755 {end do\}
1756 }
1757 {^ifoned
1758 do ix1=ixcmin1,ixcmax1
1759 gradt(ix^d,1)=0.5d0*(qd(ix1)+qd(ix1+1))*qvec(ix^d,1)
1760 end do
1761 }
1762
1763 ! conduction flux qvec at cell face
1764 do idims=1,ndim
1765 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1766 {^ifthreed
1767 if(idims==1) then
1768 {do ix^db=ixamin^db,ixamax^db\}
1769 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1770 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1,ix2-1,ix3-1,idims))
1771 {end do\}
1772 else if(idims==2) then
1773 {do ix^db=ixamin^db,ixamax^db\}
1774 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1-1,ix2,ix3,idims)&
1775 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1-1,ix2,ix3-1,idims))
1776 {end do\}
1777 else
1778 {do ix^db=ixamin^db,ixamax^db\}
1779 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1780 +gradt(ix1-1,ix2,ix3,idims)+gradt(ix1-1,ix2-1,ix3,idims))
1781 {end do\}
1782 end if
1783 }
1784 {^iftwod
1785 if(idims==1) then
1786 {do ix^db=ixamin^db,ixamax^db\}
1787 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2-1,idims))
1788 {end do\}
1789 else
1790 {do ix^db=ixamin^db,ixamax^db\}
1791 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1-1,ix2,idims))
1792 {end do\}
1793 end if
1794 }
1795 {^ifoned
1796 do ix1=ixamin1,ixamax1
1797 qvec(ix1,idims)=gradt(ix1,idims)
1798 end do
1799 }
1800 if(fl%tc_saturate) then
1801 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1802 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
1803 ixb^l=ixa^l+kr(idims,^d);
1804 qd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3
1805 {do ix^db=ixamin^db,ixamax^db\}
1806 if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
1807 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
1808 end if
1809 {end do\}
1810 end if
1811 end do
1812 end subroutine set_source_tc_hd
1813
1814 !> get HD thermal conduction source and flux in non-uniform geometry grid
1815 subroutine set_source_tc_hd_geo(ixI^L,ixO^L,w,x,fl,qvec,rho,Te)
1817 integer, intent(in) :: ixI^L, ixO^L
1818 double precision, intent(in) :: x(ixI^S,1:ndim)
1819 double precision, intent(in) :: w(ixI^S,1:nw)
1820 type(tc_fluid), intent(in) :: fl
1821 double precision, intent(in) :: Te(ixI^S),rho(ixI^S)
1822 double precision, intent(out) :: qvec(ixI^S,1:ndim)
1823 double precision :: gradT(ixI^S,1:ndim),ke(ixI^S),qd(ixI^S)
1824 integer :: idims,ix^D,ix^L,ixC^L,ixA^L,ixB^L
1825
1826 ix^l=ixo^l^ladd1;
1827 ! ixC is cell-corner index
1828 ixcmax^d=ixomax^d; ixcmin^d=ixomin^d-1;
1829
1830 ! calculate thermal conduction flux with symmetric scheme
1831 ! T gradient from face centers to cell corners: surface weighted average
1832 do idims=1,ndim
1833 ixbmin^d=ixmin^d;
1834 ixbmax^d=ixmax^d-kr(idims,^d);
1835 call gradientf(te,x,ixi^l,ixb^l,idims,ke)
1836 {^ifthreed
1837 if(idims==1) then
1838 {do ix^db=ixcmin^db,ixcmax^db\}
1839 qvec(ix^d,1)=(ke(ix1,ix2,ix3)*block%surfaceC(ix1,ix2,ix3,1)&
1840 +ke(ix1,ix2+1,ix3)*block%surfaceC(ix1,ix2+1,ix3,1)&
1841 +ke(ix1,ix2,ix3+1)*block%surfaceC(ix1,ix2,ix3+1,1)&
1842 +ke(ix1,ix2+1,ix3+1)*block%surfaceC(ix1,ix2+1,ix3+1,1))/&
1843 (block%surfaceC(ix1,ix2,ix3,1)+block%surfaceC(ix1,ix2+1,ix3,1)&
1844 +block%surfaceC(ix1,ix2,ix3+1,1)+block%surfaceC(ix1,ix2+1,ix3+1,1))
1845 {end do\}
1846 else if(idims==2) then
1847 {do ix^db=ixcmin^db,ixcmax^db\}
1848 qvec(ix^d,2)=(ke(ix1,ix2,ix3)*block%surfaceC(ix1,ix2,ix3,2)&
1849 +ke(ix1+1,ix2,ix3)*block%surfaceC(ix1+1,ix2,ix3,2)&
1850 +ke(ix1,ix2,ix3+1)*block%surfaceC(ix1,ix2,ix3+1,2)&
1851 +ke(ix1+1,ix2,ix3+1)*block%surfaceC(ix1+1,ix2,ix3+1,2))/&
1852 (block%surfaceC(ix1,ix2,ix3,2)+block%surfaceC(ix1+1,ix2,ix3,2)&
1853 +block%surfaceC(ix1,ix2,ix3+1,2)+block%surfaceC(ix1+1,ix2,ix3+1,2)+1.d-300)
1854 ! zero theta-normal surface area at pole axis
1855 {end do\}
1856 else
1857 {do ix^db=ixcmin^db,ixcmax^db\}
1858 qvec(ix^d,3)=(ke(ix1,ix2,ix3)*block%surfaceC(ix1,ix2,ix3,3)&
1859 +ke(ix1+1,ix2,ix3)*block%surfaceC(ix1+1,ix2,ix3,3)&
1860 +ke(ix1,ix2+1,ix3)*block%surfaceC(ix1,ix2+1,ix3,3)&
1861 +ke(ix1+1,ix2+1,ix3)*block%surfaceC(ix1+1,ix2+1,ix3,3))/&
1862 (block%surfaceC(ix1,ix2,ix3,3)+block%surfaceC(ix1+1,ix2,ix3,3)&
1863 +block%surfaceC(ix1,ix2+1,ix3,3)+block%surfaceC(ix1+1,ix2+1,ix3,3))
1864 {end do\}
1865 end if
1866 }
1867 {^iftwod
1868 if(idims==1) then
1869 {do ix^db=ixcmin^db,ixcmax^db\}
1870 qvec(ix^d,1)=(ke(ix1,ix2)*block%surfaceC(ix1,ix2,1)+ke(ix1,ix2+1)*block%surfaceC(ix1,ix2+1,1))&
1871 /(block%surfaceC(ix1,ix2,1)+block%surfaceC(ix1,ix2+1,1))
1872 {end do\}
1873 else
1874 {do ix^db=ixcmin^db,ixcmax^db\}
1875 qvec(ix^d,2)=(ke(ix1,ix2)*block%surfaceC(ix1,ix2,2)+ke(ix1+1,ix2)*block%surfaceC(ix1+1,ix2,2))&
1876 /(block%surfaceC(ix1,ix2,2)+block%surfaceC(ix1+1,ix2,2))
1877 {end do\}
1878 end if
1879 }
1880 {^ifoned
1881 do ix1=ixcmin1,ixcmax1
1882 qvec(ix1,idims)=ke(ix1)
1883 end do
1884 }
1885 end do
1886 ! conductivity at cell center
1887 if(fl%tc_constant) then
1888 qd(ix^s)=fl%tc_k_para
1889 else
1890 if(phys_trac) then
1891 {do ix^db=ixmin^db,ixmax^db\}
1892 if(te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
1893 qd(ix^d)=fl%tc_k_para*dsqrt(block%wextra(ix^d,fl%Tcoff_)**5)
1894 else
1895 qd(ix^d)=fl%tc_k_para*dsqrt(te(ix^d)**5)
1896 end if
1897 {end do\}
1898 else
1899 qd(ix^s)=fl%tc_k_para*dsqrt(te(ix^s)**5)
1900 end if
1901 end if
1902 ! conductivity Ke at cell corner
1903 ! cell corner conduction flux gradT
1904 {^ifthreed
1905 {do ix^db=ixcmin^db,ixcmax^db\}
1906 ke(ix^d)=(qd(ix1,ix2,ix3)*block%dvolume(ix1,ix2,ix3)+qd(ix1+1,ix2,ix3)*block%dvolume(ix1+1,ix2,ix3)&
1907 +qd(ix1,ix2+1,ix3)*block%dvolume(ix1,ix2+1,ix3)+qd(ix1+1,ix2+1,ix3)*block%dvolume(ix1+1,ix2+1,ix3)&
1908 +qd(ix1,ix2,ix3+1)*block%dvolume(ix1,ix2,ix3+1)+qd(ix1+1,ix2,ix3+1)*block%dvolume(ix1+1,ix2,ix3+1)&
1909 +qd(ix1,ix2+1,ix3+1)*block%dvolume(ix1,ix2+1,ix3+1)+qd(ix1+1,ix2+1,ix3+1)*block%dvolume(ix1+1,ix2+1,ix3+1))&
1910 /(block%dvolume(ix1,ix2,ix3)+block%dvolume(ix1+1,ix2,ix3)+block%dvolume(ix1,ix2+1,ix3)+block%dvolume(ix1+1,ix2+1,ix3)&
1911 +block%dvolume(ix1,ix2,ix3+1)+block%dvolume(ix1+1,ix2,ix3+1)+block%dvolume(ix1,ix2+1,ix3+1)+block%dvolume(ix1+1,ix2+1,ix3+1))
1912 gradt(ix^d,1)=ke(ix^d)*qvec(ix^d,1)
1913 gradt(ix^d,2)=ke(ix^d)*qvec(ix^d,2)
1914 gradt(ix^d,3)=ke(ix^d)*qvec(ix^d,3)
1915 {end do\}
1916 }
1917 {^iftwod
1918 {do ix^db=ixcmin^db,ixcmax^db\}
1919 ke(ix^d)=(qd(ix1,ix2)*block%dvolume(ix1,ix2)+qd(ix1+1,ix2)*block%dvolume(ix1+1,ix2)&
1920 +qd(ix1,ix2+1)*block%dvolume(ix1,ix2+1)+qd(ix1+1,ix2+1)*block%dvolume(ix1+1,ix2+1))&
1921 /(block%dvolume(ix1,ix2)+block%dvolume(ix1+1,ix2)+block%dvolume(ix1,ix2+1)+block%dvolume(ix1+1,ix2+1))
1922 gradt(ix^d,1)=ke(ix^d)*qvec(ix^d,1)
1923 gradt(ix^d,2)=ke(ix^d)*qvec(ix^d,2)
1924 {end do\}
1925 }
1926 {^ifoned
1927 do ix1=ixcmin1,ixcmax1
1928 gradt(ix^d,1)=(qd(ix1)*block%dvolume(ix1)+qd(ix1+1)*block%dvolume(ix1+1))/(block%dvolume(ix1)+block%dvolume(ix1+1))*qvec(ix^d,1)
1929 end do
1930 }
1931
1932 ! conduction flux qvec at cell face
1933 do idims=1,ndim
1934 ixamax^d=ixomax^d; ixamin^d=ixomin^d-kr(idims,^d);
1935 {^ifthreed
1936 if(idims==1) then
1937 {do ix^db=ixamin^db,ixamax^db\}
1938 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1939 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1,ix2-1,ix3-1,idims))
1940 {end do\}
1941 else if(idims==2) then
1942 {do ix^db=ixamin^db,ixamax^db\}
1943 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1-1,ix2,ix3,idims)&
1944 +gradt(ix1,ix2,ix3-1,idims)+gradt(ix1-1,ix2,ix3-1,idims))
1945 {end do\}
1946 else
1947 {do ix^db=ixamin^db,ixamax^db\}
1948 qvec(ix^d,idims)=0.25d0*(gradt(ix1,ix2,ix3,idims)+gradt(ix1,ix2-1,ix3,idims)&
1949 +gradt(ix1-1,ix2,ix3,idims)+gradt(ix1-1,ix2-1,ix3,idims))
1950 {end do\}
1951 end if
1952 }
1953 {^iftwod
1954 if(idims==1) then
1955 {do ix^db=ixamin^db,ixamax^db\}
1956 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1,ix2-1,idims))
1957 {end do\}
1958 else
1959 {do ix^db=ixamin^db,ixamax^db\}
1960 qvec(ix^d,idims)=0.5d0*(gradt(ix1,ix2,idims)+gradt(ix1-1,ix2,idims))
1961 {end do\}
1962 end if
1963 }
1964 {^ifoned
1965 do ix1=ixamin1,ixamax1
1966 qvec(ix1,idims)=gradt(ix1,idims)
1967 end do
1968 }
1969 if(fl%tc_saturate) then
1970 ! consider saturation (Cowie and Mckee 1977 ApJ, 211, 135)
1971 ! unsigned saturated TC flux = 5 phi rho c**3, c=sqrt(p/rho) is isothermal sound speed, phi=1.1
1972 ixb^l=ixa^l+kr(idims,^d);
1973 qd(ixa^s)=2.75d0*(rho(ixa^s)+rho(ixb^s))*dsqrt(0.5d0*(te(ixa^s)+te(ixb^s)))**3
1974 {do ix^db=ixamin^db,ixamax^db\}
1975 if(dabs(qvec(ix^d,idims))>qd(ix^d)) then
1976 qvec(ix^d,idims)=sign(1.d0,qvec(ix^d,idims))*qd(ix^d)
1977 end if
1978 {end do\}
1979 end if
1980 end do
1981 end subroutine set_source_tc_hd_geo
1982
1983end 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.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
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 explicit timestep for the TC (mhd implementation) Note: for multi-D MHD (1D MHD will use HD f...
double precision function, public get_tc_dt_hd(w, ixil, ixol, dxd, x, fl)
Get the explicit timestep for the TC (hd implementation) Note: also used in 1D MHD (or for neutrals i...
subroutine tc_init_params(phys_gamma)
subroutine, public sts_set_source_tc_hd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
subroutine, public sts_set_source_tc_mhd(ixil, ixol, w, x, wres, fix_conserve_at_step, my_dt, igrid, nflux, fl)
anisotropic thermal conduction with slope limited symmetric scheme Sharma 2007 Journal of Computation...
double precision tc_gamma_1
The adiabatic index.
subroutine, public tc_get_mhd_params(fl, read_mhd_params)
Init TC coefficients: MHD case.
subroutine set_source_tc_hd_geo(ixil, ixol, w, x, fl, qvec, rho, te)
get HD thermal conduction source and flux in non-uniform geometry grid
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)
get HD thermal conduction source and flux in uniform Cartesian grid
subroutine set_source_tc_mhd_geo(ixil, ixol, w, x, fl, qvec, rho, te, alpha)
subroutine set_source_tc_mhd(ixil, ixol, w, x, fl, qvec, rho, te, alpha)