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