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