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