MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_afld.t
Go to the documentation of this file.
1!> Module for including anisotropic flux limited diffusion (AFLD)-approximation in Radiation-hydrodynamics simulations using mod_rhd
2!> Based on Turner and stone 2001. See
3!> [1]Moens, N., Sundqvist, J. O., El Mellah, I., Poniatowski, L., Teunissen, J., and Keppens, R.,
4!> Radiation-hydrodynamics with MPI-AMRVAC . Flux-limited diffusion
5!> <i>Astronomy and Astrophysics</i>, vol. 657, 2022. doi:10.1051/0004-6361/202141023.
6!> For more information.
7
8module mod_afld
9 use mod_comm_lib, only: mpistop
10 implicit none
11
12 !> source split for energy interact and radforce:
13 logical :: fld_eint_split = .false.
14 logical :: fld_radforce_split = .false.
15 !> Opacity per unit of unit_density
16 double precision, public :: fld_kappa0 = 0.34d0
17 !> mean particle mass
18 double precision, public :: afld_mu = 0.6d0
19 !> Tolerance for bisection method for Energy sourceterms
20 !> This is a percentage of the minimum of gas- and radiation energy
21 double precision, public :: fld_bisect_tol = 1.d-4
22 !> Tolerance for adi method for radiative Energy diffusion
23 double precision, public :: fld_diff_tol = 1.d-4
24 !> Number for splitting the diffusion module
25 double precision, public :: diff_crit
26 !> Use constant Opacity?
27 character(len=8), allocatable :: fld_opacity_law(:)
28 character(len=50) :: fld_opal_table = 'Y09800'
29 !> Diffusion limit lambda = 0.33
30 character(len=16) :: fld_fluxlimiter = 'Pomraning'
31 ! !> diffusion coefficient for multigrid method
32 integer, allocatable :: i_diff_mg(:)
33 !> Which method to find the root for the energy interaction polynomial
34 character(len=8) :: fld_interaction_method = 'Halley'
35 !> Set Diffusion coefficient to unity
36 logical :: fld_diff_testcase = .false.
37 !> Take running average for Diffusion coefficient
38 logical :: diff_coef_filter = .false.
39 integer :: size_d_filter = 1
40 !> Take a running average over the fluxlimiter
41 logical :: flux_lim_filter = .false.
42 integer :: size_l_filter = 1
43 !> Use or dont use lineforce opacities
44 logical :: lineforce_opacities = .false.
45 !> Resume run when multigrid returns error
46 logical :: diffcrash_resume = .true.
47 !> A copy of rhd_Gamma
48 double precision, private, protected :: afld_gamma
49 !> running timestep for diffusion solver, initialised as zero
50 double precision :: dt_diff = 0.d0
51 !> public methods
52 !> these are called in mod_rhd_phys
53 public :: get_afld_rad_force
55 public :: afld_radforce_get_dt
56 public :: afld_init
57 public :: afld_get_radflux
58 public :: afld_get_radpress
59 public :: afld_get_fluxlimiter
60 public :: afld_get_opacity
61 contains
62
63 !> Reading in fld-list parameters from .par file
64 subroutine afld_params_read(files)
67 character(len=*), intent(in) :: files(:)
68 integer :: n
69
70 namelist /fld_list/ fld_kappa0, fld_eint_split, fld_radforce_split, &
75
76 do n = 1, size(files)
77 open(unitpar, file=trim(files(n)), status="old")
78 read(unitpar, fld_list, end=111)
79 111 close(unitpar)
80 end do
81 end subroutine afld_params_read
82
83 !> Initialising FLD-module:
84 !> Read opacities
85 !> Initialise Multigrid
86 !> adimensionalise kappa
87 !> Add extra variables to w-array, flux, kappa, eddington Tensor
88 !> Lambda and R
89 !> ...
90 subroutine afld_init(He_abundance, afld_gamma)
93 use mod_physics
96 double precision, intent(in) :: he_abundance, afld_gamma
97 double precision :: sigma_thomson
98 integer :: idir,jdir
99 character(len=1) :: ind_1
100 character(len=1) :: ind_2
101 character(len=2) :: cmp_f
102 character(len=5) :: cmp_e
103
104 !> allocate boundary conditions
105 allocate(fld_opacity_law(1:ndim))
106 fld_opacity_law(1:ndim) = 'const'
107
108 !> read par files
110
111 use_multigrid = .true.
114 mg%n_extra_vars = 1
115 mg%operator_type = mg_ahelmholtz
116 allocate(i_diff_mg(ndim))
117 do idir = 1,ndim
118 write(ind_1,'(I1)') idir
119 cmp_f = 'D' // ind_1
120 i_diff_mg(idir) = var_set_extravar(cmp_f,cmp_f)
121 enddo
122 !> Need mean molecular weight
123 afld_mu = (1.+4*he_abundance)/(2.+3.*he_abundance)
124 end subroutine afld_init
125
126 !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
127 !> This subroutine handles the radiation force
128 subroutine get_afld_rad_force(qdt,ixI^L,ixO^L,wCT,w,x,&
129 energy,qsourcesplit,active)
130 use mod_constants
133 use mod_geometry
134 integer, intent(in) :: ixi^l, ixo^l
135 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
136 double precision, intent(in) :: wct(ixi^s,1:nw)
137 double precision, intent(inout) :: w(ixi^s,1:nw)
138 logical, intent(in) :: energy,qsourcesplit
139 logical, intent(inout) :: active
140 double precision :: radiation_forcect(ixo^s,1:ndim)
141 double precision :: kappact(ixo^s,1:ndim)
142 double precision :: rad_fluxct(ixo^s,1:ndim)
143 double precision :: div_v(ixi^s,1:ndim,1:ndim)
144 double precision :: edd(ixo^s,1:ndim,1:ndim)
145 double precision :: nabla_vp(ixo^s)
146 double precision :: vel(ixi^s), grad_v(ixi^s), grad0_v(ixo^s)
147 double precision :: grad_e(ixi^s)
148 integer :: idir, jdir
149 double precision :: afld_r(ixo^s,1:ndim), lambda(ixo^s,1:ndim)
150
151 !> Calculate and add sourceterms
152 if(qsourcesplit .eqv. fld_radforce_split) then
153 active = .true.
154 call afld_get_fluxlimiter(wct,x,ixi^l,ixo^l,lambda,afld_r,nghostcells)
155 do idir = 1,ndim
156 !> Radiation force = kappa*rho/c *Flux = lambda gradE
157 call gradient(wct(ixi^s,iw_r_e),ixi^l,ixo^l,idir,grad_e,nghostcells)
158 radiation_forcect(ixo^s,idir) = -lambda(ixo^s,idir)*grad_e(ixo^s)
159 !> Momentum equation source term
160 w(ixo^s,iw_mom(idir)) = w(ixo^s,iw_mom(idir)) &
161 + qdt*radiation_forcect(ixo^s,idir)
162 !> Energy equation source term (kinetic energy)
163 w(ixo^s,iw_e) = w(ixo^s,iw_e) &
164 + qdt*wct(ixo^s,iw_mom(idir))/wct(ixo^s,iw_rho)*radiation_forcect(ixo^s,idir)
165 enddo
166 !> Photon tiring
167 !> calculate tensor div_v
168 !> !$OMP PARALLEL DO
169 do idir = 1,ndim
170 do jdir = 1,ndim
171 vel(ixi^s) = wct(ixi^s,iw_mom(jdir))/wct(ixi^s,iw_rho)
172 call gradient(vel,ixi^l,ixo^l,idir,grad_v)
173 div_v(ixo^s,idir,jdir) = grad_v(ixo^s)
174 enddo
175 enddo
176 !> !$OMP END PARALLEL DO
177 call afld_get_eddington(wct, x, ixi^l, ixo^l, edd, nghostcells)
178 !> VARIABLE NAMES DIV ARE ACTUALLY GRADIENTS
179 {^ifoned
180 nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1)
181 }
182 {^iftwod
183 !>eq 34 Turner and stone (Only 2D)
184 nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
185 + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
186 + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
187 + div_v(ixo^s,2,2)*edd(ixo^s,2,2)
188 }
189 {^ifthreed
190 nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
191 + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
192 + div_v(ixo^s,1,3)*edd(ixo^s,1,3) &
193 + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
194 + div_v(ixo^s,2,2)*edd(ixo^s,2,2) &
195 + div_v(ixo^s,2,3)*edd(ixo^s,2,3) &
196 + div_v(ixo^s,3,1)*edd(ixo^s,3,1) &
197 + div_v(ixo^s,3,2)*edd(ixo^s,3,2) &
198 + div_v(ixo^s,3,3)*edd(ixo^s,3,3)
199 }
200 w(ixo^s,iw_r_e) = w(ixo^s,iw_r_e) &
201 - qdt * nabla_vp(ixo^s)*wct(ixo^s,iw_r_e)
202 end if
203 end subroutine get_afld_rad_force
204
205 subroutine afld_radforce_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
208 use mod_geometry
209 integer, intent(in) :: ixi^l, ixo^l
210 double precision, intent(in) :: dx^d, x(ixi^s,1:ndim), w(ixi^s,1:nw)
211 double precision, intent(inout) :: dtnew
212 integer :: idir
213 double precision :: radiation_force(ixo^s,1:ndim)
214 double precision :: lambda(ixo^s,1:ndim), grad_e(ixi^s)
215 double precision :: dxinv(1:ndim), afld_r(ixo^s,1:ndim)
216 double precision :: max_grad
217
218 ^d&dxinv(^d)=one/dx^d;
219 call afld_get_fluxlimiter(w,x,ixi^l,ixo^l,lambda,afld_r,nghostcells)
220 do idir = 1, ndim
221 call gradient(w(ixi^s,iw_r_e),ixi^l,ixo^l,idir,grad_e,nghostcells)
222 radiation_force(ixo^s,idir) = -lambda(ixo^s,idir)*grad_e(ixo^s)
223 max_grad = maxval(abs(radiation_force(ixo^s,idir)))
224 max_grad = max(max_grad, epsilon(1.0d0))
225 dtnew = min(dtnew, courantpar/sqrt(max_grad*dxinv(idir)))
226 end do
227 end subroutine afld_radforce_get_dt
228
229 !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
230 !> This subroutine handles the energy exchange between gas and radiation
231 subroutine get_afld_energy_interact(qdt,ixI^L,ixO^L,wCT,w,x,&
232 energy,qsourcesplit,active)
233 use mod_constants
236 use mod_physics, only: phys_get_pthermal !needed to get temp
237 integer, intent(in) :: ixi^l, ixo^l
238 double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
239 double precision, intent(in) :: wct(ixi^s,1:nw)
240 double precision, intent(inout) :: w(ixi^s,1:nw)
241 logical, intent(in) :: energy,qsourcesplit
242 logical, intent(inout) :: active
243
244 !> Calculate and add sourceterms
245 if(qsourcesplit .eqv. fld_eint_split) then
246 active = .true.
247 !> Add energy sourceterms
248 call energy_interaction(w,w,x,ixi^l,ixo^l)
249 end if
250 end subroutine get_afld_energy_interact
251
252 !> Sets the opacity in the w-array
253 !> by calling mod_opal_opacity
254 subroutine afld_get_opacity(w, x, ixI^L, ixO^L, fld_kappa)
257 use mod_physics, only: phys_get_tgas
260 integer, intent(in) :: ixi^l, ixo^l
261 double precision, intent(in) :: w(ixi^s, 1:nw)
262 double precision, intent(in) :: x(ixi^s, 1:ndim)
263 double precision, intent(out) :: fld_kappa(ixo^s,1:ndim)
264 integer :: i,j,ix^d, idir
265 double precision :: temp(ixi^s), pth(ixi^s), a2(ixo^s)
266 double precision :: rho0,temp0,n,sigma_b
267 double precision :: akram, bkram
268 double precision :: vth(ixo^s), gradv(ixi^s), eta(ixo^s), t(ixo^s)
269
270 do idir = 1, ndim
271 select case (fld_opacity_law(idir))
272 case('const')
273 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity
274 case('thomson')
275 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity
276 case('kramers')
277 rho0 = half !> Take lower value of rho in domain
278 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity*((w(ixo^s,iw_rho)/rho0))
279 case('bump')
280 !> Opacity bump
281 rho0 = 0.2d0
282 n = 7.d0
283 sigma_b = 2.d-2
284 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity*(one + n*dexp(-one/sigma_b*(dlog(w(ixo^s,iw_rho)/rho0))**two))
285 case('non_iso')
286 call phys_get_pthermal(w,x,ixi^l,ixo^l,temp)
287 temp(ixo^s) = temp(ixo^s)/w(ixo^s,iw_rho)
288 rho0 = 0.5d0 !> Take lower value of rho in domain
289 temp0 = one
290 n = -7.d0/two
291 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity*(w(ixo^s,iw_rho)/rho0)*(temp(ixo^s)/temp0)**n
292 case('fastwind')
293 call phys_get_pthermal(w,x,ixi^l,ixo^l,pth)
294 a2(ixo^s) = pth(ixo^s)/w(ixo^s,iw_rho)*unit_velocity**2.d0
295 akram = 13.1351597305d0
296 bkram = -4.5182188206d0
297 fld_kappa(ixo^s,idir) = fld_kappa0/unit_opacity &
298 * (1.d0+10.d0**akram*w(ixo^s,iw_rho)*unit_density*(a2(ixo^s)/1.d12)**bkram)
299 {do ix^d=ixomin^d,ixomax^d\ }
300 !> Hard limit on kappa
301 fld_kappa(ix^d,idir) = min(fld_kappa(ix^d,idir),2.3d0*fld_kappa0/unit_opacity)
302 {enddo\}
303 case('opal')
304 call phys_get_tgas(w,x,ixi^l,ixo^l,temp)
305 {do ix^d=ixomin^d,ixomax^d\ }
306 rho0 = w(ix^d,iw_rho)*unit_density
307 temp0 = temp(ix^d)*unit_temperature
308 call set_opal_opacity(rho0,temp0,n)
309 fld_kappa(ix^d,idir) = n/unit_opacity
310 {enddo\}
311 case('special')
312 if (.not. associated(usr_special_aniso_opacity)) then
313 call mpistop("special opacity not defined")
314 endif
315 call usr_special_aniso_opacity(ixi^l,ixo^l,w,x,fld_kappa(ixo^s,idir),idir)
316 case default
317 call mpistop("Doesn't know opacity law")
318 end select
319 end do
320 end subroutine afld_get_opacity
321
322 !> Calculate fld flux limiter
323 !> This subroutine calculates flux limiter lambda using the prescription
324 !> stored in fld_fluxlimiter.
325 !> It also calculates the ratio of radiation scaleheight and mean free path
326 subroutine afld_get_fluxlimiter(w,x,ixI^L,ixO^L,fld_lambda,fld_R,nth)
328 use mod_geometry
330 integer, intent(in) :: ixi^l, ixo^l, nth
331 double precision, intent(in) :: w(ixi^s, 1:nw)
332 double precision, intent(in) :: x(ixi^s, 1:ndim)
333 double precision, intent(out) :: fld_r(ixo^s,1:ndim), fld_lambda(ixo^s,1:ndim)
334 integer :: idir, ix^d
335 integer :: filter, idim
336 double precision :: kappa(ixo^s,1:ndim)
337 double precision :: normgrad2(ixo^s)
338 double precision :: grad_r_e(ixi^s)
339 double precision :: rad_e(ixi^s)
340 double precision :: tmp_l(ixi^s), filtered_l(ixi^s)
341
342 select case (fld_fluxlimiter)
343 case('Diffusion')
344 fld_lambda(ixo^s,1:ndim) = 1.d0/3.d0
345 fld_r(ixo^s,1:ndim) = zero
346 case('FreeStream')
347 !> Calculate R everywhere
348 !> |grad E|/(rho kappa E)
349 rad_e(ixi^s) = w(ixi^s, iw_r_e)
350 call afld_get_opacity(w,x,ixi^l,ixo^l,kappa)
351 do idir=1,ndim
352 call gradient(rad_e,ixi^l,ixo^l,idir,grad_r_e,nth)
353 normgrad2(ixo^s) = grad_r_e(ixo^s)**2
354 fld_r(ixo^s,idir) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s,idir)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
355 ! Note: possible zeros for uniform setup, to adjust
356 if(maxval(normgrad2(ixo^s))==0.0d0)call mpistop("choose other fluxlimiter, FreeStream has issues")
357 !> Calculate the flux limiter, lambda
358 fld_lambda(ixo^s,idir) = one/fld_r(ixo^s,idir)
359 end do
360 case('Pomraning')
361 !> Calculate R everywhere
362 !> |grad E|/(rho kappa E)
363 normgrad2(ixo^s) = zero
364 rad_e(ixi^s) = w(ixi^s,iw_r_e)
365 call afld_get_opacity(w,x,ixi^l,ixo^l,kappa)
366 do idir = 1,ndim
367 call gradient(rad_e,ixi^l,ixo^l,idir,grad_r_e,nth)
368 normgrad2(ixo^s) = grad_r_e(ixo^s)**2
369 fld_r(ixo^s,idir) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s,idir)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
370 !> Calculate the flux limiter, lambda
371 !> Levermore and Pomraning: lambda = (2 + R)/(6 + 3R + R^2)
372 fld_lambda(ixo^s,idir) = (2.d0+fld_r(ixo^s,idir))/(6.d0+3*fld_r(ixo^s,idir)+fld_r(ixo^s,idir)**2.d0)
373 end do
374 case('Minerbo')
375 !> Calculate R everywhere
376 !> |grad E|/(rho kappa E)
377 normgrad2(ixo^s) = zero
378 rad_e(ixi^s) = w(ixi^s,iw_r_e)
379 call afld_get_opacity(w,x,ixi^l,ixo^l,kappa)
380 do idir = 1,ndim
381 call gradient(rad_e,ixi^l,ixo^l,idir,grad_r_e,nth)
382 normgrad2(ixo^s) = grad_r_e(ixo^s)**2
383 fld_r(ixo^s,idir) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s,idir)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
384 !> Calculate the flux limiter, lambda
385 !> Minerbo:
386 {do ix^d=ixomin^d,ixomax^d\ }
387 if(fld_r(ix^d,idir) .lt. 3.d0/2.d0) then
388 fld_lambda(ix^d,idir) = 2.d0/(3.d0 + dsqrt(9.d0 + 12.d0*fld_r(ix^d,idir)**2.d0))
389 else
390 fld_lambda(ix^d,idir) = 1.d0/(1.d0 + fld_r(ix^d,idir) + dsqrt(1.d0 + 2.d0*fld_r(ix^d,idir)))
391 endif
392 {enddo\}
393 end do
394 case('special')
395 if (.not. associated(usr_special_fluxlimiter)) then
396 call mpistop("special fluxlimiter not defined")
397 endif
398 call usr_special_fluxlimiter(ixi^l, ixo^l, w, x, fld_lambda, fld_r)
399 case default
400 call mpistop('Fluxlimiter unknown')
401 end select
402
403 if(flux_lim_filter) then
404 if(size_l_filter .lt. 1) call mpistop("D filter of size < 1 makes no sense")
405 if(size_l_filter .gt. nghostcells) call mpistop("D filter of size > nghostcells makes no sense")
406 do idir=1,ndim
407 tmp_l(ixo^s) = fld_lambda(ixo^s,idir)
408 filtered_l(ixo^s) = zero
409 do filter = 1,size_l_filter
410 {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_l_filter\}
411 do idim = 1,ndim
412 filtered_l(ix^d) = filtered_l(ix^d) &
413 + tmp_l(ix^d+filter*kr(idim,^d)) &
414 + tmp_l(ix^d-filter*kr(idim,^d))
415 enddo
416 {enddo\}
417 enddo
418 {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
419 tmp_l(ix^d) = (tmp_l(ix^d)+filtered_l(ix^d))/(1+2*size_l_filter*ndim)
420 {enddo\}
421 enddo
422 fld_lambda(ixo^s,idir) = tmp_l(ixo^s)
423 endif
424 end subroutine afld_get_fluxlimiter
425
426 !> Calculate Radiation Flux
427 !> Calculate the Flux using the fld closure relation
428 !> F = -c*lambda/(kappa*rho) *grad E
429 subroutine afld_get_radflux(w, x, ixI^L, ixO^L, rad_flux, nth)
431 use mod_geometry
432 integer, intent(in) :: ixi^l, ixo^l, nth
433 double precision, intent(in) :: w(ixi^s, 1:nw)
434 double precision, intent(in) :: x(ixi^s, 1:ndim)
435 double precision, intent(out) :: rad_flux(ixo^s, 1:ndim)
436 integer :: ix^d, idir
437 double precision :: cc
438 double precision :: grad_r_e(ixi^s)
439 double precision :: rad_e(ixi^s)
440 double precision :: kappa(ixo^s,1:ndim), lambda(ixo^s,1:ndim), fld_r(ixo^s,1:ndim)
441
442 cc = const_c/unit_velocity
443 rad_e(ixi^s) = w(ixi^s, iw_r_e)
444 call afld_get_opacity(w, x, ixi^l, ixo^l, kappa)
445 call afld_get_fluxlimiter(w, x, ixi^l, ixo^l, lambda, fld_r, nghostcells)
446 do idir = 1,ndim
447 call gradient(rad_e,ixi^l,ixo^l,idir,grad_r_e,nghostcells)
448 rad_flux(ixo^s, idir) = -cc*lambda(ixo^s,idir)/(kappa(ixo^s,idir)*w(ixo^s,iw_rho))*grad_r_e(ixo^s)
449 end do
450 end subroutine afld_get_radflux
451
452 !> Calculate Eddington-tensor
453 !> Stores Eddington-tensor in w-array
454 subroutine afld_get_eddington(w, x, ixI^L, ixO^L, eddington_tensor, nth)
456 use mod_geometry
457 integer, intent(in) :: ixI^L, ixO^L, nth
458 double precision, intent(in) :: w(ixI^S, 1:nw)
459 double precision, intent(in) :: x(ixI^S, 1:ndim)
460 double precision, intent(out) :: eddington_tensor(ixO^S,1:ndim,1:ndim)
461 double precision :: tnsr2(ixO^S,1:ndim,1:ndim)
462 double precision :: normgrad2(ixO^S), f(ixO^S,1:ndim)
463 double precision :: grad_r_e(ixI^S,1:ndim), rad_e(ixI^S)
464 double precision :: lambda(ixO^S,1:ndim), fld_R(ixO^S,1:ndim)
465 integer :: i,j, idir,jdir
466
467 call afld_get_fluxlimiter(w,x,ixi^l,ixo^l,lambda,fld_r, nth)
468 !> Calculate R everywhere
469 !> |grad E|/(rho kappa E)
470 normgrad2(ixo^s) = zero
471 rad_e(ixi^s) = w(ixi^s, iw_r_e)
472 do idir = 1,ndim
473 call gradient(rad_e,ixi^l,ixo^l,idir,grad_r_e(ixi^s,idir),nth)
474 normgrad2(ixo^s) = normgrad2(ixo^s)+grad_r_e(ixo^s,idir)**2
475 !> Calculate radiation pressure
476 !> P = (lambda + lambda^2 R^2)*E
477 f(ixo^s,idir) = lambda(ixo^s,idir)+lambda(ixo^s,idir)**two*fld_r(ixo^s,idir)**two
478 f(ixo^s,idir) = half*(one-f(ixo^s,idir))+half*(3.d0*f(ixo^s,idir)-one)
479 end do
480
481 {^ifoned
482 eddington_tensor(ixo^s,1,1) = f(ixo^s,1)
483 }
484 {^nooned
485 do idir = 1,ndim
486 eddington_tensor(ixo^s,idir,idir) = half*(one-f(ixo^s,idir))
487 enddo
488 do idir = 1,ndim
489 do jdir = 1,ndim
490 if(idir .ne. jdir) eddington_tensor(ixo^s,idir,jdir) = zero
491 tnsr2(ixo^s,idir,jdir) = half*(3.d0*f(ixo^s,idir) - 1)&
492 * grad_r_e(ixo^s,idir)*grad_r_e(ixo^s,jdir)/max(normgrad2(ixo^s),smalldouble)
493 enddo
494 enddo
495 do idir = 1,ndim
496 do jdir = 1,ndim
497 where(normgrad2(ixo^s) .gt. smalldouble)
498 eddington_tensor(ixo^s,idir,jdir) = eddington_tensor(ixo^s,idir,jdir)+tnsr2(ixo^s,idir,jdir)
499 endwhere
500 enddo
501 enddo
502 }
503 end subroutine afld_get_eddington
504
505 !> Calculate Radiation Pressure
506 !> Returns Radiation Pressure as tensor
507 subroutine afld_get_radpress(w, x, ixI^L, ixO^L, rad_pressure, nth)
509 integer, intent(in) :: ixi^l, ixo^l, nth
510 double precision, intent(in) :: w(ixi^s, 1:nw)
511 double precision, intent(in) :: x(ixi^s, 1:ndim)
512 double precision, intent(out):: rad_pressure(ixo^s,1:ndim,1:ndim)
513 integer :: i,j
514 double precision :: eddington_tensor(ixo^s,1:ndim,1:ndim)
515
516 call afld_get_eddington(w,x,ixi^l,ixo^l,eddington_tensor, nth)
517 do i=1,ndim
518 do j=1,ndim
519 rad_pressure(ixo^s,i,j) = eddington_tensor(ixo^s,i,j)*w(ixo^s,iw_r_e)
520 enddo
521 enddo
522 end subroutine afld_get_radpress
523
524!> Calling all subroutines to perform the multigrid method
525!> Communicates rad_e and diff_coeff to multigrid library
526 subroutine diffuse_e_rad_mg(dtfactor,qdt,qtC,psa,psb)
528 use mod_forest
532 type(state), target :: psa(max_blocks)
533 type(state), target :: psb(max_blocks)
534 double precision, intent(in) :: qdt
535 double precision, intent(in) :: qtC
536 double precision, intent(in) :: dtfactor
537 integer, parameter :: max_its = 50
538 integer :: n
539 integer :: iw_to,iw_from
540 integer :: iigrid, igrid, id
541 integer :: nc, lvl, i
542 type(tree_node), pointer :: pnode
543 double precision :: fac, facD
544 double precision :: res, max_residual, lambda
545
546 !> Set diffusion timestep, add previous timestep if mg did not converge:
547 dt_diff = dt_diff + qdt
548 ! Avoid setting a very restrictive limit to the residual when the time step
549 ! is small (as the operator is ~ 1/(D * qdt))
550 if (qdt < dtmin) then
551 if(mype==0)then
552 print *,'skipping implicit solve: dt too small!'
553 print *,'Currently at time=',global_time,' time step=',qdt,' dtmin=',dtmin
554 endif
555 return
556 endif
557 ! max_residual = 1d-7/qdt
558 max_residual = fld_diff_tol !1d-7/qdt
559 mg%operator_type = mg_ahelmholtz
560 mg%smoother_type = mg_smoother_gsrb
561 call mg_set_methods(mg)
562 if (.not. mg%is_allocated) call mpistop("multigrid tree not allocated yet")
563 lambda = 1.d0/(dtfactor * dt_diff)
564 call ahelmholtz_set_lambda(lambda)
565 call update_diffcoeff(psb)
566 fac = 1.d0
567 facd = 1.d0
568 !This is mg_copy_to_tree from psb state
569 {^ifoned
570 call mg_copy_to_tree(i_diff_mg(1), mg_iveps, factor=facd, state_from=psb)
571 if (time_advance)then
572 call mg_restrict(mg, mg_iveps)
573 call mg_fill_ghost_cells(mg, mg_iveps)
574 endif
575 }
576 {^iftwod
577 call mg_copy_to_tree(i_diff_mg(1), mg_iveps1, factor=facd, state_from=psb)
578 call mg_copy_to_tree(i_diff_mg(2), mg_iveps2, factor=facd, state_from=psb)
579 if (time_advance)then
580 call mg_restrict(mg, mg_iveps1)
581 call mg_fill_ghost_cells(mg, mg_iveps1)
582
583 call mg_restrict(mg, mg_iveps2)
584 call mg_fill_ghost_cells(mg, mg_iveps2)
585 endif
586 }
587 !This is mg_copy_to_tree from psb state
588 call mg_copy_to_tree(iw_r_e, mg_iphi, factor=fac, state_from=psb)
589 !>replace call set_rhs(mg, -1/dt, 0.0_dp)
590 call mg_copy_to_tree(iw_r_e, mg_irhs, factor=-1/(dtfactor*dt_diff), state_from=psb)
591 call phys_set_mg_bounds()
592 call mg_fas_fmg(mg, .true., max_res=res)
593 do n = 1, max_its
594 ! print*, n, res
595 if (res < max_residual) exit
596 call mg_fas_vcycle(mg, max_res=res)
597 end do
598 if (res .le. 0.d0) then
599 if (diffcrash_resume) then
600 if (mg%my_rank == 0) &
601 write(*,*) it, ' residual zero ', res
602 return
603 endif
604 if (mg%my_rank == 0) then
605 print*, res
606 error stop "Diffusion residual to zero"
607 endif
608 endif
609 if(n == max_its + 1) then
610 if(diffcrash_resume) then
611 if(mg%my_rank == 0) &
612 write(*,*) it, ' residual high ', res
613 return
614 endif
615 if(mg%my_rank == 0) then
616 print *, "Did you specify boundary conditions correctly?"
617 print *, "Or is the variation in diffusion too large?"
618 print*, n, res
619 print *, mg%bc(1, mg_iphi)%bc_value, mg%bc(2, mg_iphi)%bc_value
620 end if
621 error stop "diffusion_solve: no convergence"
622 end if
623 !> Reset dt_diff when diffusion worked out
624 dt_diff = 0.d0
625 ! !This is mg_copy_from_tree_gc for psa state
626 call mg_copy_from_tree_gc(mg_iphi, iw_r_e, state_to=psa)
627 end subroutine diffuse_e_rad_mg
628
629 !> inplace update of psa==>F_im(psa)
630 subroutine evaluate_e_rad_mg(qtC,psa)
633 type(state), target :: psa(max_blocks)
634 double precision, intent(in) :: qtC
635 integer :: iigrid, igrid, level
636 integer :: ixO^L
637
638 call update_diffcoeff(psa)
639 ixo^l=ixg^ll^lsub1;
640 !$OMP PARALLEL DO PRIVATE(igrid)
641 do iigrid=1,igridstail; igrid=igrids(iigrid);
642 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
643 ! call afld_get_diffcoef_central(psa(igrid)%w, psa(igrid)%w, psa(igrid)%x, ixG^LL, ixO^L)
644 call put_diffterm_onegrid(ixg^ll,ixo^l,psa(igrid)%w)
645 end do
646 !$OMP END PARALLEL DO
647 ! enforce boundary conditions for psa
648 call getbc(qtc,0.d0,psa,1,nwflux+nwaux)
649 end subroutine evaluate_e_rad_mg
650
651 !> inplace update of psa==>F_im(psa)
652 subroutine put_diffterm_onegrid(ixI^L,ixO^L,w)
654 integer, intent(in) :: ixI^L, ixO^L
655 double precision, intent(inout) :: w(ixI^S, 1:nw)
656 double precision :: gradE(ixO^S),divF(ixO^S)
657 double precision :: divF_h(ixO^S),divF_j(ixO^S)
658 double precision :: diff_term(ixO^S)
659 integer :: idir, jxO^L, hxO^L
660
661 divf(ixo^s) = 0.d0
662 do idir = 1,ndim
663 hxo^l=ixo^l-kr(idir,^d);
664 jxo^l=ixo^l+kr(idir,^d);
665 divf_h(ixo^s) = w(ixo^s,i_diff_mg(idir))*w(hxo^s,i_diff_mg(idir))/(w(ixo^s,i_diff_mg(idir)) + w(hxo^s,i_diff_mg(idir)))*(w(hxo^s,iw_r_e) - w(ixo^s,iw_r_e))
666 divf_j(ixo^s) = w(ixo^s,i_diff_mg(idir))*w(jxo^s,i_diff_mg(idir))/(w(ixo^s,i_diff_mg(idir)) + w(jxo^s,i_diff_mg(idir)))*(w(jxo^s,iw_r_e) - w(ixo^s,iw_r_e))
667 divf(ixo^s) = divf(ixo^s) + 2.d0*(divf_h(ixo^s) + divf_j(ixo^s))/dxlevel(idir)**2
668 enddo
669 w(ixo^s,iw_r_e) = divf(ixo^s)
670 end subroutine put_diffterm_onegrid
671
672 !> Calculates cell-centered diffusion coefficient to be used in multigrid
673 subroutine afld_get_diffcoef_central(w, wCT, x, ixI^L, ixO^L)
675 use mod_geometry
677 integer, intent(in) :: ixI^L, ixO^L
678 double precision, intent(inout) :: w(ixI^S, 1:nw)
679 double precision, intent(in) :: wCT(ixI^S, 1:nw)
680 double precision, intent(in) :: x(ixI^S, 1:ndim)
681 double precision :: kappa(ixO^S,1:ndim), lambda(ixO^S,1:ndim), fld_R(ixO^S,1:ndim)
682 double precision :: max_D(ixI^S), grad_r_e(ixI^S), rad_e(ixI^S)
683 double precision :: cc
684 integer :: idir,i,j,ix^D
685
686 cc = const_c/unit_velocity
687 if(fld_diff_testcase) then
688 w(ixo^s,i_diff_mg(:)) = 1.d0
689 else
690 call afld_get_opacity(wct, x, ixi^l, ixo^l, kappa)
691 call afld_get_fluxlimiter(wct, x, ixi^l, ixo^l, lambda, fld_r, nghostcells-1)
692 do idir = 1,ndim
693 !> calculate diffusion coefficient
694 w(ixo^s,i_diff_mg(idir)) = cc*lambda(ixo^s,idir)/(kappa(ixo^s,idir)*wct(ixo^s,iw_rho))
695 where(w(ixo^s,i_diff_mg(idir)) .lt. 0.d0)
696 w(ixo^s,i_diff_mg(idir)) = smalldouble
697 end where
698 if(diff_coef_filter) then
699 call afld_smooth_diffcoef(w,ixi^l,ixo^l,idir)
700 endif
701 enddo
702 endif
703 if(associated(usr_special_diffcoef)) &
704 call usr_special_diffcoef(w, wct, x, ixi^l, ixo^l)
705 end subroutine afld_get_diffcoef_central
706
707 subroutine update_diffcoeff(psa)
709 type(state), target :: psa(max_blocks)
710 integer :: iigrid, igrid, level
711 integer :: ixO^L
712
713 ixo^l=ixg^ll^lsub1;
714 !$OMP PARALLEL DO PRIVATE(igrid)
715 do iigrid=1,igridstail; igrid=igrids(iigrid);
716 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
717 call afld_get_diffcoef_central(psa(igrid)%w, psa(igrid)%w, psa(igrid)%x, ixg^ll, ixo^l)
718 end do
719 !$OMP END PARALLEL DO
720 end subroutine update_diffcoeff
721
722 !> Use running average on Diffusion coefficient
723 subroutine afld_smooth_diffcoef(w, ixI^L, ixO^L,idir)
725 integer, intent(in) :: ixI^L, ixO^L, idir
726 double precision, intent(inout) :: w(ixI^S, 1:nw)
727 double precision :: tmp_D(ixI^S), filtered_D(ixI^S)
728 integer :: ix^D, filter, idim
729
730 if(size_d_filter .lt. 1) call mpistop("D filter of size < 1 makes no sense")
731 if(size_d_filter .gt. nghostcells) call mpistop("D filter of size > nghostcells makes no sense")
732 tmp_d(ixo^s) = w(ixo^s,i_diff_mg(idir))
733 filtered_d(ixo^s) = zero
734 do filter = 1,size_d_filter
735 {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
736 do idim = 1,ndim
737 filtered_d(ix^d) = filtered_d(ix^d) &
738 + tmp_d(ix^d+filter*kr(idim,^d)) &
739 + tmp_d(ix^d-filter*kr(idim,^d))
740 enddo
741 {enddo\}
742 enddo
743 {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
744 tmp_d(ix^d) = (tmp_d(ix^d)+filtered_d(ix^d))/(1+2*size_d_filter*ndim)
745 {enddo\}
746 w(ixo^s,i_diff_mg(idir)) = tmp_d(ixo^s)
747 end subroutine afld_smooth_diffcoef
748
749 !> This subroutine calculates the radiation heating, radiation cooling
750 !> and photon tiring using an implicit scheme.
751 !> These sourceterms are applied using the root-finding of a 4th order polynomial
752 !> This routine loops over every cell in the domain
753 !> and computes the coefficients of the polynomials in every cell
754 subroutine energy_interaction(w, wCT, x, ixI^L, ixO^L)
756 use mod_geometry
757 use mod_physics
759 integer, intent(in) :: ixI^L, ixO^L
760 double precision, intent(in) :: x(ixI^S,1:ndim)
761 double precision, intent(in) :: wCT(ixI^S,1:nw)
762 double precision, intent(inout) :: w(ixI^S,1:nw)
763 double precision :: a1(ixO^S), a2(ixO^S)
764 double precision :: c0(ixO^S), c1(ixO^S)
765 double precision :: e_gas(ixO^S), E_rad(ixO^S)
766 double precision :: kappa(ixO^S)
767 double precision :: sigma_b,cc
768 integer :: i,j,ix^D
769
770 cc = const_c/unit_velocity
771 sigma_b = const_rad_a*cc/4.d0*(unit_temperature**4.d0)/(unit_pressure)
772 !> e_gas is the INTERNAL ENERGY without KINETIC ENERGY
773 e_gas(ixo^s) = wct(ixo^s,iw_e)-half*sum(wct(ixo^s, iw_mom(:))**2, dim=ndim+1)/wct(ixo^s, iw_rho)
774 if(allocated(iw_mag)) then
775 e_gas(ixo^s) = e_gas(ixo^s)-half*sum(wct(ixo^s,iw_mag(:))**2,dim=ndim+1)
776 endif
777 {do ix^d=ixomin^d,ixomax^d\ }
778 e_gas(ix^d) = max(e_gas(ix^d),small_pressure/(afld_gamma-1.d0))
779 {enddo\}
780 e_rad(ixo^s) = wct(ixo^s,iw_r_e)
781 if(associated(usr_special_opacity_qdot)) then
782 call usr_special_opacity_qdot(ixi^l,ixo^l,w,x,kappa)
783 else
784 call afld_get_opacity(wct,x,ixi^l,ixo^l,kappa)
785 endif
786 if(fld_interaction_method .eq. 'Instant') then
787 a1(ixo^s) = 4.d0*sigma_b/cc*(afld_gamma-one)**4.d0/wct(ixo^s,iw_rho)**4.d0
788 a2(ixo^s) = e_gas(ixo^s) + e_rad(ixo^s)
789 c0(ixo^s) = a2(ixo^s)/a1(ixo^s)
790 c1(ixo^s) = 1.d0/a1(ixo^s)
791 else
792 !> Calculate coefficients for polynomial
793 a1(ixo^s) = 4.d0*kappa(ixo^s)*sigma_b*(afld_gamma-one)**4.d0/wct(ixo^s,iw_rho)**3.d0*dt
794 a2(ixo^s) = (const_c/unit_velocity)*kappa(ixo^s)*wct(ixo^s,iw_rho)*dt
795 c0(ixo^s) = ((one+a2(ixo^s))*e_gas(ixo^s)+a2(ixo^s)*e_rad(ixo^s))/a1(ixo^s)
796 c1(ixo^s) = (one+a2(ixo^s))/a1(ixo^s)
797 endif
798 !> Loop over every cell for rootfinding method
799 {do ix^d=ixomin^d,ixomax^d\ }
800 select case(fld_interaction_method)
801 case('Bisect')
802 call bisection_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
803 case('Newton')
804 call newton_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
805 case('Halley')
806 call halley_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
807 case('Instant')
808 call halley_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
809 case default
810 call mpistop('root-method not known')
811 end select
812 {enddo\}
813
814 if(fld_interaction_method .eq. 'Instant') then
815 e_rad(ixo^s) = a2(ixo^s)-e_gas(ixo^s)
816 else
817 !> advance E_rad
818 e_rad(ixo^s) = (a1(ixo^s)*e_gas(ixo^s)**4.d0+e_rad(ixo^s))/(one + a2(ixo^s))
819 endif
820 !> Update gas-energy in w, internal + kinetic
821 w(ixo^s,iw_e) = e_gas(ixo^s)
822 !> Beginning of module substracted wCT Ekin
823 !> So now add wCT Ekin
824 w(ixo^s,iw_e) = w(ixo^s,iw_e) + half*sum(wct(ixo^s, iw_mom(:))**2,dim=ndim+1)/wct(ixo^s, iw_rho)
825 if(allocated(iw_mag)) then
826 w(ixo^s,iw_e) = w(ixo^s,iw_e)+half*sum(wct(ixo^s, iw_mag(:))**2,dim=ndim+1)
827 endif
828 !> Update rad-energy in w
829 w(ixo^s,iw_r_e) = e_rad(ixo^s)
830 end subroutine energy_interaction
831
832 !> Find the root of the 4th degree polynomial using the bisection method
833 subroutine bisection_method(e_gas, E_rad, c0, c1)
835 double precision, intent(in) :: c0, c1
836 double precision, intent(in) :: E_rad
837 double precision, intent(inout) :: e_gas
838 double precision :: bisect_a, bisect_b, bisect_c
839 integer :: n, max_its
840
841 n = 0
842 max_its = 10000000
843 bisect_a = zero
844 bisect_b = 1.2d0*max(abs(c0/c1),abs(c0)**(1.d0/4.d0))
845 do while(abs(bisect_b-bisect_a) .ge. fld_bisect_tol*min(e_gas,e_rad))
846 bisect_c = (bisect_a + bisect_b)/two
847 n = n +1
848 if(n .gt. max_its) then
849 goto 2435
850 call mpistop('No convergece in bisection scheme')
851 endif
852 if(polynomial_bisection(bisect_a, c0, c1)*&
853 polynomial_bisection(bisect_b, c0, c1) .lt. zero) then
854 if(polynomial_bisection(bisect_a, c0, c1)*&
855 polynomial_bisection(bisect_c, c0, c1) .lt. zero) then
856 bisect_b = bisect_c
857 elseif(polynomial_bisection(bisect_b, c0, c1)*&
858 polynomial_bisection(bisect_c, c0, c1) .lt. zero) then
859 bisect_a = bisect_c
860 elseif(polynomial_bisection(bisect_a, c0, c1) .eq. zero) then
861 bisect_b = bisect_a
862 bisect_c = bisect_a
863 goto 2435
864 elseif(polynomial_bisection(bisect_b, c0, c1) .eq. zero) then
865 bisect_a = bisect_b
866 bisect_c = bisect_b
867 goto 2435
868 elseif(polynomial_bisection(bisect_c, c0, c1) .eq. zero) then
869 bisect_a = bisect_c
870 bisect_b = bisect_c
871 goto 2435
872 else
873 call mpistop("Problem with fld bisection method")
874 endif
875 elseif(polynomial_bisection(bisect_a, c0, c1) &
876 - polynomial_bisection(bisect_b, c0, c1) .lt. fld_bisect_tol*polynomial_bisection(bisect_a, c0, c1)) then
877 goto 2435
878 else
879 bisect_a = e_gas
880 bisect_b = e_gas
881 print*, "IGNORING GAS-RAD ENERGY EXCHANGE ", c0, c1
882 print*, polynomial_bisection(bisect_a, c0, c1), polynomial_bisection(bisect_b, c0, c1)
883 if(polynomial_bisection(bisect_a, c0, c1) .le. smalldouble) then
884 bisect_b = bisect_a
885 elseif(polynomial_bisection(bisect_a, c0, c1) .le. smalldouble) then
886 bisect_a = bisect_b
887 endif
888 goto 2435
889 endif
890 enddo
891 2435 e_gas = (bisect_a + bisect_b)/two
892 end subroutine bisection_method
893
894 !> Find the root of the 4th degree polynomial using the Newton-Ralphson method
895 subroutine newton_method(e_gas, E_rad, c0, c1)
897 double precision, intent(in) :: c0, c1
898 double precision, intent(in) :: E_rad
899 double precision, intent(inout) :: e_gas
900 double precision :: xval, yval, der, deltax
901 integer :: ii
902
903 yval = bigdouble
904 xval = e_gas
905 der = one
906 deltax = one
907 ii = 0
908 !> Compare error with dx = dx/dy dy
909 do while (abs(deltax) .gt. fld_bisect_tol)
910 yval = polynomial_bisection(xval, c0, c1)
911 der = dpolynomial_bisection(xval, c0, c1)
912 deltax = -yval/der
913 xval = xval + deltax
914 ii = ii + 1
915 if (ii .gt. 1d3) then
916 call bisection_method(e_gas, e_rad, c0, c1)
917 return
918 endif
919 enddo
920 e_gas = xval
921 end subroutine newton_method
922
923 !> Find the root of the 4th degree polynomial using the Halley method
924 subroutine halley_method(e_gas, E_rad, c0, c1)
926 double precision, intent(in) :: c0, c1
927 double precision, intent(in) :: E_rad
928 double precision, intent(inout) :: e_gas
929 double precision :: xval, yval, der, dder, deltax
930 integer :: ii
931
932 yval = bigdouble
933 xval = e_gas
934 der = one
935 dder = one
936 deltax = one
937 ii = 0
938 !> Compare error with dx = dx/dy dy
939 do while (abs(deltax) .gt. fld_bisect_tol)
940 yval = polynomial_bisection(xval, c0, c1)
941 der = dpolynomial_bisection(xval, c0, c1)
942 dder = ddpolynomial_bisection(xval, c0, c1)
943 deltax = -two*yval*der/(two*der**2 - yval*dder)
944 xval = xval + deltax
945 ii = ii + 1
946 if (ii .gt. 1d3) then
947 call newton_method(e_gas, e_rad, c0, c1)
948 return
949 endif
950 enddo
951 e_gas = xval
952 end subroutine halley_method
953
954 !> Evaluate polynomial at argument e_gas
955 function polynomial_bisection(e_gas, c0, c1) result(val)
957 double precision, intent(in) :: e_gas
958 double precision, intent(in) :: c0, c1
959 double precision :: val
960
961 val = e_gas**4.d0 + c1*e_gas - c0
962 end function polynomial_bisection
963
964 !> Evaluate first derivative of polynomial at argument e_gas
965 function dpolynomial_bisection(e_gas, c0, c1) result(der)
967 double precision, intent(in) :: e_gas
968 double precision, intent(in) :: c0, c1
969 double precision :: der
970
971 der = 4.d0*e_gas**3.d0 + c1
972 end function dpolynomial_bisection
973
974 !> Evaluate second derivative of polynomial at argument e_gas
975 function ddpolynomial_bisection(e_gas, c0, c1) result(dder)
977 double precision, intent(in) :: e_gas
978 double precision, intent(in) :: c0, c1
979 double precision :: dder
980
981 dder = 4.d0*3.d0*e_gas**2.d0
982 end function ddpolynomial_bisection
983end module mod_afld
Module for including anisotropic flux limited diffusion (AFLD)-approximation in Radiation-hydrodynami...
Definition mod_afld.t:8
logical lineforce_opacities
Use or dont use lineforce opacities.
Definition mod_afld.t:44
subroutine afld_smooth_diffcoef(w, ixil, ixol, idir)
Use running average on Diffusion coefficient.
Definition mod_afld.t:724
character(len=8) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
Definition mod_afld.t:34
logical fld_eint_split
source split for energy interact and radforce:
Definition mod_afld.t:13
subroutine afld_get_diffcoef_central(w, wct, x, ixil, ixol)
Calculates cell-centered diffusion coefficient to be used in multigrid.
Definition mod_afld.t:674
logical flux_lim_filter
Take a running average over the fluxlimiter.
Definition mod_afld.t:41
subroutine, public afld_get_radflux(w, x, ixil, ixol, rad_flux, nth)
Calculate Radiation Flux Calculate the Flux using the fld closure relation F = -c*lambda/(kappa*rho) ...
Definition mod_afld.t:430
double precision, public fld_bisect_tol
Tolerance for bisection method for Energy sourceterms This is a percentage of the minimum of gas- and...
Definition mod_afld.t:21
subroutine, public get_afld_rad_force(qdt, ixil, ixol, wct, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
Definition mod_afld.t:130
double precision, public fld_kappa0
Opacity per unit of unit_density.
Definition mod_afld.t:16
subroutine, public afld_get_fluxlimiter(w, x, ixil, ixol, fld_lambda, fld_r, nth)
Calculate fld flux limiter This subroutine calculates flux limiter lambda using the prescription stor...
Definition mod_afld.t:327
double precision, public fld_diff_tol
Tolerance for adi method for radiative Energy diffusion.
Definition mod_afld.t:23
character(len=16) fld_fluxlimiter
Diffusion limit lambda = 0.33.
Definition mod_afld.t:30
subroutine diffuse_e_rad_mg(dtfactor, qdt, qtc, psa, psb)
Calling all subroutines to perform the multigrid method Communicates rad_e and diff_coeff to multigri...
Definition mod_afld.t:527
double precision function ddpolynomial_bisection(e_gas, c0, c1)
Evaluate second derivative of polynomial at argument e_gas.
Definition mod_afld.t:976
subroutine bisection_method(e_gas, e_rad, c0, c1)
Find the root of the 4th degree polynomial using the bisection method.
Definition mod_afld.t:834
logical fld_diff_testcase
Set Diffusion coefficient to unity.
Definition mod_afld.t:36
logical diffcrash_resume
Resume run when multigrid returns error.
Definition mod_afld.t:46
double precision function dpolynomial_bisection(e_gas, c0, c1)
Evaluate first derivative of polynomial at argument e_gas.
Definition mod_afld.t:966
character(len=8), dimension(:), allocatable fld_opacity_law
Use constant Opacity?
Definition mod_afld.t:27
subroutine, public afld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x)
Definition mod_afld.t:206
subroutine evaluate_e_rad_mg(qtc, psa)
inplace update of psa==>F_im(psa)
Definition mod_afld.t:631
subroutine energy_interaction(w, wct, x, ixil, ixol)
This subroutine calculates the radiation heating, radiation cooling and photon tiring using an implic...
Definition mod_afld.t:755
subroutine, public afld_get_radpress(w, x, ixil, ixol, rad_pressure, nth)
Calculate Radiation Pressure Returns Radiation Pressure as tensor.
Definition mod_afld.t:508
subroutine update_diffcoeff(psa)
Definition mod_afld.t:708
subroutine halley_method(e_gas, e_rad, c0, c1)
Find the root of the 4th degree polynomial using the Halley method.
Definition mod_afld.t:925
double precision function polynomial_bisection(e_gas, c0, c1)
Evaluate polynomial at argument e_gas.
Definition mod_afld.t:956
subroutine, public afld_init(he_abundance, afld_gamma)
Initialising FLD-module: Read opacities Initialise Multigrid adimensionalise kappa Add extra variable...
Definition mod_afld.t:91
subroutine newton_method(e_gas, e_rad, c0, c1)
Find the root of the 4th degree polynomial using the Newton-Ralphson method.
Definition mod_afld.t:896
character(len=50) fld_opal_table
Definition mod_afld.t:28
subroutine, public get_afld_energy_interact(qdt, ixil, ixol, wct, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
Definition mod_afld.t:233
double precision, public diff_crit
Number for splitting the diffusion module.
Definition mod_afld.t:25
logical fld_radforce_split
Definition mod_afld.t:14
integer size_d_filter
Definition mod_afld.t:39
subroutine, public afld_get_opacity(w, x, ixil, ixol, fld_kappa)
Sets the opacity in the w-array by calling mod_opal_opacity.
Definition mod_afld.t:255
logical diff_coef_filter
Take running average for Diffusion coefficient.
Definition mod_afld.t:38
double precision, public afld_mu
mean particle mass
Definition mod_afld.t:18
integer, dimension(:), allocatable i_diff_mg
Definition mod_afld.t:32
integer size_l_filter
Definition mod_afld.t:42
subroutine put_diffterm_onegrid(ixil, ixol, w)
inplace update of psa==>F_im(psa)
Definition mod_afld.t:653
subroutine afld_params_read(files)
public methods these are called in mod_rhd_phys
Definition mod_afld.t:65
double precision dt_diff
running timestep for diffusion solver, initialised as zero
Definition mod_afld.t:50
subroutine afld_get_eddington(w, x, ixil, ixol, eddington_tensor, nth)
Calculate Eddington-tensor Stores Eddington-tensor in w-array.
Definition mod_afld.t:455
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
Module with basic grid data structures.
Definition mod_forest.t:2
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
update ghost cells of all blocks including physical boundaries
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
This module contains definitions of global parameters and variables and some generic functions/subrou...
double precision unit_density
Physical scaling factor for density.
double precision unit_opacity
Physical scaling factor for Opacity.
integer, parameter unitpar
file handle for IO
double precision global_time
The global simulation time.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer it
Number of time steps taken.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
double precision dt
global time step
double precision courantpar
The Courant (CFL) number used for the simulation.
double precision unit_velocity
Physical scaling factor for velocity.
logical time_advance
do time evolving
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical use_multigrid
Use multigrid (only available in 2D and 3D)
double precision dtmin
Stop the simulation when the time step becomes smaller than this value.
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
subroutine mg_copy_to_tree(iw_from, iw_to, restrict, restrict_gc, factor, state_from)
Copy a variable to the multigrid tree, including a layer of ghost cells.
subroutine mg_copy_from_tree_gc(iw_from, iw_to, state_to)
Copy from multigrid tree with one layer of ghost cells. Corner ghost cells are not used/set.
This module reads in Rosseland-mean opacities from OPAL tables. Table opacity values are given in bas...
subroutine, public init_opal_table(tabledir, set_custom_tabledir)
This subroutine is called when the FLD radiation module is initialised. The OPAL tables for different...
subroutine, public set_opal_opacity(rho, temp, kappa)
This subroutine calculates the opacity for a given temperature-density structure. Opacities are read ...
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_get_tgas), pointer phys_get_tgas
Definition mod_physics.t:71
procedure(sub_evaluate_implicit), pointer phys_evaluate_implicit
Definition mod_physics.t:79
procedure(sub_get_pthermal), pointer phys_get_pthermal
Definition mod_physics.t:70
procedure(sub_set_mg_bounds), pointer phys_set_mg_bounds
Definition mod_physics.t:52
procedure(sub_implicit_update), pointer phys_implicit_update
Definition mod_physics.t:78
Module with all the methods that users can customize in AMRVAC.
procedure(special_diffcoef), pointer usr_special_diffcoef
procedure(special_fluxlimiter), pointer usr_special_fluxlimiter
procedure(special_opacity_qdot), pointer usr_special_opacity_qdot
procedure(special_aniso_opacity), pointer usr_special_aniso_opacity
integer function var_set_extravar(name_cons, name_prim, ix)
Set extra variable in w, which is not advected and has no boundary conditions. This has to be done af...
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:11