53 integer,
intent(in) :: ixI^L, ixO^L
54 double precision,
intent(in) :: w(ixI^S,nw)
55 double precision,
intent(in) :: x(ixI^S,1:ndim)
56 double precision,
intent(out):: res(ixI^S)
65 double precision :: gamma
69 procedure(
fld_get_var),
pointer,
nopass :: get_rfactor => null()
96 character(len=*),
intent(in) :: files(:)
105 do n = 1,
size(files)
106 open(
unitpar, file=trim(files(n)), status=
"old")
107 read(
unitpar, fld_list,
end=111)
115 subroutine fld_init(gas_eos_type, gas_ion_energy, gas_pi_table)
121 character(len=*),
intent(in) :: gas_eos_type, gas_pi_table
122 logical,
intent(in) :: gas_ion_energy
132 if(trim(gas_eos_type)==
'LTE')
call mpistop(
"FLD is not yet available with eos_type='LTE': "//&
133 'the radiation exchange takes the gas temperature as (gamma-1) e/(rho R)')
134 if(gas_ion_energy.and.trim(gas_eos_type)==
'PI')
then
135 call mpistop(
'FLD currently does not support PI with ionE=T: '//&
136 'the radiation exchange solver assumes ideal-gas internal energy')
139 if(trim(gas_eos_type)==
'PI'.and.trim(gas_pi_table)==
'prominence')
then
140 call mpistop(
'FLD with PI prominence and OPAL opacity is not implemented: '//&
141 'the opacity temperature callback is incompatible with primitive states')
147 call mpistop(
"please set the constant opacity to a reasonable value")
151 call mpistop(
"convergence tolerance for root solver too strict")
154 if(
mype==0) print *,
'Will do photon tiring explicit!!!'
159 call mpistop(
"convergence tolerance for MG solver too strict")
168 call mpistop(
"nth_for_diff_mg must be 1 or 2")
180 mg%operator_type = mg_vhelmholtz
182 mg%smoother_type = mg_smoother_gsrb
186 if(
si_unit)
call mpistop(
"adjust opal module with SI-cgs conversions for SI - or use cgs!")
204 mg%bc(ib, mg_iphi)%bc_type = mg_bc_neumann
205 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
208 mg%bc(ib, mg_iphi)%bc_type = mg_bc_dirichlet
209 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
212 mg%bc(ib, mg_iphi)%bc_type = mg_bc_neumann
213 mg%bc(ib, mg_iphi)%bc_value = 0.0_dp
218 print *,
'Special boundary for Erad needs specific user-set MG BC treatment'
219 print *,
' and this could be through usr_special_mg_bc call'
225 call mpistop(
"divE_multigrid warning: unknown b.c. ")
229 mg%bc(ib, mg_iveps)%bc_type = mg_bc_neumann
230 mg%bc(ib, mg_iveps)%bc_value = 0.0_dp
243 integer,
intent(in) :: ixi^
l, ixo^
l
244 double precision,
intent(in) :: qdt, x(ixi^s,1:
ndim)
245 double precision,
intent(in) :: wct(ixi^s,1:nw),wctprim(ixi^s,1:nw)
246 double precision,
intent(inout) :: w(ixi^s,1:nw)
247 logical,
intent(in) :: qsourcesplit
248 logical,
intent(inout) :: active
251 integer :: idir,jdir,nth_for_fld,ix^
d
252 double precision,
dimension(ixI^S) :: a1,a2,a3,c0,c1,kappa
253 double precision,
dimension(ixI^S) :: e_gas,e_rad,tmp
254 double precision,
dimension(ixI^S,1:ndim,1:ndim) :: div_v,edd
268 call gradient(wctprim(ixi^s,iw_mom(jdir)),ixi^
l,ixo^
l,idir,tmp)
269 div_v(ixo^s,idir,jdir) = tmp(ixo^s)
274 a3(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1)
277 a3(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
278 + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
279 + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
280 + div_v(ixo^s,2,2)*edd(ixo^s,2,2)
283 a3(ixo^s) = div_v(ixo^s,1,1)*edd(ixo^s,1,1) &
284 + div_v(ixo^s,1,2)*edd(ixo^s,1,2) &
285 + div_v(ixo^s,1,3)*edd(ixo^s,1,3) &
286 + div_v(ixo^s,2,1)*edd(ixo^s,2,1) &
287 + div_v(ixo^s,2,2)*edd(ixo^s,2,2) &
288 + div_v(ixo^s,2,3)*edd(ixo^s,2,3) &
289 + div_v(ixo^s,3,1)*edd(ixo^s,3,1) &
290 + div_v(ixo^s,3,2)*edd(ixo^s,3,2) &
291 + div_v(ixo^s,3,3)*edd(ixo^s,3,3)
295 call gradient(wctprim(ixi^s,iw_r_e),ixi^
l,ixo^
l,idir,tmp,nth_for_fld)
298 tmp(ixo^s) = -a1(ixo^s)*tmp(ixo^s)
300 w(ixo^s,iw_mom(idir)) = w(ixo^s,iw_mom(idir))+ qdt*tmp(ixo^s)
302 w(ixo^s,iw_e) = w(ixo^s,iw_e) + qdt*wctprim(ixo^s,iw_mom(idir))*tmp(ixo^s)
306 w(ixo^s,iw_r_e) = w(ixo^s,iw_r_e) - qdt*wctprim(ixo^s,iw_r_e)*a3(ixo^s)
316 call fl%get_Rfactor(wct,x,ixi^
l,ixo^
l,tmp)
317 a1(ixo^s) = qdt*kappa(ixo^s)*
c_norm*
arad_norm*(fl%gamma-
one)**4/(wct(ixo^s,iw_rho)**3*tmp(ixo^s)**4)
318 a2(ixo^s) =
c_norm*kappa(ixo^s)*wct(ixo^s,iw_rho)*qdt
319 a3(ixo^s) = a3(ixo^s)*qdt
321 c0(ixo^s) = ((
one+a2(ixo^s)+a3(ixo^s))*e_gas(ixo^s)+a2(ixo^s)*e_rad(ixo^s))/a1(ixo^s)/(
one+a3(ixo^s))
322 c1(ixo^s) = (
one+a2(ixo^s)+a3(ixo^s))/a1(ixo^s)/(
one+a3(ixo^s))
325 {
do ix^
d = ixomin^
d,ixomax^
d\}
334 call mpistop(
'root-method not known')
338 e_rad(ixo^s) = (a1(ixo^s)*e_gas(ixo^s)**4.d0+e_rad(ixo^s))/(
one+a2(ixo^s)+a3(ixo^s))
341 {
do ix^db= ixomin^db,ixomax^db\}
343 write(*,*)
"Error in FLD add_fld_rad_force: small value"
344 write(*,*)
"of internal or radiation energy density after exchange"
346 write(*,*)
"Location: ", x(ix^
d,:)
347 write(*,*)
"Cell number: ", ix^
d
348 write(*,*)
"internal energy density is=",e_gas(ix^
d),
" versus small_e=",
small_e
349 write(*,*)
"radiation energy density is=",e_rad(ix^
d),
" versus small_r_e=",
small_r_e
350 call mpistop(
"FLD error:May need to turn on fixes")
355 if(fix_small_values)
then
356 {
do ix^d = ixomin^d,ixomax^d\ }
357 e_gas(ix^d) = max(e_gas(ix^d),small_e)
358 e_rad(ix^d) = max(e_rad(ix^d),small_r_e)
365 w(ixo^s,iw_e) = e_gas(ixo^s)
366 w(ixo^s,iw_e) = w(ixo^s,iw_e)+half*sum(w(ixo^s,iw_mom(:))**2,dim=ndim+1)/w(ixo^s,iw_rho)
367 if(
allocated(iw_mag))
then
368 w(ixo^s,iw_e) = w(ixo^s,iw_e)+half*sum(w(ixo^s,iw_mag(:))**2,dim=ndim+1)
371 w(ixo^s,iw_r_e) = e_rad(ixo^s)
381 integer,
intent(in) :: ixi^
l, ixo^
l
382 double precision,
intent(in) ::
dx^
d, x(ixi^s,1:
ndim), w(ixi^s,1:nw)
383 double precision,
intent(out) :: invtauc(ixi^s)
386 double precision :: dxinv(1:
ndim)
387 double precision :: kappa(ixi^s)
390 ^
d&dxinv(^
d)=one/
dx^
d;
391 invtauc(ixo^s)=4.0d0*minval(dxinv(1:
ndim))/(3.0d0*kappa(ixo^s)*w(ixo^s,iw_rho))
402 integer,
intent(in) :: ixi^
l, ixo^
l
403 double precision,
intent(in) ::
dx^
d, x(ixi^s,1:
ndim), w(ixi^s,1:nw)
404 double precision,
intent(inout) :: dtnew
407 integer :: idim,idims,nth_for_fld
408 double precision :: dxinv(1:
ndim), max_grav
409 double precision :: lambda(ixi^s),fld_r(ixi^s)
410 double precision :: tmp(ixi^s),boostfactor
411 double precision :: max_diff,max_diff_coef,max_diff_dim,dtdifflimit
412 double precision :: cmax(ixi^s),cmaxtot(ixi^s),courantmaxtots
414 if(
fld_debug)print *,
'DT limit on entry to radforce_get_dt=',dtnew
418 ^
d&dxinv(^
d)=one/
dx^
d;
420 call gradient(w(ixi^s,iw_r_e),ixi^
l,ixo^
l,idim,tmp,nth_for_fld)
421 max_grav = maxval(dabs(-lambda(ixo^s)*tmp(ixo^s)/w(ixo^s,iw_rho)))
422 max_grav = max(max_grav, epsilon(1.0d0))
423 dtnew = min(dtnew, 1.0d0 / dsqrt(max_grav * dxinv(idim)))
427 call gradient(w(ixi^s,iw_r_e),ixi^
l,ixo^
l,idim,tmp,nth_for_fld)
428 max_grav = maxval(dabs(-lambda(ixo^s)*tmp(ixo^s)/w(ixo^s,iw_rho))/
block%ds(ixo^s,idim))
429 max_grav = max(max_grav, epsilon(1.0d0))
430 dtnew = min(dtnew, 1.0d0 / dsqrt(max_grav))
433 if(
fld_debug)print *,
'DT limit after RADFORCE eff grav=',dtnew
440 max_diff_coef = maxval(
c_norm*lambda(ixo^s)/(w(ixo^s,iw_rho)*tmp(ixo^s)))
441 ^
d&dxinv(^
d)=one/
dx^
d;
443 max_diff_dim = max(2.0d0*
ndim*max_diff_coef*dxinv(idim)**2, epsilon(1.0d0))
444 max_diff = max(max_diff,max_diff_dim)
448 max_diff_coef = maxval(
c_norm*lambda(ixo^s)/(w(ixo^s,iw_rho)*tmp(ixo^s))/
block%ds(ixo^s,idim)**2)
449 max_diff_dim = max(2.0d0*
ndim*max_diff_coef, epsilon(1.0d0))
450 max_diff = max(max_diff,max_diff_dim)
453 dtdifflimit=1.0d0/max_diff
454 if(
fld_debug) print *,
'DT limit from diffusion is actually=',dtdifflimit
460 dtdifflimit=dtdifflimit*boostfactor
461 if(
fld_debug) print *,
'DT limit from diffusion is boosted to=',dtdifflimit
462 dtnew=min(dtnew,dtdifflimit)
463 if(
fld_debug) print *,
'DT limit after diffusion is =',dtnew
469 ^
d&dxinv(^
d)=one/
dx^
d;
471 cmax(ixo^s)=dabs(w(ixo^s,iw_mom(idims)))+dsqrt(tmp(ixo^s))
473 cmaxtot(ixo^s)=cmax(ixo^s)*dxinv(idims)
475 cmaxtot(ixo^s)=cmaxtot(ixo^s)+cmax(ixo^s)*dxinv(idims)
480 cmax(ixo^s)=dabs(w(ixo^s,iw_mom(idims)))+dsqrt(tmp(ixo^s))
482 cmaxtot(ixo^s)=cmax(ixo^s)/
block%ds(ixo^s,idims)
484 cmaxtot(ixo^s)=cmaxtot(ixo^s)+cmax(ixo^s)/
block%ds(ixo^s,idims)
489 courantmaxtots=maxval(cmaxtot(ixo^s))
491 if(courantmaxtots>smalldouble) dtnew=min(dtnew,
courantpar/courantmaxtots)
492 if(
fld_debug)print *,
'DT limit FINALLY ENFORCED IS NOW=',dtnew
504 integer,
intent(in) :: ixi^
l, ixo^
l
505 double precision,
intent(in) :: w(ixi^s, 1:nw)
506 double precision,
intent(in) :: x(ixi^s, 1:
ndim)
507 double precision,
intent(out) :: fld_kappa(ixi^s)
511 double precision :: rho0,temp0,kapp0
512 double precision :: temp(ixi^s)
520 call fl%get_tgas(w,x,ixi^
l,ixo^
l,temp)
521 {
do ix^
d=ixomin^
d,ixomax^
d\ }
529 call mpistop(
"special opacity not defined")
533 call mpistop(
"Doesn't know opacity law")
541 integer,
intent(in) :: ixi^
l, ixo^
l
542 double precision,
intent(in) :: w(ixi^s, 1:nw)
543 double precision,
intent(in) :: x(ixi^s, 1:
ndim)
544 double precision,
intent(out):: rad_pressure(ixi^s,1:
ndim,1:
ndim)
547 double precision :: eddington_tensor(ixi^s,1:
ndim,1:
ndim)
548 double precision :: lambda(ixi^s),fld_r(ixi^s)
554 print *,
'In get_radPress with nth=',nth,
' on ixO=',ixo^
l
555 print *,
'Max and Min value of fe'
556 print *,maxval(eddington_tensor(ixo^s,1:
ndim,1:
ndim))
557 print *,minval(eddington_tensor(ixo^s,1:
ndim,1:
ndim))
558 print *,
'Max and Min value of Erad'
559 print *,maxval(w(ixo^s,iw_r_e))
560 print *,minval(w(ixo^s,iw_r_e))
561 print *,
'End get_radPress'
565 rad_pressure(ixo^s,i,j) = eddington_tensor(ixo^s,i,j)*w(ixo^s,iw_r_e)
578 integer,
intent(in) :: ixi^
l,ixo^
l,nth
579 double precision,
intent(in) :: w(ixi^s,1:nw)
580 double precision,
intent(in) :: x(ixi^s,1:
ndim)
581 double precision,
intent(out) :: fld_r(ixi^s),fld_lambda(ixi^s)
584 double precision :: wprim(ixi^s,1:nw)
586 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
600 integer,
intent(in) :: ixi^
l,ixo^
l,nth
601 double precision,
intent(in) :: w(ixi^s,1:nw)
602 double precision,
intent(in) :: x(ixi^s,1:
ndim)
603 double precision,
intent(out) :: fld_r(ixi^s),fld_lambda(ixi^s)
606 integer :: idir, ix^
d
607 double precision :: kappa(ixi^s),normgrad2(ixi^s)
608 double precision :: grad_r_e(ixi^s)
613 fld_lambda(ixo^s) = 1.d0/3.d0
617 normgrad2(ixo^s) = zero
619 call gradient(w(ixi^s,iw_r_e),ixi^
l,ixo^
l,idir,grad_r_e,nth)
620 normgrad2(ixo^s) = normgrad2(ixo^s)+grad_r_e(ixo^s)**2
625 fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
626 where(normgrad2(ixo^s)<smalldouble**2)
629 fld_lambda(ixo^s) = 1.0d0/3.0d0
631 fld_lambda(ixo^s) = one/fld_r(ixo^s)
636 normgrad2(ixo^s) = zero
638 call gradient(w(ixi^s,iw_r_e),ixi^
l,ixo^
l,idir,grad_r_e,nth)
639 normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_e(ixo^s)**2
642 fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
645 fld_lambda(ixo^s) = (2.d0+fld_r(ixo^s))/(6.d0+3*fld_r(ixo^s)+fld_r(ixo^s)**2)
649 normgrad2(ixo^s) = zero
651 call gradient(w(ixi^s,iw_r_e),ixi^
l,ixo^
l,idir,grad_r_e,nth)
652 normgrad2(ixo^s) = normgrad2(ixo^s) + grad_r_e(ixo^s)**2
655 fld_r(ixo^s) = dsqrt(normgrad2(ixo^s))/(kappa(ixo^s)*w(ixo^s,iw_rho)*w(ixo^s,iw_r_e))
658 {
do ix^
d = ixomin^
d,ixomax^
d\ }
659 if(fld_r(ix^
d) .lt. 3.d0/2.d0)
then
660 fld_lambda(ix^
d) = 2.d0/(3.d0+dsqrt(9.d0+12.d0*fld_r(ix^
d)**2))
662 fld_lambda(ix^
d) = 1.d0/(1.d0+fld_r(ix^
d)+dsqrt(1.d0+2.d0*fld_r(ix^
d)))
667 call mpistop(
"special fluxlimiter not defined")
671 call mpistop(
'Fluxlimiter unknown')
683 integer,
intent(in) :: ixi^
l, ixo^
l
684 double precision,
intent(in) :: w(ixi^s, 1:nw)
685 double precision,
intent(in) :: x(ixi^s, 1:
ndim)
686 double precision,
intent(out) :: rad_flux(ixi^s, 1:
ndim)
689 integer :: idir,nth_for_fld
690 double precision :: wprim(ixi^s,1:nw)
691 double precision :: grad_r_e(ixi^s)
692 double precision :: kappa(ixi^s), lambda(ixi^s), fld_r(ixi^s)
694 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
704 call gradient(wprim(ixi^s,iw_r_e),ixi^
l,ixo^
l,idir,grad_r_e,nth_for_fld)
705 rad_flux(ixo^s,idir)=-(
c_norm*lambda(ixo^s)/(kappa(ixo^s)*wprim(ixo^s,iw_rho)))*grad_r_e(ixo^s)
714 integer,
intent(in) :: ixI^L, ixO^L, nth
715 double precision,
intent(in) :: w(ixI^S, 1:nw)
716 double precision,
intent(in) :: x(ixI^S, 1:ndim)
717 double precision,
intent(out) :: eddington_tensor(ixI^S,1:ndim,1:ndim)
718 double precision,
intent(out) :: lambda(ixI^S),fld_R(ixI^S)
722 double precision :: normgrad2(ixI^S)
723 double precision :: tmp(ixI^S),grad_r_e(ixI^S,1:ndim)
724 double precision :: nn_regularized(ixI^S,1:ndim,1:ndim)
726 normgrad2(ixo^s) = zero
728 call gradient(w(ixi^s, iw_r_e),ixi^l,ixo^l,idir,tmp,nth)
729 grad_r_e(ixo^s,idir)=tmp(ixo^s)
730 normgrad2(ixo^s)=normgrad2(ixo^s)+tmp(ixo^s)**2
735 nn_regularized(ixo^s,idir,jdir)=(grad_r_e(ixo^s,idir)*grad_r_e(ixo^s,jdir)+smalldouble**2)/(normgrad2(ixo^s)+smalldouble**2)
737 nn_regularized(ixo^s,idir,jdir)=(grad_r_e(ixo^s,idir)*grad_r_e(ixo^s,jdir))/(normgrad2(ixo^s)+smalldouble**2)
744 tmp(ixo^s) = lambda(ixo^s)+(lambda(ixo^s)*fld_r(ixo^s))**2
747 eddington_tensor(ixo^s,idir,idir) = half*(one-tmp(ixo^s))
752 if(idir .ne. jdir) eddington_tensor(ixo^s,idir,jdir) = zero
754 eddington_tensor(ixo^s,idir,jdir) = eddington_tensor(ixo^s,idir,jdir)+&
755 half*(3.d0*tmp(ixo^s)-one)*nn_regularized(ixo^s,idir,jdir)
762 integer,
intent(in) :: ixI^L, ixO^L
763 double precision,
intent(in) :: w(ixI^S, 1:nw)
764 double precision,
intent(out) :: e_gas(ixI^S),E_rad(ixI^S)
768 e_gas(ixo^s) = w(ixo^s,iw_e)-half*sum(w(ixo^s,iw_mom(:))**2,dim=
ndim+1)/w(ixo^s,iw_rho)
769 if(
allocated(iw_mag))
then
770 e_gas(ixo^s) = e_gas(ixo^s)-half*sum(w(ixo^s,iw_mag(:))**2,dim=
ndim+1)
772 e_rad(ixo^s) = w(ixo^s,iw_r_e)
775 {
do ix^db= ixomin^db,ixomax^db\}
777 write(*,*)
"Error in FLD get_egas_Erad: small value"
779 write(*,*)
"Cell number: ", ix^d
780 write(*,*)
"internal energy density is=",e_gas(ix^d),
" versus small_e=",
small_e
781 write(*,*)
"radiation energy density is=",e_rad(ix^d),
" versus small_r_e=",
small_r_e
782 call mpistop(
"FLD error:May need to turn on fixes")
787 if(fix_small_values)
then
788 {
do ix^d = ixomin^d,ixomax^d\ }
789 e_gas(ix^d) = max(e_gas(ix^d),small_e)
790 e_rad(ix^d) = max(e_rad(ix^d),small_r_e)
807 double precision,
intent(in) :: qdt
808 double precision,
intent(in) :: qtc
809 double precision,
intent(in) :: dtfactor
812 integer,
parameter :: max_its = 100
813 integer :: n,ixo^
l,ix^
d
814 double precision :: res, max_residual, mg_lambda, fac
815 double precision :: wmax(nw),wmin(nw)
816 double precision :: wmaxb(nw),wminb(nw)
817 integer :: iigrid, igrid
827 do iigrid=1,igridstail; igrid=igrids(iigrid);
828 {
do ix^
d = ixomin^
d,ixomax^
d\ }
843 print *,
'Currently at time=',
global_time,
' time step=',qdt,
' dtfactor=',dtfactor
844 print *,
'at start of MG solver, we have fld_diff_tol =',
fld_diff_tol
845 print *,
'at start of MG solver, we have LHS E_rad range as :',wmax(iw_r_e),wmin(iw_r_e)
846 print *,
'at start of MG solver, we have Diff coeff range as:',wmax(
i_diff_mg),wmin(
i_diff_mg)
847 print *,
'at start of MG solver, we have density range as :',wmax(iw_rho),wmin(iw_rho)
848 print *,
'at start of MG solver, we have RHS E_rad range as :',wmaxb(iw_r_e),wminb(iw_r_e)
849 print *,
'at start of MG solver, we have qdt as',qdt,
' and max_residual=',max_residual
850 print *,
'at start of MG solver, ratio coeffs on level 1 =',wmax(
i_diff_mg)/(
dx(1,1)**2)
855 call mg_set_methods(
mg)
856 if(.not.
mg%is_allocated)
call mpistop(
"multigrid tree not allocated yet")
864 call vhelmholtz_set_lambda(fac)
874 call mg_restrict(
mg, mg_iveps)
875 call mg_fill_ghost_cells(
mg, mg_iveps)
877 call mg_fas_fmg(
mg, .true., max_res=res)
878 if(
fld_debug.and.
mype==0)print *,
'MG residual obtained with FMG is =',res
880 if(res < max_residual)
exit
881 call mg_fas_vcycle(
mg, max_res=res)
882 if(
fld_debug.and.
mype==0)print *,
'MG residual obtained with Vcycle =',res,
' at step =',n
884 if(
fld_debug.and.
mype==0)print *,
'FINAL MG residual obtained is =',res
885 if(res .ge. max_residual)
then
887 write(*,*)
it,
' residual from MG ', res
888 write(*,*)
it,
' max_residual in MG ', max_residual
889 write(*,*)
it,
' dtfactor*qdt in MG ', qdt*dtfactor
890 print *,
'Currently at time=',
global_time,
' time step=',qdt,
' dtfactor=',dtfactor
893 call mpistop(
"no convergence in MG")
895 if(
mype==0)
write(*,*)
'WARNING for it=',
it,
' NO CONVERGENCE IN MG but still carry on'
903 do iigrid=1,igridstail; igrid=igrids(iigrid);
904 {
do ix^db= ixomin^db,ixomax^db\}
906 write(*,*)
"Error in FLD fld_implicit_update: small value"
907 write(*,*)
"of radiation energy density after MG"
909 write(*,*)
"Location: ", psa(igrid)%x(ix^
d,:),
" on grid",igrid
910 write(*,*)
"Cell number: ", ix^
d
911 write(*,*)
"radiation energy density is=",psa(igrid)%w(ix^
d,iw_r_e),
" versus small_r_e=",
small_r_e
912 call mpistop(
"FLD error:May need to turn on fixes")
918 if(fix_small_values)
then
920 do iigrid=1,igridstail; igrid=igrids(iigrid);
921 {
do ix^d = ixomin^d,ixomax^d\ }
922 psa(igrid)%w(ix^d,iw_r_e)= max(psa(igrid)%w(ix^d,iw_r_e),small_r_e)
931 type(state),
target :: psa(max_blocks)
934 integer :: iigrid, igrid, ixO^L
939 do iigrid=1,igridstail; igrid=igrids(iigrid);
950 double precision,
intent(in) :: qtc
952 integer :: iigrid, igrid
961 do iigrid=1,igridstail; igrid=igrids(iigrid);
972 integer,
intent(in) :: ixI^L, ixO^L
973 double precision,
intent(inout) :: w(ixI^S, 1:nw)
974 double precision,
intent(in) :: x(ixI^S, 1:ndim)
976 double precision :: divF(ixI^S)
977 integer :: idir, jxO^L, hxO^L
979 if(.not.
slab)
call mpistop(
"laplacian coded up for uniform cartesian grid")
986 hxo^l=ixo^l-
kr(idir,^
d);
987 jxo^l=ixo^l+
kr(idir,^
d);
988 divf(ixo^s) = divf(ixo^s) + &
1002 w(ixo^s,iw_r_e) = divf(ixo^s)
1012 integer,
intent(in) :: ixi^
l, ixo^
l
1013 double precision,
intent(in) :: x(ixi^s,1:
ndim)
1014 double precision,
intent(inout) :: w(ixi^s,1:nw)
1017 double precision :: wprim(ixi^s,1:nw)
1018 double precision :: kappa(ixi^s),lambda(ixi^s),fld_r(ixi^s)
1020 wprim(ixi^s,1:nw)=w(ixi^s,1:nw)
1026 w(ixo^s,
i_diff_mg) =
c_norm*lambda(ixo^s)/(kappa(ixo^s)*wprim(ixo^s,iw_rho))
1028 if(minval(w(ixo^s,
i_diff_mg))<smalldouble)
then
1029 print *,
'min diffcoef=',minval(w(ixo^s,
i_diff_mg))
1030 call mpistop(
"too small diffusion coefficient")
1032 if(maxval(w(ixo^s,
i_diff_mg))>bigdouble)
call mpistop(
"too large diffusion coefficient")
1035 print *,
'setting diffcoefs with data on',ixi^
l
1036 print *,
'min diffcoef=',minval(w(ixo^s,
i_diff_mg))
1037 print *,
'min lambda kappa rho fld_R'
1038 print *,minval(lambda(ixo^s))
1039 print *,minval(kappa(ixo^s))
1040 print *,minval(wprim(ixo^s,iw_rho))
1041 print *,minval(fld_r(ixo^s))
1042 print *,
'max diffcoef=',maxval(w(ixo^s,
i_diff_mg))
1043 print *,
'max lambda kappa rho fld_R'
1044 print *,maxval(lambda(ixo^s))
1045 print *,maxval(kappa(ixo^s))
1046 print *,maxval(wprim(ixo^s,iw_rho))
1047 print *,maxval(fld_r(ixo^s))
1048 print *,
'done setting diffcoefs in slot',
i_diff_mg,
' on range',ixo^
l
1057 double precision,
intent(in) :: c0, c1
1058 double precision,
intent(inout) :: e_gas
1059 double precision :: bisect_a, bisect_b, bisect_c
1060 integer :: n, max_its
1065 bisect_b = min(dabs(c0/c1),dabs(c0)**(1.d0/4.d0))+smalldouble
1067 bisect_c = (bisect_a + bisect_b)/two
1069 if(n .gt. max_its)
then
1070 call mpistop(
'No convergece in bisection scheme')
1093 call mpistop(
"Problem with fld bisection method")
1101 if(
fld_debug)print*,
"IGNORING GAS-RAD ENERGY EXCHANGE ", c0, c1
1103 call mpistop(
'issues in bisection scheme')
1112 2435 e_gas = (bisect_a + bisect_b)/two
1118 double precision,
intent(in) :: c0, c1
1119 double precision,
intent(inout) :: e_gas
1120 double precision :: xval, yval, der, deltax
1133 xval = xval + deltax
1135 if(ii .gt. 1d3)
then
1136 if(
fld_debug)print*,
'skip to bisection algorithm'
1147 double precision,
intent(in) :: c0, c1
1148 double precision,
intent(inout) :: e_gas
1149 double precision :: xval, yval, der, dder, deltax
1163 deltax = -two*yval*der/(two*der**2 - yval*dder)
1164 xval = xval + deltax
1166 if(ii .gt. 1d3)
then
1167 if(
fld_debug)print*,
'skip to Newton algorithm'
1178 double precision,
intent(in) :: e_gas
1179 double precision,
intent(in) :: c0, c1
1180 double precision :: val
1182 val = e_gas**4.d0 + c1*e_gas - c0
1188 double precision,
intent(in) :: e_gas
1189 double precision,
intent(in) :: c0, c1
1190 double precision :: der
1192 der = 4.d0*e_gas**3.d0 + c1
1198 double precision,
intent(in) :: e_gas
1199 double precision,
intent(in) :: c0, c1
1200 double precision :: dder
1202 dder = 4.d0*3.d0*e_gas**2.d0
Abstract interface for the gas-EoS getters the radiation fluid needs (same shape as thermal_conductio...
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter one
Module for flux limited diffusion (FLD)-approximation in Radiation-(Magneto)hydrodynamics simulations...
subroutine fld_get_eddington(w, x, ixil, ixol, eddington_tensor, lambda, fld_r, nth, fl)
Calculate Eddington-tensor (where w is primitive) also feeds back the flux limiter lambda and R.
double precision, public fld_bisect_tol
Tolerance for bisection method for Energy sourceterms This is a percentage of the minimum of gas- and...
subroutine, public fld_radforce_get_dt(w, ixil, ixol, dtnew, dxd, x, fl)
get dt limit for radiation force and FLD explicit source additions NOTE: w is primitive on entry
logical fld_force_mg_converged
switches for local debug purposes
double precision, public fld_diff_tol
Tolerance for radiative Energy diffusion.
subroutine update_diffcoeff(psa, fl)
subroutine fld_params_read(files)
public methods these are called in mod_hd_phys or mod_mhd_phys
character(len=40) fld_fluxlimiter
flux limiter choice
subroutine, public fld_get_radflux(w, x, ixil, ixol, rad_flux, fl)
Calculate Radiation Flux NOTE: only for diagnostics purposes (w conservative on entry) This returns c...
character(len=40) fld_opal_table
subroutine, public fld_get_opacity_prim(w, x, ixil, ixol, fld_kappa, fl)
Sets the opacity in the w-array by calling mod_opal_opacity NOTE: assumes primitives in w NOTE: assum...
double precision, public fld_boost_dt
subroutine get_and_check_egas_erad_from_conserved(w, ixil, ixol, e_gas, e_rad)
logical fld_slowsteps
handling ramp-up phase with explicit diffusion dt limit, slowly boosted
double precision, public fld_cnorm
subroutine evaluate_diffterm_onegrid(ixil, ixol, w, x)
inplace update of psa==>F_im(psa)
double precision function ddpolynomial_bisection(e_gas, c0, c1)
Evaluate second derivative of polynomial at argument e_gas.
subroutine, public fld_get_fluxlimiter_prim(w, x, ixil, ixol, fld_lambda, fld_r, nth, fl)
This subroutine calculates flux limiter lambda according to fld_fluxlimiter It also calculates fld_R ...
double precision, public fld_kappa0
Opacity value when using constant opacity.
subroutine newton_method(e_gas, c0, c1)
Find the root of the 4th degree polynomial using the Newton method.
double precision function polynomial_bisection(e_gas, c0, c1)
Evaluate polynomial at argument e_gas.
subroutine, public add_fld_rad_force(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO This subroutine handles th...
character(len=40) fld_opacity_law
switches for opacity
character(len=40) fld_interaction_method
Which method to find the root for the energy interaction polynomial.
subroutine, public fld_set_mg_bounds
Set the boundaries for the diffusion of E.
subroutine, public fld_get_radpress(w, x, ixil, ixol, rad_pressure, fl)
Returns Radiation Pressure as tensor NOTE: w is primitive on entry.
subroutine, public fld_get_local_invtauc(w, ixil, ixol, dxd, x, invtauc, fl)
maybe needed for restricting the cmax/cmin in diffusion limit CURRENTLY UNUSED NOTE: w is primitive o...
logical fld_radforce_split
source split for energy interact and radforce:
logical fld_bound_diff
switches for using changed cmax-cmin bounds
subroutine, public fld_implicit_update(dtfactor, qdt, qtc, psa, psb, fl)
Calling all subroutines to perform the multigrid method Communicates rad_e and diff_coeff to multigri...
subroutine, public fld_get_fluxlimiter(w, x, ixil, ixol, fld_lambda, fld_r, nth, fl)
This subroutine calculates flux limiter lambda according to fld_fluxlimiter It also calculates fld_R ...
double precision function dpolynomial_bisection(e_gas, c0, c1)
Evaluate first derivative of polynomial at argument e_gas.
logical fld_tiring_explicit
switch to handle photon tiring explicit or implicit
subroutine, public fld_get_diffcoef_central(w, x, ixil, ixol, fl)
Calculates cell-centered diffusion coefficient to be used in multigrid.
integer i_diff_mg
diffusion coefficient for multigrid method
subroutine bisection_method(e_gas, c0, c1)
Find the root of the 4th degree polynomial using the bisection method.
subroutine, public fld_evaluate_implicit(qtc, psa, fl)
inplace update of psa==>F_im(psa)
subroutine, public fld_init(gas_eos_type, gas_ion_energy, gas_pi_table)
Initialising FLD-module Read opacities Initialise Multigrid and adimensionalise kappa.
subroutine halley_method(e_gas, c0, c1)
Find the root of the 4th degree polynomial using the Halley method.
integer nth_for_diff_mg
diffusion coefficient stencil control
Module with basic grid data structures.
Module with geometry-related routines (e.g., divergence, curl).
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
double precision const_kappae
double precision arad_norm
Normalised radiation constant.
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
integer, parameter bc_asymm
double precision global_time
The global simulation time.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer it
Number of time steps taken.
integer it_init
initial iteration count
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
integer, parameter ndim
Number of spatial dimensions for grid variables.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision courantpar
The Courant (CFL) number used for the simulation.
integer ixm
the mesh range of a physical block without ghost cells
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
integer slowsteps
If > 1, then in the first slowsteps-1 time steps dt is reduced by a factor .
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision small_r_e
double precision c_norm
Normalised speed of light.
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
integer, parameter bc_cont
logical si_unit
Use SI units (.true.) or use cgs units (.false.).
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer, parameter bc_symm
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical use_multigrid
Use multigrid (only available in 2D and 3D).
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer refine_max_level
Maximal number of AMR levels.
integer max_blocks
The maximum number of grid blocks in a processor.
logical check_small_values
check and optionally fix unphysical small values (density, gas pressure)
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
subroutine mg_copy_to_tree(iw_from, iw_to, restrict, restrict_gc, factor, state_from)
Copy a variable to the multigrid tree, including a layer of ghost cells.
subroutine mg_copy_from_tree_gc(iw_from, iw_to, state_to)
Copy from multigrid tree with one layer of ghost cells. Corner ghost cells are not used/set.
This module reads in Rosseland-mean opacities from OPAL tables. Table opacity values are given in bas...
subroutine, public init_opal_table(tabledir, set_custom_tabledir)
This subroutine is called when the FLD radiation module is initialised. The OPAL tables for different...
subroutine, public set_opal_opacity(rho, temp, kappa)
This subroutine calculates the opacity for a given temperature-density structure. Opacities are read ...
This module defines the procedures of a physics module. It contains function pointers for the various...
procedure(sub_convert), pointer phys_to_primitive
integer phys_wider_stencil
To use wider stencils in flux calculations. A value of 1 will extend it by one cell in both direction...
procedure(sub_set_mg_bounds), pointer phys_set_mg_bounds
procedure(sub_get_csrad2), pointer phys_get_csrad2
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_mg_bc), pointer usr_special_mg_bc
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...
Radiation fluid object: gas-EoS callbacks the FLD module needs, wired by the physics module at link t...