MPI-AMRVAC  3.0
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
mod_fld.t
Go to the documentation of this file.
1 !> Nicolas Moens
2 !> Module for including flux limited diffusion (FLD)-approximation in Radiation-hydrodynamics simulations using mod_rhd
3 !> Based on Turner and stone 2001. See
4 !> [1]Moens, N., Sundqvist, J. O., El Mellah, I., Poniatowski, L., Teunissen, J., and Keppens, R.,
5 !> “Radiation-hydrodynamics with MPI-AMRVAC . Flux-limited diffusion”,
6 !> <i>Astronomy and Astrophysics</i>, vol. 657, 2022. doi:10.1051/0004-6361/202141023.
7 !> For more information.
8 
9 module mod_fld
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 
16  !> Opacity per unit of unit_density
17  double precision, public :: fld_kappa0 = 0.34d0
18 
19  !> mean particle mass
20  double precision, public :: fld_mu = 0.6d0
21 
22  !> Tolerance for bisection method for Energy sourceterms
23  !> This is a percentage of the minimum of gas- and radiation energy
24  double precision, public :: fld_bisect_tol = 1.d-4
25 
26  !> Tolerance for adi method for radiative Energy diffusion
27  double precision, public :: fld_diff_tol = 1.d-4
28 
29  !> Number for splitting the diffusion module
30  double precision, public :: diff_crit
31 
32  !> Use constant Opacity?
33  character(len=8) :: fld_opacity_law = 'const'
34  character(len=6) :: fld_opal_table = 'Y09800' !>'xxxxxx'
35 
36  !> Diffusion limit lambda = 0.33
37  character(len=16) :: fld_fluxlimiter = 'Pomraning'
38 
39  !> diffusion coefficient for multigrid method
40  integer :: i_diff_mg
41 
42  !> Which method to solve diffusion part
43  character(len=8) :: fld_diff_scheme = 'mg'
44 
45  !> Which method to find the root for the energy interaction polynomial
46  character(len=8) :: fld_interaction_method = 'Halley'
47 
48  !> Take running average for Diffusion coefficient
49  logical :: diff_coef_filter = .false.
50  integer :: size_d_filter = 1
51 
52  !> Take a running average over the fluxlimiter
53  logical :: flux_lim_filter = .false.
54  integer :: size_l_filter = 1
55 
56  !> Use or dont use lineforce opacities
57  logical :: lineforce_opacities = .false.
58 
59  !> Resume run when multigrid returns error
60  logical :: diffcrash_resume = .true.
61 
62  !> Index for Flux weighted opacities
63  integer, allocatable, public :: i_opf(:)
64 
65  !> A copy of rhd_Gamma
66  double precision, private, protected :: fld_gamma
67 
68  !> running timestep for diffusion solver, initialised as zero
69  double precision :: dt_diff = 0.d0
70 
71  !> public methods
72  !> these are called in mod_rhd_phys
73  public :: get_fld_rad_force
74  public :: get_fld_energy_interact
75  public :: fld_radforce_get_dt
76  public :: fld_init
77  public :: fld_get_radflux
78  public :: fld_get_radpress
79  public :: fld_get_fluxlimiter
80  public :: fld_get_opacity
81 
82  contains
83 
84 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
85 !!!!!!!!!!!!!!!!!!! GENERAL
86 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
87 
88  !> Reading in fld-list parameters from .par file
89  subroutine fld_params_read(files)
91  use mod_constants
92  character(len=*), intent(in) :: files(:)
93  integer :: n
94 
95  namelist /fld_list/ fld_kappa0, fld_eint_split, fld_radforce_split, &
100 
101  do n = 1, size(files)
102  open(unitpar, file=trim(files(n)), status="old")
103  read(unitpar, fld_list, end=111)
104  111 close(unitpar)
105  end do
106 
107  end subroutine fld_params_read
108 
109  !> Initialising FLD-module:
110  !> Read opacities
111  !> Initialise Multigrid
112  !> adimensionalise kappa
113  !> Add extra variables to w-array, flux, kappa, eddington Tensor
114  !> Lambda and R
115  !> ...
116  subroutine fld_init(He_abundance, rhd_radiation_diffusion, rhd_gamma)
118  use mod_variables
119  use mod_physics
120  use mod_opal_opacity, only: init_opal
122 
123  double precision, intent(in) :: he_abundance, rhd_gamma
124  logical, intent(in) :: rhd_radiation_diffusion
125  double precision :: sigma_thomson
126  integer :: idir,jdir
127 
128  character(len=1) :: ind_1
129  character(len=1) :: ind_2
130  character(len=2) :: cmp_f
131  character(len=5) :: cmp_e
132 
133  !> read par files
135 
136  !> Set lineforce opacities as variable
137  if (lineforce_opacities) then
138  allocate(i_opf(ndim))
139  do idir = 1,ndim
140  write(ind_1,'(I1)') idir
141  cmp_f = 'k' // ind_1
142  i_opf(idir) = var_set_extravar(cmp_f,cmp_f)
143  enddo
144  endif
145 
146  if (rhd_radiation_diffusion) then
147  if (fld_diff_scheme .eq. 'mg') then
148 
149  use_multigrid = .true.
150 
153 
154  mg%n_extra_vars = 1
155  mg%operator_type = mg_vhelmholtz
156 
157  endif
158  endif
159 
160  i_diff_mg = var_set_extravar("D", "D")
161 
162  !> Need mean molecular weight
163  fld_mu = (1.+4*he_abundance)/(2.+3.*he_abundance)
164 
165  !> set rhd_gamma
166  fld_gamma = rhd_gamma
167 
168  !> Read in opacity table if necesary
169  if (fld_opacity_law .eq. 'opal') call init_opal(he_abundance,fld_opal_table)
170  if ((fld_opacity_law .eq. 'thomson') .or. (fld_opacity_law .eq. 'fastwind')) then
171  sigma_thomson = 6.6524585d-25
172  fld_kappa0 = sigma_thomson/const_mp * (1.+2.*he_abundance)/(1.+4.*he_abundance)
173  endif
174  end subroutine fld_init
175 
176  !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
177  !> This subroutine handles the radiation force
178  subroutine get_fld_rad_force(qdt,ixI^L,ixO^L,wCT,w,x,&
179  energy,qsourcesplit,active)
180  use mod_constants
182  use mod_usr_methods
183  use mod_geometry
184 
185  integer, intent(in) :: ixi^l, ixo^l
186  double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
187  double precision, intent(in) :: wct(ixi^s,1:nw)
188  double precision, intent(inout) :: w(ixi^s,1:nw)
189  logical, intent(in) :: energy,qsourcesplit
190  logical, intent(inout) :: active
191 
192  double precision :: radiation_forcect(ixo^s,1:ndim)
193  double precision :: kappact(ixo^s)
194  double precision :: rad_fluxct(ixo^s,1:ndim)
195 
196  double precision :: div_v(ixi^s,1:ndim,1:ndim)
197  double precision :: edd(ixo^s,1:ndim,1:ndim)
198  double precision :: nabla_vp(ixo^s)
199  double precision :: vel(ixi^s), grad_v(ixi^s), grad0_v(ixo^s)
200  double precision :: grad_e(ixo^s)
201 
202  integer :: idir, jdir
203 
204  double precision :: fld_r(ixo^s), lambda(ixo^s)
205 
206  !> Calculate and add sourceterms
207  if(qsourcesplit .eqv. fld_radforce_split) then
208  active = .true.
209 
210  call fld_get_opacity(wct, x, ixi^l, ixo^l, kappact)
211  call fld_get_radflux(wct, x, ixi^l, ixo^l, rad_fluxct)
212  call fld_get_fluxlimiter(wct, x, ixi^l, ixo^l, lambda, fld_r)
213 
214  do idir = 1,ndim
215  !> Radiation force = kappa*rho/c *Flux = lambda gradE
216  radiation_forcect(ixo^s,idir) = kappact(ixo^s)*rad_fluxct(ixo^s,idir)/(const_c/unit_velocity)
217 
218  ! call gradientO(wCT(ixI^S,iw_r_e),x,ixI^L,ixO^L,idir,grad_E,nghostcells)
219  ! radiation_forceCT(ixO^S,idir) = lambda(ixO^S)*grad_E(ixO^S)
220 
221  !> Momentum equation source term
222  w(ixo^s,iw_mom(idir)) = w(ixo^s,iw_mom(idir)) &
223  + qdt * wct(ixo^s,iw_rho)*radiation_forcect(ixo^s,idir)
224  ! w(ixO^S,iw_mom(idir)) = w(ixO^S,iw_mom(idir)) &
225  ! + qdt *radiation_forceCT(ixO^S,idir)
226 
227  ! if (energy .and. .not. block%e_is_internal) then
228  !> Energy equation source term (kinetic energy)
229  w(ixo^s,iw_e) = w(ixo^s,iw_e) &
230  + qdt * wct(ixo^s,iw_mom(idir))*radiation_forcect(ixo^s,idir)
231  ! w(ixO^S,iw_e) = w(ixO^S,iw_e) &
232  ! + qdt * wCT(ixO^S,iw_mom(idir))/wCT(ixO^S,iw_rho)*radiation_forceCT(ixO^S,idir)
233  ! endif
234  enddo
235 
236  !> Photon tiring
237  !> calculate tensor div_v
238  !> !$OMP PARALLEL DO
239  do idir = 1,ndim
240  do jdir = 1,ndim
241  vel(ixi^s) = wct(ixi^s,iw_mom(jdir))/wct(ixi^s,iw_rho)
242 
243  call gradient(vel,ixi^l,ixo^l,idir,grad_v)
244  div_v(ixo^s,idir,jdir) = grad_v(ixo^s)
245 
246  ! call gradientO(vel,x,ixI^L,ixO^L,idir,grad0_v,nghostcells)
247  ! div_v(ixO^S,idir,jdir) = grad0_v(ixO^S)
248  enddo
249  enddo
250  !> !$OMP END PARALLEL DO
251 
252  call fld_get_eddington(wct, x, ixi^l, ixo^l, edd)
253 
254  !> VARIABLE NAMES DIV ARE ACTUALLY GRADIENTS
255  {^ifoned
256  nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
257  }
258 
259  {^iftwod
260  !>eq 34 Turner and stone (Only 2D)
261  nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
262  + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
263  + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
264  + div_v(ixo^s,2,2)*edd(ixo^s,2,2)
265  }
266 
267  {^ifthreed
268  nabla_vp(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
269  + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
270  + div_v(ixo^s,1,3)*edd(ixo^s,1,3) &
271  + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
272  + div_v(ixo^s,2,2)*edd(ixo^s,2,2) &
273  + div_v(ixo^s,2,3)*edd(ixo^s,2,3) &
274  + div_v(ixo^s,3,1)*edd(ixo^s,3,1) &
275  + div_v(ixo^s,3,2)*edd(ixo^s,3,2) &
276  + div_v(ixo^s,3,3)*edd(ixo^s,3,3)
277  }
278 
279  w(ixo^s,iw_r_e) = w(ixo^s,iw_r_e) &
280  - qdt * nabla_vp(ixo^s)*wct(ixo^s,iw_r_e)
281 
282  end if
283 
284  end subroutine get_fld_rad_force
285 
286 
287  subroutine fld_radforce_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
289  use mod_usr_methods
290 
291  integer, intent(in) :: ixi^l, ixo^l
292  double precision, intent(in) :: dx^d, x(ixi^s,1:ndim), w(ixi^s,1:nw)
293  double precision, intent(inout) :: dtnew
294 
295  double precision :: radiation_force(ixo^s,1:ndim)
296  double precision :: rad_flux(ixo^s,1:ndim)
297  double precision :: kappa(ixo^s)
298  double precision :: dxinv(1:ndim), max_grad
299  integer :: idim
300 
301  ^d&dxinv(^d)=one/dx^d;
302 
303  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
304  call fld_get_radflux(w, x, ixi^l, ixo^l, rad_flux)
305 
306  do idim = 1, ndim
307  radiation_force(ixo^s,idim) = w(ixo^s,iw_rho)*kappa(ixo^s)*rad_flux(ixo^s,idim)/(const_c/unit_velocity)
308  max_grad = maxval(abs(radiation_force(ixo^s,idim)))
309  max_grad = max(max_grad, epsilon(1.0d0))
310  dtnew = min(dtnew, courantpar / sqrt(max_grad * dxinv(idim)))
311  end do
312 
313  end subroutine fld_radforce_get_dt
314 
315  !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
316  !> This subroutine handles the energy exchange between gas and radiation
317  subroutine get_fld_energy_interact(qdt,ixI^L,ixO^L,wCT,w,x,&
318  energy,qsourcesplit,active)
319  use mod_constants
321  use mod_usr_methods
322 
323  use mod_physics, only: phys_get_pthermal !needed to get temp
324 
325  integer, intent(in) :: ixi^l, ixo^l
326  double precision, intent(in) :: qdt, x(ixi^s,1:ndim)
327  double precision, intent(in) :: wct(ixi^s,1:nw)
328  double precision, intent(inout) :: w(ixi^s,1:nw)
329  logical, intent(in) :: energy,qsourcesplit
330  logical, intent(inout) :: active
331 
332  !> Calculate and add sourceterms
333  if(qsourcesplit .eqv. fld_eint_split) then
334  active = .true.
335  !> Add energy sourceterms
336  call energy_interaction(w, w, x, ixi^l, ixo^l)
337  end if
338  end subroutine get_fld_energy_interact
339 
340  !> Sets the opacity in the w-array
341  !> by calling mod_opal_opacity
342  subroutine fld_get_opacity(w, x, ixI^L, ixO^L, fld_kappa)
344  use mod_physics, only: phys_get_pthermal
345  use mod_physics, only: phys_get_tgas
346  use mod_usr_methods
347  use mod_opal_opacity
348 
349  integer, intent(in) :: ixi^l, ixo^l
350  double precision, intent(in) :: w(ixi^s, 1:nw)
351  double precision, intent(in) :: x(ixi^s, 1:ndim)
352  double precision, intent(out) :: fld_kappa(ixo^s)
353  double precision :: temp(ixi^s), pth(ixi^s), a2(ixo^s)
354  double precision :: rho0,temp0,n,sigma_b
355  double precision :: akram, bkram
356  double precision :: vth(ixo^s), gradv(ixi^s), eta(ixo^s), t(ixo^s)
357 
358  integer :: i,j,ix^d, idir
359 
360  select case (fld_opacity_law)
361  case('const')
362  fld_kappa(ixo^s) = fld_kappa0/unit_opacity
363  case('thomson')
364  fld_kappa(ixo^s) = fld_kappa0/unit_opacity
365  case('kramers')
366  rho0 = half !> Take lower value of rho in domain
367  fld_kappa(ixo^s) = fld_kappa0/unit_opacity*((w(ixo^s,iw_rho)/rho0))
368  case('bump')
369  !> Opacity bump
370  rho0 = 0.2d0 !0.5d-1
371  n = 7.d0
372  sigma_b = 2.d-2
373  !fld_kappa(ixO^S) = fld_kappa0/unit_opacity*(one + n*dexp(-((rho0 - w(ixO^S,iw_rho))**two)/rho0))
374  fld_kappa(ixo^s) = fld_kappa0/unit_opacity*(one + n*dexp(-one/sigma_b*(dlog(w(ixo^s,iw_rho)/rho0))**two))
375  case('non_iso')
376  call phys_get_pthermal(w,x,ixi^l,ixo^l,temp)
377  temp(ixo^s)=temp(ixo^s)/w(ixo^s,iw_rho)
378 
379  rho0 = 0.5d0 !> Take lower value of rho in domain
380  temp0 = one
381  n = -7.d0/two
382  fld_kappa(ixo^s) = fld_kappa0/unit_opacity*(w(ixo^s,iw_rho)/rho0)*(temp(ixo^s)/temp0)**n
383  case('fastwind')
384  call phys_get_pthermal(w,x,ixi^l,ixo^l,pth)
385  a2(ixo^s) = pth(ixo^s)/w(ixo^s,iw_rho)*unit_velocity**2.d0
386 
387  akram = 13.1351597305
388  bkram = -4.5182188206
389 
390  fld_kappa(ixo^s) = fld_kappa0/unit_opacity &
391  * (1.d0+10.d0**akram*w(ixo^s,iw_rho)*unit_density*(a2(ixo^s)/1.d12)**bkram)
392 
393  {do ix^d=ixomin^d,ixomax^d\ }
394  !> Hard limit on kappa
395  fld_kappa(ix^d) = min(fld_kappa(ix^d),2.3d0*fld_kappa0/unit_opacity)
396 
397  !> Limit kappa through T
398  ! fld_kappa(ix^D) = fld_kappa0/unit_opacity &
399  ! * (1.d0+10.d0**akram*w(ix^D,iw_rho)*unit_density &
400  ! * (max(a2(ix^D),const_kB*5.9d4/(fld_mu*const_mp))/1.d12)**bkram)
401  {enddo\ }
402 
403  case('opal')
404  call phys_get_tgas(w,x,ixi^l,ixo^l,temp)
405  {do ix^d=ixomin^d,ixomax^d\ }
406  rho0 = w(ix^d,iw_rho)*unit_density
407  temp0 = temp(ix^d)*unit_temperature
408  call set_opal_opacity(rho0,temp0,n)
409  fld_kappa(ix^d) = n/unit_opacity
410  {enddo\ }
411 
412  case('special')
413  if (.not. associated(usr_special_opacity)) then
414  call mpistop("special opacity not defined")
415  endif
416  call usr_special_opacity(ixi^l, ixo^l, w, x, fld_kappa)
417 
418  case default
419  call mpistop("Doesn't know opacity law")
420  end select
421  end subroutine fld_get_opacity
422 
423  !> Calculate fld flux limiter
424  !> This subroutine calculates flux limiter lambda using the prescription
425  !> stored in fld_fluxlimiter.
426  !> It also calculates the ratio of radiation scaleheight and mean free path
427  subroutine fld_get_fluxlimiter(w, x, ixI^L, ixO^L, fld_lambda, fld_R)
429  use mod_geometry
430  use mod_usr_methods
431 
432  integer, intent(in) :: ixi^l, ixo^l
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) :: fld_r(ixo^s), fld_lambda(ixo^s)
436  double precision :: kappa(ixo^s)
437  double precision :: normgrad2(ixo^s)
438  double precision :: grad_r_e(ixi^s), grad_r_eo(ixo^s)
439  double precision :: rad_e(ixi^s)
440  integer :: idir, ix^d
441 
442  double precision :: tmp_l(ixi^s), filtered_l(ixi^s)
443  integer :: filter, idim
444 
445  select case (fld_fluxlimiter)
446  case('Diffusion')
447  fld_lambda(ixo^s) = 1.d0/3.d0
448  fld_r(ixo^s) = zero
449 
450  case('FreeStream')
451  !> Calculate R everywhere
452  !> |grad E|/(rho kappa E)
453  normgrad2(ixo^s) = 0.d0 !smalldouble
454 
455  rad_e(ixi^s) = w(ixi^s, iw_r_e)
456  do idir = 1,ndim
457  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo,nghostcells)
458  normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_eo(ixo^s)**2
459 
460  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e)
461  ! normgrad2(ixO^S) = normgrad2(ixO^S) + grad_r_e(ixO^S)**2
462  end do
463 
464  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
465 
466  fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
467 
468  !> Calculate the flux limiter, lambda
469  fld_lambda(ixo^s) = one/fld_r(ixo^s)
470 
471  case('Pomraning')
472  !> Calculate R everywhere
473  !> |grad E|/(rho kappa E)
474  normgrad2(ixo^s) = 0.d0 !smalldouble !*w(ixO^S,iw_r_e)
475 
476  rad_e(ixi^s) = w(ixi^s, iw_r_e)
477  do idir = 1,ndim
478  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo,nghostcells)
479  normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_eo(ixo^s)**2
480 
481  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e)
482  ! normgrad2(ixO^S) = normgrad2(ixO^S) + grad_r_e(ixO^S)**2
483  end do
484 
485  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
486 
487  fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
488 
489  !> Calculate the flux limiter, lambda
490  !> Levermore and Pomraning: lambda = (2 + R)/(6 + 3R + R^2)
491  fld_lambda(ixo^s) = (2.d0+fld_r(ixo^s))/(6.d0+3*fld_r(ixo^s)+fld_r(ixo^s)**2.d0)
492 
493  case('Pomraning2')
494  call mpistop("Pomraning2 is not quite working, use Pomraning or Minerbo")
495  !> Calculate R everywhere
496  !> |grad E|/(rho kappa E)
497  normgrad2(ixo^s) = 0.d0 !smalldouble
498 
499  rad_e(ixi^s) = w(ixi^s, iw_r_e)
500  do idir = 1,ndim
501  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo,nghostcells)
502  normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_eo(ixo^s)**2
503 
504  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e)
505  ! normgrad2(ixO^S) = normgrad2(ixO^S) + grad_r_e(ixO^S)**2
506  end do
507 
508  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
509 
510  fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
511 
512  !> Calculate the flux limiter, lambda
513  !> Levermore and Pomraning: lambda = 1/R(coth(R)-1/R)
514  fld_lambda(ixo^s) = one/fld_r(ixo^s)*(one/dtanh(fld_r(ixo^s)) - one/fld_r(ixo^s))
515  ! fld_lambda(ixO^S) = one/fld_R(ixO^S)*(dcosh(fld_R(ixO^S))/dsinh(fld_R(ixO^S)) - one/fld_R(ixO^S))
516 
517  !>WHAT HAPPENS WHEN R=0 (full diffusion) => 1/R = NAN => dtanh(1/R) =????
518  where(dtanh(fld_r(ixo^s)) .ne. dtanh(fld_r(ixo^s)))
519  fld_lambda(ixo^s) = 1.d0/3.d0
520  endwhere
521 
522  case('Minerbo')
523  !> Calculate R everywhere
524  !> |grad E|/(rho kappa E)
525  normgrad2(ixo^s) = 0.d0 !smalldouble
526 
527  rad_e(ixi^s) = w(ixi^s, iw_r_e)
528  do idir = 1,ndim
529  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo,nghostcells)
530  normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_eo(ixo^s)**2
531 
532  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e)
533  ! normgrad2(ixO^S) = normgrad2(ixO^S) + grad_r_e(ixO^S)**2
534  end do
535 
536  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
537 
538  fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
539 
540  !> Calculate the flux limiter, lambda
541  !> Minerbo:
542  {do ix^d=ixomin^d,ixomax^d\ }
543  if (fld_r(ix^d) .lt. 3.d0/2.d0) then
544  fld_lambda(ix^d) = 2.d0/(3.d0 + dsqrt(9.d0 + 12.d0*fld_r(ix^d)**2.d0))
545  else
546  fld_lambda(ix^d) = 1.d0/(1.d0 + fld_r(ix^d) + dsqrt(1.d0 + 2.d0*fld_r(ix^d)))
547  endif
548  {enddo\}
549 
550  case('special')
551  if (.not. associated(usr_special_fluxlimiter)) then
552  call mpistop("special fluxlimiter not defined")
553  endif
554  call usr_special_fluxlimiter(ixi^l, ixo^l, w, x, fld_lambda, fld_r)
555  case default
556  call mpistop('Fluxlimiter unknown')
557  end select
558 
559 
560  if (flux_lim_filter) then
561  if (size_l_filter .lt. 1) call mpistop("D filter of size < 1 makes no sense")
562  if (size_l_filter .gt. nghostcells) call mpistop("D filter of size > nghostcells makes no sense")
563 
564  tmp_l(ixo^s) = fld_lambda(ixo^s)
565  filtered_l(ixo^s) = zero
566 
567  do filter = 1,size_l_filter
568  {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_l_filter\}
569  do idim = 1,ndim
570  filtered_l(ix^d) = filtered_l(ix^d) &
571  + tmp_l(ix^d+filter*kr(idim,^d)) &
572  + tmp_l(ix^d-filter*kr(idim,^d))
573  enddo
574  {enddo\}
575  enddo
576 
577  {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
578  tmp_l(ix^d) = (tmp_l(ix^d)+filtered_l(ix^d))/(1+2*size_l_filter*ndim)
579  {enddo\}
580 
581  fld_lambda(ixo^s) = tmp_l(ixo^s)
582  endif
583 
584  end subroutine fld_get_fluxlimiter
585 
586  !> Calculate Radiation Flux
587  !> stores radiation flux in w-array
588  subroutine fld_get_radflux(w, x, ixI^L, ixO^L, rad_flux)
590  use mod_geometry
591 
592  integer, intent(in) :: ixi^l, ixo^l
593  double precision, intent(in) :: w(ixi^s, 1:nw)
594  double precision, intent(in) :: x(ixi^s, 1:ndim)
595  double precision, intent(out) :: rad_flux(ixo^s, 1:ndim)
596 
597  double precision :: grad_r_e(ixi^s), grad_r_eo(ixo^s)
598  double precision :: rad_e(ixi^s)
599  double precision :: kappa(ixo^s), lambda(ixo^s), fld_r(ixo^s)
600  integer :: ix^d, idir
601 
602  rad_e(ixi^s) = w(ixi^s, iw_r_e)
603 
604  call fld_get_opacity(w, x, ixi^l, ixo^l, kappa)
605  call fld_get_fluxlimiter(w, x, ixi^l, ixo^l, lambda, fld_r)
606 
607  !> Calculate the Flux using the fld closure relation
608  !> F = -c*lambda/(kappa*rho) *grad E
609  do idir = 1,ndim
610  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo,nghostcells)
611  rad_flux(ixo^s, idir) = -(const_c/unit_velocity)*lambda(ixo^s)/(kappa(ixo^s)*w(ixo^s,iw_rho))*grad_r_eo(ixo^s)
612 
613  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e)
614  ! rad_flux(ixO^S, idir) = -(const_c/unit_velocity)*lambda(ixO^S)/(kappa(ixO^S)*w(ixO^S,iw_rho))*grad_r_e(ixO^S)
615  end do
616 
617  end subroutine fld_get_radflux
618 
619  !> Calculate Eddington-tensor
620  !> Stores Eddington-tensor in w-array
621  subroutine fld_get_eddington(w, x, ixI^L, ixO^L, eddington_tensor)
623  use mod_geometry
624 
625  integer, intent(in) :: ixI^L, ixO^L
626  double precision, intent(in) :: w(ixI^S, 1:nw)
627  double precision, intent(in) :: x(ixI^S, 1:ndim)
628  double precision, intent(out) :: eddington_tensor(ixO^S,1:ndim,1:ndim)
629  double precision :: tnsr2(ixO^S,1:ndim,1:ndim)
630  double precision :: normgrad2(ixO^S), f(ixO^S)
631  double precision :: grad_r_e(ixI^S, 1:ndim), rad_e(ixI^S)
632  double precision :: grad_r_eO(ixO^S, 1:ndim)
633  double precision :: lambda(ixO^S), fld_R(ixO^S)
634  integer :: i,j, idir,jdir
635 
636  !> Calculate R everywhere
637  !> |grad E|/(rho kappa E)
638  normgrad2(ixo^s) = zero
639 
640  rad_e(ixi^s) = w(ixi^s, iw_r_e)
641  do idir = 1,ndim
642  call gradiento(rad_e,x,ixi^l,ixo^l,idir,grad_r_eo(ixo^s, idir),nghostcells)
643  normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_eo(ixo^s,idir)**2
644 
645  ! call gradient(rad_e,ixI^L,ixO^L,idir,grad_r_e(ixI^S,idir))
646  ! normgrad2(ixO^S) = normgrad2(ixO^S) + grad_r_e(ixO^S,idir)**two
647  end do
648 
649  call fld_get_fluxlimiter(w, x, ixi^l, ixo^l, lambda, fld_r)
650 
651  !> Calculate radiation pressure
652  !> P = (lambda + lambda^2 R^2)*E
653  f(ixo^s) = lambda(ixo^s) + lambda(ixo^s)**two * fld_r(ixo^s)**two
654  f(ixo^s) = one/two*(one-f(ixo^s)) + one/two*(3.d0*f(ixo^s) - one)
655 
656  {^ifoned
657  eddington_tensor(ixo^s,1,1) = f(ixo^s)
658  }
659 
660  {^nooned
661  do idir = 1,ndim
662  eddington_tensor(ixo^s,idir,idir) = half*(one-f(ixo^s))
663  enddo
664 
665  do idir = 1,ndim
666  do jdir = 1,ndim
667  if (idir .ne. jdir) eddington_tensor(ixo^s,idir,jdir) = zero
668  tnsr2(ixo^s,idir,jdir) = half*(3.d0*f(ixo^s) - 1)&
669  *grad_r_eo(ixo^s,idir)*grad_r_eo(ixo^s,jdir)/normgrad2(ixo^s)
670  enddo
671  enddo
672 
673  ! do idir = 1,ndim
674  ! do jdir = 1,ndim
675  ! if (idir .ne. jdir) eddington_tensor(ixO^S,idir,jdir) = zero
676  ! tnsr2(ixO^S,idir,jdir) = half*(3.d0*f(ixO^S) - 1)&
677  ! *grad_r_e(ixO^S,idir)*grad_r_e(ixO^S,jdir)/normgrad2(ixO^S)
678  ! enddo
679  ! enddo
680 
681  do idir = 1,ndim
682  do jdir = 1,ndim
683  where ((tnsr2(ixo^s,idir,jdir) .eq. tnsr2(ixo^s,idir,jdir)) &
684  .and. (normgrad2(ixo^s) .gt. smalldouble))
685  eddington_tensor(ixo^s,idir,jdir) = eddington_tensor(ixo^s,idir,jdir) + tnsr2(ixo^s,idir,jdir)
686  endwhere
687  enddo
688  enddo
689  }
690 
691  end subroutine fld_get_eddington
692 
693  !> Calculate Radiation Pressure
694  !> Returns Radiation Pressure as tensor
695  subroutine fld_get_radpress(w, x, ixI^L, ixO^L, rad_pressure)
697 
698  integer, intent(in) :: ixi^l, ixo^l
699  double precision, intent(in) :: w(ixi^s, 1:nw)
700  double precision, intent(in) :: x(ixi^s, 1:ndim)
701  double precision :: eddington_tensor(ixo^s,1:ndim,1:ndim)
702  double precision, intent(out):: rad_pressure(ixo^s,1:ndim,1:ndim)
703 
704  integer i,j
705 
706  call fld_get_eddington(w, x, ixi^l, ixo^l, eddington_tensor)
707 
708  do i=1,ndim
709  do j=1,ndim
710  rad_pressure(ixo^s,i,j) = eddington_tensor(ixo^s,i,j)* w(ixo^s,iw_r_e)
711  enddo
712  enddo
713  end subroutine fld_get_radpress
714 
715  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
716  !!!!!!!!!!!!!!!!!!! Multigrid diffusion
717  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
718 
719  !> Calling all subroutines to perform the multigrid method
720  !> Communicates rad_e and diff_coeff to multigrid library
721  subroutine diffuse_e_rad_mg(dtfactor,qdt,qtC,psa,psb)
723  use mod_forest
724  ! use mod_ghostcells_update
726  ! use mod_physics, only: phys_set_mg_bounds, phys_req_diagonal
727 
728  type(state), target :: psa(max_blocks) !< Advance psa=psb+dtfactor*qdt*F_im(psa)
729  type(state), target :: psb(max_blocks)
730  double precision, intent(in) :: qdt
731  double precision, intent(in) :: qtC
732  double precision, intent(in) :: dtfactor
733 
734  integer :: n
735  double precision :: res, max_residual, lambda
736  integer, parameter :: max_its = 100
737 
738  integer :: iw_to,iw_from
739  integer :: iigrid, igrid, id
740  integer :: nc, lvl, i
741  type(tree_node), pointer :: pnode
742  real(dp) :: fac, facD
743 
744  ! print*, '1'
745 
746  !> Set diffusion timestep, add previous timestep if mg did not converge:
747  if (it == 0) dt_diff = 0
748  dt_diff = dt_diff + qdt
749 
750  ! Avoid setting a very restrictive limit to the residual when the time step
751  ! is small (as the operator is ~ 1/(D * qdt))
752  if (qdt < dtmin) then
753  if(mype==0)then
754  print *,'skipping implicit solve: dt too small!'
755  print *,'Currently at time=',global_time,' time step=',qdt,' dtmin=',dtmin
756  endif
757  return
758  endif
759  ! max_residual = 1d-7/qdt
760  max_residual = fld_diff_tol !1d-7/qdt
761 
762  mg%operator_type = mg_vhelmholtz
763  mg%smoother_type = mg_smoother_gs
764  call mg_set_methods(mg)
765 
766  if (.not. mg%is_allocated) call mpistop("multigrid tree not allocated yet")
767 
768 ! lambda = 1.d0/(dtfactor * qdt)
769  lambda = 1.d0/(dtfactor * dt_diff)
770  call vhelmholtz_set_lambda(lambda)
771 
772  call update_diffcoeff(psb)
773 
774  fac = 1.d0
775  facd = 1.d0
776 
777  ! print*, '2'
778 
779  !This is mg_copy_to_tree from psb state
780  call mg_copy_to_tree(i_diff_mg, mg_iveps, factor=facd, state_from=psb)
781  !This is mg_copy_to_tree from psb state
782  !!! replaces:: call mg_copy_to_tree(su_, mg_irhs, factor=-lambda)
783  ! iw_from=i_diff_mg
784  ! iw_to=mg_iveps
785  ! fac=facD
786  ! do iigrid=1,igridstail; igrid=igrids(iigrid);
787  ! pnode => igrid_to_node(igrid, mype)%node
788  ! id = pnode%id
789  ! lvl = mg%boxes(id)%lvl
790  ! nc = mg%box_size_lvl(lvl)
791  ! ! Include one layer of ghost cells on grid leaves
792  ! {^IFONED
793  ! mg%boxes(id)%cc(0:nc+1, iw_to) = fac * &
794  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, iw_from)
795  ! }
796  ! {^IFTWOD
797  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, iw_to) = fac * &
798  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, iw_from)
799  ! }
800  ! {^IFTHREED
801  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, iw_to) = fac * &
802  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, &
803  ! ixMlo3-1:ixMhi3+1, iw_from)
804  ! }
805  ! end do
806 
807  ! print*, '3'
808 
809  !This is mg_copy_to_tree from psb state
810  call mg_copy_to_tree(iw_r_e, mg_iphi, factor=fac, state_from=psb)
811  !This is mg_copy_to_tree from psb state
812  !!! replaces:: call mg_copy_to_tree(su_, mg_irhs, factor=-lambda)
813  ! iw_from=iw_r_e
814  ! iw_to=mg_iphi
815  ! fac=fac
816  ! do iigrid=1,igridstail; igrid=igrids(iigrid);
817  ! pnode => igrid_to_node(igrid, mype)%node
818  ! id = pnode%id
819  ! lvl = mg%boxes(id)%lvl
820  ! nc = mg%box_size_lvl(lvl)
821  ! ! Include one layer of ghost cells on grid leaves
822  ! {^IFONED
823  ! mg%boxes(id)%cc(0:nc+1, iw_to) = fac * &
824  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, iw_from)
825  ! }
826  ! {^IFTWOD
827  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, iw_to) = fac * &
828  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, iw_from)
829  ! }
830  ! {^IFTHREED
831  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, iw_to) = fac * &
832  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, &
833  ! ixMlo3-1:ixMhi3+1, iw_from)
834  ! }
835  ! end do
836 
837  ! print*, '4'
838 
839 
840  !>replace call set_rhs(mg, -1/dt, 0.0_dp)
841  call mg_copy_to_tree(iw_r_e, mg_irhs, factor=-1/(dtfactor*dt_diff), state_from=psb)
842  !This is mg_copy_to_tree from psb state
843  !!! replaces:: call mg_copy_to_tree(su_, mg_irhs, factor=-lambda)
844  ! iw_from=iw_r_e
845  ! iw_to=mg_irhs
846  ! fac=-1/(dtfactor*dt_diff)
847  ! do iigrid=1,igridstail; igrid=igrids(iigrid);
848  ! pnode => igrid_to_node(igrid, mype)%node
849  ! id = pnode%id
850  ! lvl = mg%boxes(id)%lvl
851  ! nc = mg%box_size_lvl(lvl)
852  ! ! Include one layer of ghost cells on grid leaves
853  ! {^IFONED
854  ! mg%boxes(id)%cc(0:nc+1, iw_to) = fac * &
855  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, iw_from)
856  ! }
857  ! {^IFTWOD
858  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, iw_to) = fac * &
859  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, iw_from)
860  ! }
861  ! {^IFTHREED
862  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, iw_to) = fac * &
863  ! psb(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, &
864  ! ixMlo3-1:ixMhi3+1, iw_from)
865  ! }
866  ! end do
867 
868  ! call phys_set_mg_bounds()
869 
870  ! print*, '5'
871 
872 
873  if (time_advance)then
874  call mg_restrict(mg, mg_iveps)
875  call mg_fill_ghost_cells(mg, mg_iveps)
876  endif
877 
878  ! print*, '6'
879 
880 
881  call mg_fas_fmg(mg, .true., max_res=res)
882  do n = 1, max_its
883  !print*, n, res
884  if (res < max_residual) exit
885  call mg_fas_vcycle(mg, max_res=res)
886  end do
887 
888  ! print*, '7'
889 
890 
891  if (res .le. 0.d0) then
892  if (diffcrash_resume) then
893  if (mg%my_rank == 0) &
894  write(*,*) it, ' resiudal zero ', res
895  return
896  endif
897  if (mg%my_rank == 0) then
898  print*, res
899  error stop "Diffusion residual to zero"
900  endif
901  endif
902 
903  ! print*, '8'
904 
905 
906  if (n == max_its + 1) then
907  if (diffcrash_resume) then
908  if (mg%my_rank == 0) &
909  write(*,*) it, ' resiudal high ', res
910  return
911  endif
912  if (mg%my_rank == 0) then
913  print *, "Did you specify boundary conditions correctly?"
914  print *, "Or is the variation in diffusion too large?"
915  print*, n, res
916  print *, mg%bc(1, mg_iphi)%bc_value, mg%bc(2, mg_iphi)%bc_value
917  end if
918  error stop "diffusion_solve: no convergence"
919  end if
920 
921  ! print*, '9'
922 
923 
924  !> Reset dt_diff when diffusion worked out
925 !0887 dt_diff = 0.d0
926  dt_diff = 0.d0
927 
928  ! !This is mg_copy_from_tree_gc for psa state
929  call mg_copy_from_tree_gc(mg_iphi, iw_r_e, state_to=psa)
930  !This is mg_copy_from_tree_gc for psa state
931  !!! replaces:: call mg_copy_from_tree_gc(mg_iphi, su_)
932  ! iw_from=mg_iphi
933  ! iw_to=iw_r_e
934  ! do iigrid=1,igridstail; igrid=igrids(iigrid);
935  ! pnode => igrid_to_node(igrid, mype)%node
936  ! id = pnode%id
937  ! lvl = mg%boxes(id)%lvl
938  ! nc = mg%box_size_lvl(lvl)
939  ! ! Include one layer of ghost cells on grid leaves
940  ! {^IFONED
941  ! psa(igrid)%w(ixMlo1-1:ixMhi1+1, iw_to) = &
942  ! mg%boxes(id)%cc(0:nc+1, iw_from)
943  ! }
944  ! {^IFTWOD
945  ! psa(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, iw_to) = &
946  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, iw_from)
947  ! }
948  ! {^IFTHREED
949  ! psa(igrid)%w(ixMlo1-1:ixMhi1+1, ixMlo2-1:ixMhi2+1, &
950  ! ixMlo3-1:ixMhi3+1, iw_to) = &
951  ! mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, iw_from)
952  ! }
953  ! end do
954 
955  ! print*, '10'
956 
957 
958  end subroutine diffuse_e_rad_mg
959 
960 
961  !> inplace update of psa==>F_im(psa)
962  subroutine evaluate_e_rad_mg(qtC,psa)
965  use mod_physics, only: phys_req_diagonal
966 
967  type(state), target :: psa(max_blocks)
968  double precision, intent(in) :: qtC
969 
970  integer :: iigrid, igrid, level
971  integer :: ixO^L
972 
973  call update_diffcoeff(psa)
974 
975  ixo^l=ixg^ll^lsub1;
976  !$OMP PARALLEL DO PRIVATE(igrid)
977  do iigrid=1,igridstail; igrid=igrids(iigrid);
978  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
979  ! call fld_get_diffcoef_central(psa(igrid)%w, psa(igrid)%w, psa(igrid)%x, ixG^LL, ixO^L)
980  call put_diffterm_onegrid(ixg^ll,ixo^l,psa(igrid)%w)
981  end do
982  !$OMP END PARALLEL DO
983 
984  ! enforce boundary conditions for psa
985  call getbc(qtc,0.d0,psa,1,nwflux+nwaux,phys_req_diagonal)
986 
987  end subroutine evaluate_e_rad_mg
988 
989  !> inplace update of psa==>F_im(psa)
990  subroutine put_diffterm_onegrid(ixI^L,ixO^L,w)
992  integer, intent(in) :: ixI^L, ixO^L
993  double precision, intent(inout) :: w(ixI^S, 1:nw)
994 
995  double precision :: gradE(ixO^S),divF(ixO^S)
996  double precision :: divF_h(ixO^S),divF_j(ixO^S)
997  double precision :: diff_term(ixO^S)
998 
999  integer :: idir, jxO^L, hxO^L
1000 
1001  ! call mpistop("phys_evaluate_implicit not implemented for FLD")
1002 
1003  divf(ixo^s) = 0.d0
1004  do idir = 1,ndim
1005  hxo^l=ixo^l-kr(idir,^d);
1006  jxo^l=ixo^l+kr(idir,^d);
1007 
1008  divf_h(ixo^s) = w(ixo^s,i_diff_mg)*w(hxo^s,i_diff_mg)/(w(ixo^s,i_diff_mg) + w(hxo^s,i_diff_mg))*(w(hxo^s,iw_r_e) - w(ixo^s,iw_r_e))
1009  divf_j(ixo^s) = w(ixo^s,i_diff_mg)*w(jxo^s,i_diff_mg)/(w(ixo^s,i_diff_mg) + w(jxo^s,i_diff_mg))*(w(jxo^s,iw_r_e) - w(ixo^s,iw_r_e))
1010  divf(ixo^s) = divf(ixo^s) + 2.d0*(divf_h(ixo^s) + divf_j(ixo^s))/dxlevel(idir)**2
1011  enddo
1012 
1013  w(ixo^s,iw_r_e) = divf(ixo^s)
1014 
1015  end subroutine put_diffterm_onegrid
1016 
1017 
1018  !> Calculates cell-centered diffusion coefficient to be used in multigrid
1019  subroutine fld_get_diffcoef_central(w, wCT, x, ixI^L, ixO^L)
1021  use mod_geometry
1022  use mod_usr_methods
1023 
1024  integer, intent(in) :: ixI^L, ixO^L
1025  double precision, intent(inout) :: w(ixI^S, 1:nw)
1026  double precision, intent(in) :: wCT(ixI^S, 1:nw)
1027  double precision, intent(in) :: x(ixI^S, 1:ndim)
1028 
1029  double precision :: kappa(ixO^S), lambda(ixO^S), fld_R(ixO^S)
1030 
1031  double precision :: max_D(ixI^S), grad_r_e(ixI^S), rad_e(ixI^S)
1032  integer :: idir,i,j, ix^D
1033 
1034 
1035  call fld_get_opacity(wct, x, ixi^l, ixo^l, kappa)
1036  call fld_get_fluxlimiter(wct, x, ixi^l, ixo^l, lambda, fld_r)
1037 
1038  !> calculate diffusion coefficient
1039  w(ixo^s,i_diff_mg) = (const_c/unit_velocity)*lambda(ixo^s)/(kappa(ixo^s)*wct(ixo^s,iw_rho))
1040 
1041  where (w(ixo^s,i_diff_mg) .lt. 0.d0) &
1042  w(ixo^s,i_diff_mg) = smalldouble
1043 
1044  if (diff_coef_filter) then
1045  !call mpistop('Hold your bloody horses, not implemented yet ')
1046  call fld_smooth_diffcoef(w, ixi^l, ixo^l)
1047  endif
1048 
1049  if (associated(usr_special_diffcoef)) &
1050  call usr_special_diffcoef(w, wct, x, ixi^l, ixo^l)
1051 
1052  end subroutine fld_get_diffcoef_central
1053 
1054  subroutine update_diffcoeff(psa)
1056 
1057  type(state), target :: psa(max_blocks)
1058 
1059  ! double precision :: wCT(ixG^LL,1:nw)
1060  integer :: iigrid, igrid, level
1061  integer :: ixO^L
1062 
1063  ixo^l=ixg^ll^lsub1;
1064  !$OMP PARALLEL DO PRIVATE(igrid)
1065  do iigrid=1,igridstail; igrid=igrids(iigrid);
1066  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1067 
1068  ! wCT = psa(igrid)%w
1069  call fld_get_diffcoef_central(psa(igrid)%w, psa(igrid)%w, psa(igrid)%x, ixg^ll, ixo^l)
1070  end do
1071  !$OMP END PARALLEL DO
1072 
1073  end subroutine update_diffcoeff
1074 
1075  !> Use running average on Diffusion coefficient
1076  subroutine fld_smooth_diffcoef(w, ixI^L, ixO^L)
1078 
1079  integer, intent(in) :: ixI^L, ixO^L
1080  double precision, intent(inout) :: w(ixI^S, 1:nw)
1081 
1082  double precision :: tmp_D(ixI^S), filtered_D(ixI^S)
1083  integer :: ix^D, filter, idim
1084 
1085  if (size_d_filter .lt. 1) call mpistop("D filter of size < 1 makes no sense")
1086  if (size_d_filter .gt. nghostcells) call mpistop("D filter of size > nghostcells makes no sense")
1087 
1088  tmp_d(ixo^s) = w(ixo^s,i_diff_mg)
1089  filtered_d(ixo^s) = zero
1090 
1091  do filter = 1,size_d_filter
1092  {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
1093  do idim = 1,ndim
1094  filtered_d(ix^d) = filtered_d(ix^d) &
1095  + tmp_d(ix^d+filter*kr(idim,^d)) &
1096  + tmp_d(ix^d-filter*kr(idim,^d))
1097  enddo
1098  {enddo\}
1099  enddo
1100 
1101  {do ix^d = ixomin^d+size_d_filter,ixomax^d-size_d_filter\}
1102  tmp_d(ix^d) = (tmp_d(ix^d)+filtered_d(ix^d))/(1+2*size_d_filter*ndim)
1103  {enddo\}
1104 
1105  w(ixo^s,i_diff_mg) = tmp_d(ixo^s)
1106  end subroutine fld_smooth_diffcoef
1107 
1108 
1109  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1110  !!!!!!!!!!!!!!!!!!! Gas-Rad Energy interaction
1111  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1112 
1113  !> This subroutine calculates the radiation heating, radiation cooling
1114  !> and photon tiring using an implicit scheme.
1115  !> These sourceterms are applied using the root-finding of a 4th order polynomial
1116  !> This routine loops over every cell in the domain
1117  !> and computes the coefficients of the polynomials in every cell
1118  subroutine energy_interaction(w, wCT, x, ixI^L, ixO^L)
1120  use mod_geometry
1121  use mod_physics
1122  use mod_usr_methods
1123 
1124  integer, intent(in) :: ixI^L, ixO^L
1125  double precision, intent(in) :: x(ixI^S,1:ndim)
1126  double precision, intent(in) :: wCT(ixI^S,1:nw)
1127  double precision, intent(inout) :: w(ixI^S,1:nw)
1128 
1129  double precision :: a1(ixO^S), a2(ixO^S)
1130  double precision :: c0(ixO^S), c1(ixO^S)
1131  double precision :: e_gas(ixO^S), E_rad(ixO^S)
1132  double precision :: kappa(ixO^S)
1133  double precision :: sigma_b
1134 
1135  integer :: i,j,idir,ix^D
1136 
1137  !> e_gas is the INTERNAL ENERGY without KINETIC ENERGY
1138  ! if (.not. block%e_is_internal) then
1139  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)
1140  ! else
1141  ! e_gas(ixO^S) = wCT(ixO^S,iw_e)
1142  ! endif
1143 
1144  {do ix^d=ixomin^d,ixomax^d\ }
1145  e_gas(ix^d) = max(e_gas(ix^d),small_pressure/(fld_gamma-1.d0))
1146  {enddo\}
1147 
1148  e_rad(ixo^s) = wct(ixo^s,iw_r_e)
1149 
1150  if (associated(usr_special_opacity_qdot)) then
1151  call usr_special_opacity_qdot(ixi^l,ixo^l,w,x,kappa)
1152  else
1153  call fld_get_opacity(wct, x, ixi^l, ixo^l, kappa)
1154  endif
1155 
1156  sigma_b = const_rad_a*const_c/4.d0*(unit_temperature**4.d0)/(unit_velocity*unit_pressure)
1157 
1158  if (fld_interaction_method .eq. 'Instant') then
1159  a1(ixo^s) = const_rad_a*(fld_mu*const_mp/const_kb*(fld_gamma-1))**4/(wct(ixo^s,iw_rho)*unit_density)**4 &
1160  /unit_pressure**3
1161  a2(ixo^s) = e_gas(ixo^s) + e_rad(ixo^s)
1162 
1163  c0(ixo^s) = a2(ixo^s)/a1(ixo^s)
1164  c1(ixo^s) = 1.d0/a1(ixo^s)
1165  else
1166  !> Calculate coefficients for polynomial
1167  a1(ixo^s) = 4*kappa(ixo^s)*sigma_b*(fld_gamma-one)**4/wct(ixo^s,iw_rho)**3*dt
1168  a2(ixo^s) = (const_c/unit_velocity)*kappa(ixo^s)*wct(ixo^s,iw_rho)*dt
1169 
1170  c0(ixo^s) = ((one + a2(ixo^s))*e_gas(ixo^s) + a2(ixo^s)*e_rad(ixo^s))/a1(ixo^s)
1171  c1(ixo^s) = (one + a2(ixo^s))/a1(ixo^s)
1172  endif
1173 
1174  !> Loop over every cell for rootfinding method
1175  {do ix^d=ixomin^d,ixomax^d\ }
1176  select case(fld_interaction_method)
1177  case('Bisect')
1178  call bisection_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
1179  case('Newton')
1180  call newton_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
1181  case('Halley')
1182  call halley_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
1183  case('Instant')
1184  call halley_method(e_gas(ix^d), e_rad(ix^d), c0(ix^d), c1(ix^d))
1185  case default
1186  call mpistop('root-method not known')
1187  end select
1188  {enddo\}
1189 
1190  if (fld_interaction_method .eq. 'Instant') then
1191  e_rad(ixo^s) = a2(ixo^s) - e_gas(ixo^s)
1192  else
1193  !> advance E_rad
1194  e_rad(ixo^s) = (a1(ixo^s)*e_gas(ixo^s)**4.d0 + e_rad(ixo^s))/(one + a2(ixo^s))
1195  endif
1196 
1197  !> new w = w + dt f(wCT)
1198  !> e_gas,E_rad = wCT + dt f(wCT)
1199  !> dt f(wCT) = e_gas,E_rad - wCT
1200  !> new w = w + e_gas,E_rad - wCT
1201 
1202  !> WAIT A SECOND?! DOES THIS EVEN WORK WITH THESE KIND OF IMPLICIT METHODS?
1203  !> NOT QUITE SURE TO BE HONEST
1204  !> IS IT POSSIBLE TO SHUT DOWN SOURCE SPLITTING FOR JUST THIS TERM?
1205  !> FIX BY PERFORMING Energy_interaction on (w,w,...)
1206 
1207  ! call mpistop('This still has to be fixed somehow')
1208 
1209  !> Update gas-energy in w, internal + kinetic
1210  ! w(ixO^S,iw_e) = w(ixO^S,iw_e) + e_gas(ixO^S) - wCT(ixO^S,iw_e)
1211  ! {do ix^D=ixOmin^D,ixOmax^D\ }
1212  ! e_gas(ix^D) = max(e_gas(ix^D),small_pressure/(fld_gamma-1.d0))
1213  ! {enddo\}
1214 
1215  !{do ix^D=ixOmin^D,ixOmax^D\ }
1216  ! w(ix^D,iw_e) = max(e_gas(ix^D),small_pressure/(fld_gamma - 1))
1217  !{enddo\}
1218  w(ixo^s,iw_e) = e_gas(ixo^s)
1219 
1220  !> Beginning of module substracted wCT Ekin
1221  !> So now add wCT Ekin
1222  ! if (.not. block%e_is_internal) then
1223  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)
1224  ! else
1225  ! w(ixO^S,iw_e) = w(ixO^S,iw_e)
1226  ! endif
1227 
1228  !> Update rad-energy in w
1229  ! w(ixO^S,iw_r_e) = w(ixO^S,iw_r_e) + E_rad(ixO^S) - wCT(ixO^S,iw_r_e)
1230  w(ixo^s,iw_r_e) = e_rad(ixo^s)
1231 
1232  end subroutine energy_interaction
1233 
1234 
1235  !> Find the root of the 4th degree polynomial using the bisection method
1236  subroutine bisection_method(e_gas, E_rad, c0, c1)
1238 
1239  double precision, intent(in) :: c0, c1
1240  double precision, intent(in) :: E_rad
1241  double precision, intent(inout) :: e_gas
1242 
1243  double precision :: bisect_a, bisect_b, bisect_c
1244  integer :: n, max_its
1245 
1246  n = 0
1247  max_its = 1d2
1248 
1249  bisect_a = zero
1250  bisect_b = min(abs(c0/c1),abs(c0)**(1.d0/4.d0))+smalldouble
1251 
1252  ! do while (abs(Polynomial_Bisection(bisect_b, c0, c1)-Polynomial_Bisection(bisect_a, c0, c1))&
1253  ! .ge. fld_bisect_tol*min(e_gas,E_rad))
1254  do while (abs(bisect_b-bisect_a) .ge. fld_bisect_tol*min(e_gas,e_rad))
1255  bisect_c = (bisect_a + bisect_b)/two
1256 
1257  n = n +1
1258  if (n .gt. max_its) then
1259  goto 2435
1260  call mpistop('No convergece in bisection scheme')
1261  endif
1262 
1263  if (polynomial_bisection(bisect_a, c0, c1)*&
1264  polynomial_bisection(bisect_b, c0, c1) .lt. zero) then
1265 
1266  if (polynomial_bisection(bisect_a, c0, c1)*&
1267  polynomial_bisection(bisect_c, c0, c1) .lt. zero) then
1268  bisect_b = bisect_c
1269  elseif (polynomial_bisection(bisect_b, c0, c1)*&
1270  polynomial_bisection(bisect_c, c0, c1) .lt. zero) then
1271  bisect_a = bisect_c
1272  elseif (polynomial_bisection(bisect_a, c0, c1) .eq. zero) then
1273  bisect_b = bisect_a
1274  bisect_c = bisect_a
1275  goto 2435
1276  elseif (polynomial_bisection(bisect_b, c0, c1) .eq. zero) then
1277  bisect_a = bisect_b
1278  bisect_c = bisect_b
1279  goto 2435
1280  elseif (polynomial_bisection(bisect_c, c0, c1) .eq. zero) then
1281  bisect_a = bisect_c
1282  bisect_b = bisect_c
1283  goto 2435
1284  else
1285  call mpistop("Problem with fld bisection method")
1286  endif
1287  elseif (polynomial_bisection(bisect_a, c0, c1) &
1288  - polynomial_bisection(bisect_b, c0, c1) .lt. fld_bisect_tol*polynomial_bisection(bisect_a, c0, c1)) then
1289  goto 2435
1290  else
1291  bisect_a = e_gas
1292  bisect_b = e_gas
1293  print*, "IGNORING GAS-RAD ENERGY EXCHANGE ", c0, c1
1294 
1295  print*, polynomial_bisection(bisect_a, c0, c1), polynomial_bisection(bisect_b, c0, c1)
1296 
1297  if (polynomial_bisection(bisect_a, c0, c1) .le. smalldouble) then
1298  bisect_b = bisect_a
1299  elseif (polynomial_bisection(bisect_a, c0, c1) .le. smalldouble) then
1300  bisect_a = bisect_b
1301  endif
1302 
1303  goto 2435
1304 
1305  endif
1306  enddo
1307 
1308  2435 e_gas = (bisect_a + bisect_b)/two
1309  end subroutine bisection_method
1310 
1311  !> Find the root of the 4th degree polynomial using the Newton-Ralphson method
1312  subroutine newton_method(e_gas, E_rad, c0, c1)
1314 
1315  double precision, intent(in) :: c0, c1
1316  double precision, intent(in) :: E_rad
1317  double precision, intent(inout) :: e_gas
1318 
1319  double precision :: xval, yval, der, deltax
1320 
1321  integer :: ii
1322 
1323  yval = bigdouble
1324  xval = e_gas
1325  der = one
1326  deltax = one
1327 
1328  ii = 0
1329  !> Compare error with dx = dx/dy dy
1330  do while (abs(deltax) .gt. fld_bisect_tol)
1331  yval = polynomial_bisection(xval, c0, c1)
1332  der = dpolynomial_bisection(xval, c0, c1)
1333  deltax = -yval/der
1334  xval = xval + deltax
1335  ii = ii + 1
1336  if (ii .gt. 1d3) then
1337  print*, 'skip to bisection algorithm'
1338  call bisection_method(e_gas, e_rad, c0, c1)
1339  return
1340  endif
1341  enddo
1342 
1343  e_gas = xval
1344  end subroutine newton_method
1345 
1346  !> Find the root of the 4th degree polynomial using the Halley method
1347  subroutine halley_method(e_gas, E_rad, c0, c1)
1349 
1350  double precision, intent(in) :: c0, c1
1351  double precision, intent(in) :: E_rad
1352  double precision, intent(inout) :: e_gas
1353 
1354  double precision :: xval, yval, der, dder, deltax
1355 
1356  integer :: ii
1357 
1358  yval = bigdouble
1359  xval = e_gas
1360  der = one
1361  dder = one
1362  deltax = one
1363 
1364  ii = 0
1365  !> Compare error with dx = dx/dy dy
1366  do while (abs(deltax) .gt. fld_bisect_tol)
1367  yval = polynomial_bisection(xval, c0, c1)
1368  der = dpolynomial_bisection(xval, c0, c1)
1369  dder = ddpolynomial_bisection(xval, c0, c1)
1370  deltax = -two*yval*der/(two*der**2 - yval*dder)
1371  xval = xval + deltax
1372  ii = ii + 1
1373  if (ii .gt. 1d3) then
1374  ! call mpistop('Halley did not convergggge')
1375  call newton_method(e_gas, e_rad, c0, c1)
1376  return
1377  endif
1378  enddo
1379 
1380  e_gas = xval
1381  end subroutine halley_method
1382 
1383  !> Evaluate polynomial at argument e_gas
1384  function polynomial_bisection(e_gas, c0, c1) result(val)
1386 
1387  double precision, intent(in) :: e_gas
1388  double precision, intent(in) :: c0, c1
1389  double precision :: val
1390 
1391  val = e_gas**4.d0 + c1*e_gas - c0
1392  end function polynomial_bisection
1393 
1394  !> Evaluate first derivative of polynomial at argument e_gas
1395  function dpolynomial_bisection(e_gas, c0, c1) result(der)
1397 
1398  double precision, intent(in) :: e_gas
1399  double precision, intent(in) :: c0, c1
1400  double precision :: der
1401 
1402  der = 4.d0*e_gas**3.d0 + c1
1403  end function dpolynomial_bisection
1404 
1405  !> Evaluate second derivative of polynomial at argument e_gas
1406  function ddpolynomial_bisection(e_gas, c0, c1) result(dder)
1408 
1409  double precision, intent(in) :: e_gas
1410  double precision, intent(in) :: c0, c1
1411  double precision :: dder
1412 
1413  dder = 4.d0*3.d0*e_gas**2.d0
1414  end function ddpolynomial_bisection
1415 
1416  !> Calculate gradient of a scalar q within ixL in direction idir
1417  !> difference with gradient is gradq(ixO^S), NOT gradq(ixI^S)
1418  subroutine gradiento(q,x,ixI^L,ixO^L,idir,gradq,n)
1420 
1421  integer, intent(in) :: ixI^L, ixO^L, idir
1422  integer, intent(in) :: n
1423 
1424  double precision, intent(in) :: q(ixI^S), x(ixI^S,1:ndim)
1425  double precision, intent(out) :: gradq(ixO^S)
1426  integer :: jxO^L, hxO^L
1427 
1428  ! hxO^L=ixO^L-n*kr(idir,^D);
1429  ! jxO^L=ixO^L+n*kr(idir,^D);
1430  !
1431  ! if (n .gt. nghostcells) call mpistop("gradientO stencil too wide")
1432  !
1433  ! gradq(ixO^S)=(q(jxO^S)-q(hxO^S))/(2*n*dxlevel(idir))
1434  ! gradq(ixO^S)=(q(jxO^S)-q(hxO^S))/(x(jxO^S,idir)-x(hxO^S,idir))
1435 
1436  !> Using higher order derivatives with wider stencil according to:
1437  !> https://en.wikipedia.org/wiki/Finite_difference_coefficient
1438 
1439  if (n .gt. nghostcells) then
1440  call mpistop("gradientO stencil too wide")
1441  elseif (n .eq. 1) then
1442  hxo^l=ixo^l-kr(idir,^d);
1443  jxo^l=ixo^l+kr(idir,^d);
1444  gradq(ixo^s)=(q(jxo^s)-q(hxo^s))/(x(jxo^s,idir)-x(hxo^s,idir))
1445  elseif (n .eq. 2) then
1446  gradq(ixo^s) = 0.d0
1447  !> coef 2/3
1448  hxo^l=ixo^l-kr(idir,^d);
1449  jxo^l=ixo^l+kr(idir,^d);
1450  gradq(ixo^s) = gradq(ixo^s) + 2.d0/3.d0*(q(jxo^s)-q(hxo^s))
1451  !> coef -1/12
1452  hxo^l=ixo^l-2*kr(idir,^d);
1453  jxo^l=ixo^l+2*kr(idir,^d);
1454  gradq(ixo^s) = gradq(ixo^s) - 1.d0/12.d0*(q(jxo^s)-q(hxo^s))
1455  !> divide by dx
1456  gradq(ixo^s) = gradq(ixo^s)/dxlevel(idir)
1457  elseif (n .eq. 3) then
1458  gradq(ixo^s) = 0.d0
1459  !> coef 3/4
1460  hxo^l=ixo^l-kr(idir,^d);
1461  jxo^l=ixo^l+kr(idir,^d);
1462  gradq(ixo^s) = gradq(ixo^s) + 3.d0/4.d0*(q(jxo^s)-q(hxo^s))
1463  !> coef -3/20
1464  hxo^l=ixo^l-2*kr(idir,^d);
1465  jxo^l=ixo^l+2*kr(idir,^d);
1466  gradq(ixo^s) = gradq(ixo^s) - 3.d0/20.d0*(q(jxo^s)-q(hxo^s))
1467  !> coef 1/60
1468  hxo^l=ixo^l-3*kr(idir,^d);
1469  jxo^l=ixo^l+3*kr(idir,^d);
1470  gradq(ixo^s) = gradq(ixo^s) + 1.d0/60.d0*(q(jxo^s)-q(hxo^s))
1471  !> divide by dx
1472  gradq(ixo^s) = gradq(ixo^s)/dxlevel(idir)
1473  else
1474  call mpistop("gradientO stencil unknown")
1475  endif
1476 
1477  end subroutine gradiento
1478 
1479 end module mod_fld
subroutine mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: comm_lib.t:194
Module for physical and numeric constants.
Definition: mod_constants.t:2
double precision, parameter const_c
Definition: mod_constants.t:48
Nicolas Moens Module for including flux limited diffusion (FLD)-approximation in Radiation-hydrodynam...
Definition: mod_fld.t:9
subroutine energy_interaction(w, wCT, x, ixIL, ixOL)
This subroutine calculates the radiation heating, radiation cooling and photon tiring using an implic...
Definition: mod_fld.t:1119
subroutine gradiento(q, x, ixIL, ixOL, idir, gradq, n)
Calculate gradient of a scalar q within ixL in direction idir difference with gradient is gradq(ixO^S...
Definition: mod_fld.t:1419
double precision, public fld_mu
mean particle mass
Definition: mod_fld.t:20
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_fld.t:24
double precision, public fld_diff_tol
Tolerance for adi method for radiative Energy diffusion.
Definition: mod_fld.t:27
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_fld.t:722
subroutine fld_smooth_diffcoef(w, ixIL, ixOL)
Use running average on Diffusion coefficient.
Definition: mod_fld.t:1077
subroutine, public fld_radforce_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
Definition: mod_fld.t:288
subroutine fld_params_read(files)
public methods these are called in mod_rhd_phys
Definition: mod_fld.t:90
logical diffcrash_resume
Resume run when multigrid returns error.
Definition: mod_fld.t:60
subroutine update_diffcoeff(psa)
Definition: mod_fld.t:1055
integer, dimension(:), allocatable, public i_opf
Index for Flux weighted opacities.
Definition: mod_fld.t:63
character(len=8) fld_opacity_law
Use constant Opacity?
Definition: mod_fld.t:33
subroutine fld_get_eddington(w, x, ixIL, ixOL, eddington_tensor)
Calculate Eddington-tensor Stores Eddington-tensor in w-array.
Definition: mod_fld.t:622
double precision function ddpolynomial_bisection(e_gas, c0, c1)
Evaluate second derivative of polynomial at argument e_gas.
Definition: mod_fld.t:1407
subroutine, public fld_get_radflux(w, x, ixIL, ixOL, rad_flux)
Calculate Radiation Flux stores radiation flux in w-array.
Definition: mod_fld.t:589
character(len=16) fld_fluxlimiter
Diffusion limit lambda = 0.33.
Definition: mod_fld.t:37
subroutine halley_method(e_gas, E_rad, c0, c1)
Find the root of the 4th degree polynomial using the Halley method.
Definition: mod_fld.t:1348
subroutine put_diffterm_onegrid(ixIL, ixOL, w)
inplace update of psa==>F_im(psa)
Definition: mod_fld.t:991
integer size_l_filter
Definition: mod_fld.t:54
integer size_d_filter
Definition: mod_fld.t:50
double precision, public fld_kappa0
Opacity per unit of unit_density.
Definition: mod_fld.t:17
character(len=8) fld_diff_scheme
Which method to solve diffusion part.
Definition: mod_fld.t:43
logical lineforce_opacities
Use or dont use lineforce opacities.
Definition: mod_fld.t:57
subroutine, public get_fld_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_fld.t:180
double precision function polynomial_bisection(e_gas, c0, c1)
Evaluate polynomial at argument e_gas.
Definition: mod_fld.t:1385
logical fld_eint_split
source split for energy interact and radforce:
Definition: mod_fld.t:13
character(len=8) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
Definition: mod_fld.t:46
subroutine, public fld_get_radpress(w, x, ixIL, ixOL, rad_pressure)
Calculate Radiation Pressure Returns Radiation Pressure as tensor.
Definition: mod_fld.t:696
logical fld_radforce_split
Definition: mod_fld.t:14
subroutine, public fld_init(He_abundance, rhd_radiation_diffusion, rhd_gamma)
Initialising FLD-module: Read opacities Initialise Multigrid adimensionalise kappa Add extra variable...
Definition: mod_fld.t:117
double precision function dpolynomial_bisection(e_gas, c0, c1)
Evaluate first derivative of polynomial at argument e_gas.
Definition: mod_fld.t:1396
subroutine, public fld_get_opacity(w, x, ixIL, ixOL, fld_kappa)
Sets the opacity in the w-array by calling mod_opal_opacity.
Definition: mod_fld.t:343
subroutine, public get_fld_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_fld.t:319
integer i_diff_mg
diffusion coefficient for multigrid method
Definition: mod_fld.t:40
subroutine evaluate_e_rad_mg(qtC, psa)
inplace update of psa==>F_im(psa)
Definition: mod_fld.t:963
character(len=6) fld_opal_table
Definition: mod_fld.t:34
subroutine fld_get_diffcoef_central(w, wCT, x, ixIL, ixOL)
Calculates cell-centered diffusion coefficient to be used in multigrid.
Definition: mod_fld.t:1020
subroutine bisection_method(e_gas, E_rad, c0, c1)
Find the root of the 4th degree polynomial using the bisection method.
Definition: mod_fld.t:1237
logical flux_lim_filter
Take a running average over the fluxlimiter.
Definition: mod_fld.t:53
logical diff_coef_filter
Take running average for Diffusion coefficient.
Definition: mod_fld.t:49
subroutine, public fld_get_fluxlimiter(w, x, ixIL, ixOL, fld_lambda, fld_R)
Calculate fld flux limiter This subroutine calculates flux limiter lambda using the prescription stor...
Definition: mod_fld.t:428
double precision dt_diff
running timestep for diffusion solver, initialised as zero
Definition: mod_fld.t:69
double precision, public diff_crit
Number for splitting the diffusion module.
Definition: mod_fld.t:30
subroutine newton_method(e_gas, E_rad, c0, c1)
Find the root of the 4th degree polynomial using the Newton-Ralphson method.
Definition: mod_fld.t:1313
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)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:320
update ghost cells of all blocks including physical boundaries
subroutine getbc(time, qdt, psb, nwstart, nwbc, req_diag)
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 small_pressure
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.
integer, dimension(:), allocatable, parameter d
double precision courantpar
The Courant (CFL) number used for the simulation.
double precision unit_velocity
Physical scaling factor for velocity.
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
double precision, dimension(:,:), allocatable dx
integer nghostcells
Number of ghost cells surrounding a grid.
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.
double precision, dimension(ndim) dxlevel
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 opacities from opal tables.
subroutine, public set_opal_opacity(rho, temp, kappa)
This subroutine calculates the opacity for a given temperature-density structure. The opacities are r...
subroutine, public init_opal(He_abundance, tablename)
This routine is called when the fld radiation module is initialised. Here, the tables for different H...
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:76
procedure(sub_evaluate_implicit), pointer phys_evaluate_implicit
Definition: mod_physics.t:86
logical phys_req_diagonal
Whether the physics routines require diagonal ghost cells, for example for computing a curl.
Definition: mod_physics.t:27
procedure(sub_get_pthermal), pointer phys_get_pthermal
Definition: mod_physics.t:75
procedure(sub_implicit_update), pointer phys_implicit_update
Definition: mod_physics.t:85
Module with all the methods that users can customize in AMRVAC.
procedure(special_opacity), pointer usr_special_opacity
procedure(special_diffcoef), pointer usr_special_diffcoef
procedure(special_fluxlimiter), pointer usr_special_fluxlimiter
procedure(special_opacity_qdot), pointer usr_special_opacity_qdot
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