28 double precision,
private :: he_abundance
31 double precision,
private :: rc_gamma
34 double precision,
private :: rc_gamma_1
37 double precision,
private :: invgam
48 integer,
parameter,
private :: n_voigt_table = 500
49 double precision,
parameter,
private :: voigt_logtau_min = -2.0d0
50 double precision,
parameter,
private :: voigt_logtau_max = 8.0d0
51 double precision,
parameter,
private :: voigt_a_ref = 4.7
d-4
52 double precision,
parameter,
private :: voigt_xmax = 6.0d0
55 double precision,
private :: voigt_e_table(n_voigt_table)
56 double precision,
private :: voigt_logtau_step
57 logical,
private :: voigt_table_ready = .false.
62 integer,
intent(in) :: ixI^L, ixO^L
63 double precision,
intent(in) :: w(ixI^S,nw)
64 double precision,
intent(in) :: x(ixI^S,1:ndim)
65 double precision,
intent(out):: res(ixI^S)
70 integer,
intent(in) :: ixI^L, ixO^L
71 double precision,
intent(in) :: w(ixI^S, nw)
72 double precision,
intent(in) :: x(ixI^S, 1:ndim)
73 double precision,
intent(out):: ne(ixI^S), nH(ixI^S)
79 integer,
intent(in) :: ixI^L, ixO^L
80 double precision,
intent(in) :: w(ixI^S,1:nw), x(ixI^S,1:ndim)
81 double precision,
intent(out) :: factor(ixI^S)
86 double precision,
intent(in) :: a, b
92 double precision :: rad_damp_height
93 double precision :: rad_damp_scale
96 double precision,
allocatable :: tcool(:), lcool(:), dldtcool(:)
97 double precision,
allocatable :: yc(:)
98 double precision :: tref, lref, tcoolmin,tcoolmax
99 double precision :: lgtcoolmin, lgtcoolmax, lgstep
103 double precision,
allocatable :: y_ppl(:), t_ppl(:), l_ppl(:), a_ppl(:)
106 double precision :: tlow
125 logical :: isppl = .false.
131 double precision :: rad_suppress_temp = 0.0d0
134 double precision :: suppress_temp_code = 0.0d0
136 logical :: rad_modify
138 logical :: rad_modify_sym
140 double precision :: rad_cut_hgt = 0.0d0
142 double precision :: rad_cut_dey = 0.15d0
144 double precision :: cfrac = 0.1d0
149 logical :: has_equi = .false.
151 logical :: subtract_equi = .false.
153 double precision,
allocatable :: frac_lowfip(:)
157 logical :: rad_newton = .false.
158 double precision :: rad_newton_pthick = 25.d0
159 double precision :: rad_newton_trad = 0.006d0
160 double precision :: rad_newton_rhosurf = 1.d4
163 double precision :: rad_taper_rho
165 double precision :: rad_taper_dey
168 logical :: rad_escape_prob = .false.
170 double precision :: rad_kappa_eff = 0.0d0
172 double precision :: rad_kappa_tcutoff = 0.0d0
174 double precision :: rad_kappa_alpha = 4.0d0
176 character(len=10) :: rad_escape_type =
'slab'
178 double precision :: rad_escape_tau_cutoff = 0.0d0
180 double precision :: rad_escape_height = 0.0d0
182 integer :: iw_colmass_ = -1
184 integer :: iw_mask_ = -1
186 integer :: iw_tracmask_ = -1
189 character(len=std_len) :: coolcurve
191 procedure(
get_subr1),
pointer,
nopass :: get_rho => null()
192 procedure(
get_subr1),
pointer,
nopass :: get_te => null()
193 procedure(
get_subr1),
pointer,
nopass :: get_rho_equi => null()
194 procedure(
get_subr1),
pointer,
nopass :: get_pthermal => null()
195 procedure(
get_subr1),
pointer,
nopass :: get_pthermal_equi => null()
196 procedure(
get_subr1),
pointer,
nopass :: get_var_rfactor => null()
200 procedure(
get_subr1),
pointer,
nopass :: get_temperature_equi => null()
203 logical :: ione = .false.
205 logical :: method_analytic = .false.
206 double precision :: inv_gamma_minus_1
207 double precision :: nh2rhofactor
208 double precision :: eion_per_nh
211 double precision :: log_t_floor = -30.0d0
235 double precision,
allocatable :: y_mod(:,:)
236 double precision,
allocatable :: y_mod_max_per_row(:)
237 integer :: y_mod_n_nh = 0
238 double precision :: y_mod_lg_nh_min = 0.0d0
239 double precision :: y_mod_lg_nh_max = 0.0d0
240 double precision :: y_mod_lg_nh_step_inv = 0.0d0
242 double precision :: y_mod_lg_nh_step = 0.0d0
245 logical :: y_mod_built = .false.
247 double precision :: t_ymod_max = huge(1.0d0)
249 character(len=8) :: y_mod_quadrature =
'boole'
251 integer :: y_mod_n_sub = 16
279 logical :: lambda_needs_nenh_table = .false.
280 double precision,
allocatable :: nenh_eq_table(:)
288 integer,
intent(in) :: ixI^L, ixO^L
289 double precision,
intent(in) :: w(ixI^S,1:nw), x(ixI^S,1:ndim)
291 double precision,
intent(out) :: factor(ixI^S)
293 if(
associated(fl%get_rho2_factor)) &
294 call fl%get_rho2_factor(ixi^l,ixo^l,w,x,factor)
300 double precision,
intent(in) :: phys_gamma,He_abund
303 he_abundance=he_abund
314 integer,
parameter :: nquad = 64
315 double precision :: xq(nquad), wq(nquad)
316 double precision :: logtau, tau0, phi0, gx, integrand, E_val
317 double precision :: a_rep
320 if(voigt_table_ready)
return
323 voigt_logtau_step = (voigt_logtau_max - voigt_logtau_min) / dble(n_voigt_table - 1)
332 phi0 = 1.0d0 / sqrt(dpi)
340 do i = 1, n_voigt_table
341 logtau = voigt_logtau_min + dble(i-1) * voigt_logtau_step
342 tau0 = 10.0d0**logtau
344 if(tau0 < 1.0
d-6)
then
345 voigt_e_table(i) = 1.0d0
353 if(tau0 * gx > 500.0d0)
then
354 integrand = integrand + wq(k) * 1.0d0
355 else if(tau0 * gx < 1.0
d-10)
then
356 integrand = integrand + wq(k) * tau0 * gx
358 integrand = integrand + wq(k) * (1.0d0 - exp(-tau0 * gx))
362 e_val = 2.0d0 * phi0 / tau0 * integrand
364 voigt_e_table(i) = max(0.0d0, min(1.0d0, e_val))
367 voigt_table_ready = .true.
378 double precision,
intent(in) :: a, x
379 double precision :: gauss_part, lorentz_part, phi_x, phi_0
382 phi_0 = 1.0d0 / sqrt(dpi)
387 gauss_part = exp(-x*x) / sqrt(dpi)
388 if(x*x + a*a > 1.0
d-30)
then
389 lorentz_part = a / (dpi * (x*x + a*a))
393 phi_x = gauss_part + lorentz_part
403 double precision,
intent(in) :: tau
404 double precision :: logtau, frac
407 if(tau < 1.0d-6)
then
414 if(logtau <= voigt_logtau_min)
then
419 if(logtau >= voigt_logtau_max)
then
422 * (10.0d0**voigt_logtau_max) / tau
427 frac = (logtau - voigt_logtau_min) / voigt_logtau_step
429 idx = max(1, min(idx, n_voigt_table - 1))
430 frac = frac - dble(idx - 1)
433 + voigt_e_table(idx + 1) * frac
442 double precision,
intent(in) :: a, b
443 integer,
intent(in) :: n
444 double precision,
intent(out) :: x(n), w(n)
445 double precision :: xi, wi, p0, p1, p2, pp, z, z1
446 integer :: i, j, k, m
452 z = cos(dpi * (dble(i) - 0.25d0) / (dble(n) + 0.5d0))
461 p0 = ((2.0d0*dble(k) - 1.0d0) * z * p1 - (dble(k) - 1.0d0) * p2) / dble(k)
464 pp = dble(n) * (z * p0 - p1) / (z*z - 1.0d0)
467 if(abs(z - z1) < 1.0
d-15)
exit
471 xi = 0.5d0 * ((b - a) * z + (b + a))
472 wi = (b - a) / ((1.0d0 - z*z) * pp*pp)
476 x(n + 1 - i) = a + b - xi
485 subroutine read_params(fl)
490 end subroutine read_params
495 double precision,
dimension(:),
allocatable :: t_table
496 double precision,
dimension(:),
allocatable :: L_table
497 double precision,
dimension(:),
allocatable :: f_table
498 double precision :: ratt, fact1, fact2, fact3, dL1, dL2
499 double precision :: tstep, Lstep
500 integer :: ntable, i, j
502 Character(len=65) :: PPL_curves(1:6)
505 fl%coolcurve=
'JCcorona'
509 fl%rad_suppress_temp=0.0d0
511 fl%rad_cut_dey=0.15d0
512 fl%rad_modify=.false.
513 fl%rad_modify_sym=.false.
514 fl%rad_taper_rho=bigdouble
515 fl%rad_taper_dey=0.0d0
517 fl%rad_damp_height=0.5d0
518 fl%rad_damp_scale=0.15d0
522 if(fl%rad_escape_prob .and. fl%rad_escape_type ==
'voigt')
then
525 write(*,
'(A,I0,A,ES9.2,A,F4.1,A)') &
526 ' Voigt escape table: ', n_voigt_table,
' points, a_ref=', &
527 voigt_a_ref,
', x_max=', voigt_xmax,
' Doppler widths'
531 if (fl%fip_ > 0)
then
532 select case (trim(fl%coolcurve))
533 case (
'Dere_photo',
'Dere_photo_DM')
535 call mpistop(
"FIP cooling requires coolcurve='Dere_photo' or 'Dere_photo_DM'")
539 if(fl%rc_split) any_source_split=.true.
542 ppl_curves = [
Character(len=65) ::
'Hildner',
'FM',
'Rosner',
'Klimchuk',
'SPEX_DM_rough',
'SPEX_DM_fine']
543 do i=1,
size(ppl_curves)
544 if (ppl_curves(i)==fl%coolcurve)
then
552 select case(fl%coolcurve)
556 print *,
'Use Hildner (1974) piecewise power law'
558 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
559 allocate(fl%a_PPL(1:fl%n_PPL))
562 fl%l_PPL(1:fl%n_PPL) = 10.d0**
x_hildner(1:
n_hildner) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
566 print *,
'Use Forbes and Malherbe (1991)-like piecewise power law'
568 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
569 allocate(fl%a_PPL(1:fl%n_PPL))
570 fl%t_PPL(1:fl%n_PPL+1) =
t_fm(1:
n_fm+1)
572 fl%l_PPL(1:fl%n_PPL) = 10.d0**
x_fm(1:
n_fm) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
576 print *,
'Use piecewise power law according to Rosner (1978)'
578 print *,
'and extended by Priest (1982) from Van Der Linden (1991)'
580 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
581 allocate(fl%a_PPL(1:fl%n_PPL))
584 fl%l_PPL(1:fl%n_PPL) = 10.d0**
x_rosner(1:
n_rosner) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
588 print *,
'Use Klimchuk (2008) piecewise power law'
590 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
591 allocate(fl%a_PPL(1:fl%n_PPL))
594 fl%l_PPL(1:fl%n_PPL) = 10.d0**
x_klimchuk(1:
n_klimchuk) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
596 case(
'SPEX_DM_rough')
598 print *,
'Use the rough piece wise power law fit to the SPEX_DM curve (2009)'
600 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
601 allocate(fl%a_PPL(1:fl%n_PPL))
608 print *,
'Use the fine, detailed piece wise power law fit to the SPEX_DM curve (2009)'
610 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
611 allocate(fl%a_PPL(1:fl%n_PPL))
617 call mpistop(
"This piecewise power law is unknown")
621 fl%t_PPL(1:fl%n_PPL+1) = 10.d0**fl%t_PPL(1:fl%n_PPL+1)
623 if (si_unit) fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * 10.0d0**(-13)
626 fl%t_PPL(1:fl%n_PPL+1) = fl%t_PPL(1:fl%n_PPL+1) / unit_temperature
627 fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * unit_numberdensity**2 * unit_time / unit_pressure
630 fl%l_PPL(fl%n_PPL+1) = fl%l_PPL(fl%n_PPL) * ( fl%t_PPL(fl%n_PPL+1) / fl%t_PPL(fl%n_PPL) )**fl%a_PPL(fl%n_PPL)
631 fl%lref = fl%l_PPL(fl%n_PPL+1)
632 fl%tref = fl%t_PPL(fl%n_PPL+1)
635 fl%tcoolmin = fl%t_PPL(1)
636 fl%tcoolmax = fl%t_PPL(fl%n_PPL+1)
638 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
645 allocate(fl%tcool(1:fl%ncool), fl%Lcool(1:fl%ncool), fl%dLdtcool(1:fl%ncool))
646 allocate(fl%Yc(1:fl%ncool))
647 if(fl%fip_ > 0)
allocate(fl%frac_lowFIP(1:fl%ncool))
649 fl%tcool(1:fl%ncool) = zero
650 fl%Lcool(1:fl%ncool) = zero
651 fl%dLdtcool(1:fl%ncool) = zero
654 select case(fl%coolcurve)
658 print *,
'Use Colgan & Feldman (2008) cooling curve'
660 print *,
'This version only till 10000 K, beware for floor T treatment'
662 allocate(t_table(1:ntable))
663 allocate(l_table(1:ntable))
669 print *,
'Use Dalgarno & McCray (1972) cooling curve'
671 allocate(t_table(1:ntable))
672 allocate(l_table(1:ntable))
678 write(*,
'(3a)')
'Use MacDonald & Bailey (1981) cooling curve '&
679 ,
'as implemented in ZEUS-3D, with the values '&
680 ,
'from Dalgarno & McCRay (1972) for low temperatures.'
682 allocate(t_table(1:ntable))
683 allocate(l_table(1:ntable))
684 t_table(1:ntable) =
t_dm(1:21)
685 l_table(1:ntable) =
l_dm(1:21)
691 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
692 ,
'for zero metallicity '
694 allocate(t_table(1:ntable))
695 allocate(l_table(1:ntable))
701 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
702 ,
'for WC-star metallicity '
704 allocate(t_table(1:ntable))
705 allocate(l_table(1:ntable))
711 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
712 ,
'for solar metallicity '
714 allocate(t_table(1:ntable))
715 allocate(l_table(1:ntable))
721 print *,
'Use Cloudy based cooling curve '&
722 ,
'for ism metallicity '
724 allocate(t_table(1:ntable))
725 allocate(l_table(1:ntable))
731 print *,
'Use Cloudy based cooling curve '&
732 ,
'for solar metallicity '
734 allocate(t_table(1:ntable))
735 allocate(l_table(1:ntable))
739 case(
'composite_solar')
741 print *,
'Use composite cooling curve for solar metallicity:'
742 print *,
' T > 12 kK: Dere/Colgan/SPEX weighted average'
743 print *,
' 7-12 kK: SPEX CIE through the Lya transition'
744 print *,
' T < 7 kK: cloudy_solar fine-structure/molecular'
747 allocate(t_table(1:ntable))
748 allocate(l_table(1:ntable))
754 print *,
'Use SPEX cooling curve (Schure et al. 2009) '&
755 ,
'for solar metallicity '
757 allocate(t_table(1:ntable))
758 allocate(l_table(1:ntable))
769 fl%lambda_needs_nenh_table = .true.
773 print *,
'Use SPEX cooling curve for solar metallicity above 10^4 K. '
774 print *,
'At lower temperatures,use Dalgarno & McCray (1972), '
775 print *,
'with a pre-set ionization fraction of 10^-3. '
776 print *,
'as described by Schure et al. (2009). '
779 allocate(t_table(1:ntable))
780 allocate(l_table(1:ntable))
793 fl%lambda_needs_nenh_table = .true.
797 print *,
'Use Dere (2009) cooling curve for solar corona'
799 allocate(t_table(1:ntable))
800 allocate(l_table(1:ntable))
804 case(
'Dere_corona_DM')
806 print *,
'Combination of Dere_corona (2009) for high temperatures and'
808 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
810 allocate(t_table(1:ntable))
811 allocate(l_table(1:ntable))
819 print *,
'Use Dere (2009) cooling curve for solar photophere'
821 allocate(t_table(1:ntable))
822 allocate(l_table(1:ntable))
823 if (fl%fip_ > 0)
allocate(f_table(1:ntable))
828 case(
'Dere_photo_DM')
830 print *,
'Combination of Dere_photo (2009) for high temperatures and'
832 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
834 allocate(t_table(1:ntable))
835 allocate(l_table(1:ntable))
836 if (fl%fip_ > 0)
allocate(f_table(1:ntable))
841 if (fl%fip_ > 0)
then
842 f_table(1:
n_dm_2-1) = zero
848 print *,
'Use Colgan (2008) cooling curve'
850 allocate(t_table(1:ntable))
851 allocate(l_table(1:ntable))
857 print *,
'Combination of Colgan (2008) for high temperatures and'
859 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
861 allocate(t_table(1:ntable))
862 allocate(l_table(1:ntable))
869 call mpistop(
"This coolingcurve is unknown")
874 fl%tcoolmax = t_table(ntable)
875 fl%tcoolmin = t_table(1)
876 ratt = (fl%tcoolmax-fl%tcoolmin)/( dble(fl%ncool-1) + smalldouble)
878 fl%tcool(1) = fl%tcoolmin
879 fl%Lcool(1) = l_table(1)
881 fl%tcool(fl%ncool) = fl%tcoolmax
882 fl%Lcool(fl%ncool) = l_table(ntable)
884 if (fl%fip_ > 0)
then
885 fl%frac_lowFIP(1) = f_table(1)
886 fl%frac_lowFIP(fl%ncool) = f_table(ntable)
890 fl%tcool(i) = fl%tcool(i-1)+ratt
894 if(fl%tcool(i) < t_table(j+1))
then
895 if(j.eq. ntable-1 )
then
896 fact1 = (fl%tcool(i)-t_table(j+1)) &
897 /(t_table(j)-t_table(j+1))
898 fact2 = (fl%tcool(i)-t_table(j)) &
899 /(t_table(j+1)-t_table(j))
900 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
901 if (fl%fip_ > 0)
then
902 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
906 dl1 = l_table(j+1)-l_table(j)
907 dl2 = l_table(j+2)-l_table(j+1)
908 jump =(max(dabs(dl1),dabs(dl2)) > 2*min(dabs(dl1),dabs(dl2)))
911 fact1 = (fl%tcool(i)-t_table(j+1)) &
912 /(t_table(j)-t_table(j+1))
913 fact2 = (fl%tcool(i)-t_table(j)) &
914 /(t_table(j+1)-t_table(j))
915 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
916 if (fl%fip_ > 0)
then
917 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
921 fact1 = ((fl%tcool(i)-t_table(j+1)) &
922 * (fl%tcool(i)-t_table(j+2))) &
923 / ((t_table(j)-t_table(j+1)) &
924 * (t_table(j)-t_table(j+2)))
925 fact2 = ((fl%tcool(i)-t_table(j)) &
926 * (fl%tcool(i)-t_table(j+2))) &
927 / ((t_table(j+1)-t_table(j)) &
928 * (t_table(j+1)-t_table(j+2)))
929 fact3 = ((fl%tcool(i)-t_table(j)) &
930 * (fl%tcool(i)-t_table(j+1))) &
931 / ((t_table(j+2)-t_table(j)) &
932 * (t_table(j+2)-t_table(j+1)))
933 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2 &
935 if (fl%fip_ > 0)
then
936 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2 &
946 fl%tcool(1:fl%ncool) = 10.0d0**fl%tcool(1:fl%ncool)
947 fl%Lcool(1:fl%ncool) = 10.0d0**fl%Lcool(1:fl%ncool)
950 if (si_unit) fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * 10.0d0**(-13)
953 fl%tcool(1:fl%ncool) = fl%tcool(1:fl%ncool) / unit_temperature
954 fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * unit_numberdensity**2 * unit_time / unit_pressure
956 fl%tcoolmin = fl%tcool(1)+smalldouble
958 if(fl%rad_suppress_temp > 0.0d0)
then
959 fl%suppress_temp_code = fl%rad_suppress_temp / unit_temperature
961 write(*,
'(A,ES10.3,A)')
' Cooling suppression active: disabled below T = ', &
962 fl%rad_suppress_temp,
' K within rad_cut_hgt'
966 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
967 fl%tcoolmax = fl%tcool(fl%ncool)
968 fl%lgtcoolmin = dlog10(fl%tcoolmin)
969 fl%lgtcoolmax = dlog10(fl%tcoolmax)
970 fl%lgstep = (fl%lgtcoolmax-fl%lgtcoolmin) * 1.d0 / (fl%ncool-1)
971 fl%dLdtcool(1) = (fl%Lcool(2)-fl%Lcool(1))/(fl%tcool(2)-fl%tcool(1))
972 fl%dLdtcool(fl%ncool) = (fl%Lcool(fl%ncool)-fl%Lcool(fl%ncool-1))/(fl%tcool(fl%ncool)-fl%tcool(fl%ncool-1))
975 fl%dLdtcool(i) = (fl%Lcool(i+1)-fl%Lcool(i-1))/(fl%tcool(i+1)-fl%tcool(i-1))
980 if (
allocated(f_table))
deallocate(f_table)
982 fl%tref = fl%tcoolmax
983 fl%lref = fl%Lcool(fl%ncool)
984 fl%Yc(fl%ncool) = zero
985 do i=fl%ncool-1, 1, -1
986 fl%Yc(i) = fl%Yc(i+1)
988 tstep = 1.0d-2*(fl%tcool(i+1)-fl%tcool(i))
989 call findl(fl%tcool(i+1)-j*tstep, lstep, fl)
990 fl%Yc(i) = fl%Yc(i) + fl%lref/fl%tref*tstep/lstep
995 rc_gamma_1=rc_gamma-1.d0
996 invgam = 1.d0/rc_gamma_1
1006 double precision :: y_extra, factor
1009 allocate(fl%y_PPL(1:fl%n_PPL+1))
1011 fl%y_PPL(1:fl%n_PPL+1) = zero
1013 do i=fl%n_PPL, 1, -1
1014 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
1015 if (fl%a_PPL(i) == 1.d0)
then
1016 y_extra = log( fl%t_PPL(i) / fl%t_PPL(i+1) )
1018 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / fl%t_PPL(i+1) )**(fl%a_PPL(i)-1) )
1020 fl%y_PPL(i) = fl%y_PPL(i+1) - factor*y_extra
1031 integer,
intent(in) :: ixI^L,ixO^L
1032 double precision,
intent(in) :: x(ixI^S,1:ndim)
1033 double precision :: w(ixI^S,1:nw)
1034 double precision,
intent(out):: coolrate(ixI^S)
1037 double precision :: rho(ixI^S)
1038 double precision :: L1,Te(ixI^S),Rfactor(ixI^S)
1039 double precision :: ne(ixI^S), nH_arr(ixI^S), rho2_factor(ixI^S)
1040 double precision :: taper
1043 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1044 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
1045 call fl%get_Te(w,x,ixi^l,ixo^l,te)
1046 call fl%get_ne_nH(ixi^l, ixo^l, w, x, ne, nh_arr)
1049 {
do ix^db = ixo^lim^db\}
1051 if(te(ix^d) <= fl%tcoolmin)
then
1053 else if(te(ix^d) >= fl%tcoolmax)
then
1055 l1 = l1*ne(ix^d)*nh_arr(ix^d)
1057 call findl(te(ix^d),l1,fl)
1058 l1 = l1*ne(ix^d)*nh_arr(ix^d)
1060 if(
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height)
then
1061 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1066 coolrate(ix^d) = l1*rho2_factor(ix^d)
1074 integer,
intent(in) :: ixI^L, ixO^L
1075 double precision,
intent(in) :: qdt, x(ixI^S, 1:ndim), wCT(ixI^S, 1:nw)
1076 double precision :: w(ixI^S, 1:nw)
1077 double precision,
intent(out) :: coolrate(ixI^S)
1079 double precision :: y1, y2, l1, tlocal2
1080 double precision :: Te(ixI^S), pnew(ixI^S), rho(ixI^S), rhonew(ixI^S)
1081 double precision :: emin, Lmax, fact, Rfactor(ixI^S), pth(ixI^S)
1082 double precision :: ne(ixI^S), nH_arr(ixI^S), rho2_factor(ixI^S)
1083 double precision :: taper
1085 double precision :: nH_val, log_nH, log_p_nH
1086 double precision :: eint_current
1087 double precision :: y_l, T_l
1090 call fl%get_pthermal(wct, x, ixi^l, ixo^l, pth)
1091 call fl%get_rho(wct, x, ixi^l, ixo^l, rho)
1092 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1093 call fl%get_Te(wct, x, ixi^l, ixo^l, te)
1094 call fl%get_ne_nH(ixi^l, ixo^l, wct, x, ne, nh_arr)
1098 call fl%get_pthermal(w, x, ixi^l, ixo^l, pnew)
1099 call fl%get_rho(w, x, ixi^l, ixo^l, rhonew)
1101 fact=fl%lref*qdt/fl%tref
1103 {
do ix^db = ixo^lim^db\}
1104 emin = rhonew(ix^d) * fl%tlow * rfactor(ix^d) * invgam
1106 nh_val = rhonew(ix^d) / fl%nH2rhoFactor
1107 log_nh = dlog10(nh_val)
1109 if (fl%method_analytic)
then
1111 y_l = wct(ix^d, iw_ne) / nh_val
1112 eint_current = fl%inv_gamma_minus_1 * (1.0d0 + y_l) * nh_val * t_l &
1113 + y_l * fl%eion_per_nH * nh_val
1116 log_p_nh = dlog10(pnew(ix^d) / nh_val)
1117 eint_current = pnew(ix^d) * fl%p2eint(log_nh, log_p_nh)
1119 lmax = max(zero, (eint_current - emin) / qdt)
1121 lmax = max(zero, ( pnew(ix^d)*invgam - emin ) / qdt)
1126 if( te(ix^d)<= fl%tcoolmin)
then
1128 else if( te(ix^d)>= fl%tcoolmax )
then
1130 if (fl%lambda_needs_nenh_table)
then
1131 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1133 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1135 l1 = min(l1*rho2_factor(ix^d), lmax)
1139 call findy(te(ix^d), y1, fl)
1140 if (fl%lambda_needs_nenh_table)
then
1141 y2 = y1 + rho2_factor(ix^d)*fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1142 / (rho(ix^d) * rfactor(ix^d))
1144 y2 = y1 + rho2_factor(ix^d)*fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1145 / (rho(ix^d) * rfactor(ix^d))
1147 call findt(tlocal2, y2, fl)
1149 if (fl%Y_mod_built .and.
rc_variable_cv(fl, te(ix^d), tlocal2))
then
1150 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1151 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1152 y2 = y1 + rho2_factor(ix^d)*qdt
1153 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1157 if( tlocal2 <= fl%tcoolmin )
then
1161 l1 = ((fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1162 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val) / qdt
1166 l1 = (te(ix^d)- tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam/qdt
1173 if(
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height)
then
1174 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1181 qsourcesplit,active,fl)
1184 integer,
intent(in) :: ixI^L, ixO^L
1185 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
1186 double precision,
intent(inout) :: w(ixI^S,1:nw)
1187 logical,
intent(in) :: qsourcesplit
1188 logical,
intent(inout) :: active
1190 double precision,
allocatable,
dimension(:^D&) :: Lequi
1191 double precision :: lb_t0_cool
1194 if(qsourcesplit .eqv.fl%rc_split)
then
1196 call cool_exact(qdt,ixi^l,ixo^l,wct,wctprim,w,x,fl)
1197 if(fl%subtract_equi)
then
1198 allocate(lequi(ixi^s))
1200 w(ixo^s,fl%e_) = w(ixo^s,fl%e_)+lequi(ixo^s)
1211 integer,
intent(in) :: ixI^L, ixO^L
1212 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
1213 double precision,
intent(inout) :: w(ixI^S,1:nw)
1215 double precision :: etherm(ixI^S), rho(ixI^S), Rfactor(ixI^S),emin
1216 double precision :: nH_val, log_nH, eint_floor, eint_current
1219 call fl%get_pthermal(w,x,ixi^l,ixo^l,etherm)
1220 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1221 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1222 {
do ix^db = ixo^lim^db\}
1223 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)
1224 if(etherm(ix^d) < emin)
then
1225 if (fl%ionE .and. .not. fl%method_analytic)
then
1227 nh_val = rho(ix^d) / fl%nH2rhoFactor
1228 log_nh = dlog10(nh_val)
1230 eint_current = etherm(ix^d) * fl%p2eint(log_nh, dlog10(etherm(ix^d)/nh_val))
1231 w(ix^d,fl%e_)=w(ix^d,fl%e_)+max(eint_floor-eint_current, zero)
1233 w(ix^d,fl%e_)=w(ix^d,fl%e_)+(emin-etherm(ix^d))*invgam
1244 integer,
intent(in) :: ix^
d
1245 double precision,
intent(in) :: te_val
1248 if(fl%iw_tracmask_ > 0)
then
1249 if(
block%wextra(ix^
d, fl%iw_tracmask_) <= 0.5d0)
return
1251 if(te_val <
block%wextra(ix^
d,fl%Tcoff_)) &
1259 double precision,
intent(in) :: t1, t2
1260 rc_variable_cv = fl%ionE .and. dabs(t1 - t2) > 1.0d-4 * t1 .and. t1 < fl%T_Ymod_max
1266 double precision,
intent(in) :: log_nh, nh_val
1267 rc_eint_floor = fl%eint_from_T(log_nh, max(dlog10(fl%tlow), fl%log_T_floor)) * nh_val
1275 integer,
intent(in) :: ix^D
1276 double precision,
intent(in) :: x_ndim, rho_val, Te_val, Rf_val
1278 double precision,
intent(out) :: factor
1279 double precision :: d_boundary, tau, kappa_local
1283 if(fl%iw_mask_ > 0)
then
1285 factor = max(0.0d0,
block%wextra(ix^d, fl%iw_mask_))
1286 if(factor == 0.0d0)
return
1291 factor = factor * rt_sc_thin_weight(te_val, x_ndim, rho_val*te_val*rf_val)
1296 if(fl%rad_modify_sym)
then
1297 d_boundary = min(x_ndim - xprobmin^nd, xprobmax^nd - x_ndim)
1299 d_boundary = x_ndim - xprobmin^nd
1301 if(d_boundary .le. fl%rad_cut_hgt)
then
1302 if(fl%suppress_temp_code > 0.0d0)
then
1305 if(te_val .lt. fl%suppress_temp_code)
then
1311 factor = factor * exp(-((d_boundary - fl%rad_cut_hgt) / fl%rad_cut_dey)**2)
1316 if(rho_val .gt. fl%rad_taper_rho)
then
1317 factor = factor * exp(-((rho_val - fl%rad_taper_rho) / fl%rad_taper_dey)**2)
1323 if(fl%rad_escape_prob .and. fl%iw_colmass_ > 0)
then
1324 kappa_local = fl%rad_kappa_eff
1325 if(fl%rad_kappa_Tcutoff > 0.0d0)
then
1326 kappa_local = kappa_local &
1327 / (1.0d0 + (te_val / fl%rad_kappa_Tcutoff)**fl%rad_kappa_alpha)
1329 tau = kappa_local *
block%wextra(ix^d, fl%iw_colmass_)
1330 if(tau > 1.0d-6)
then
1331 select case(fl%rad_escape_type)
1334 factor = factor * (1.0d0 - exp(-tau)) / tau
1340 call mpistop(
"Unknown rad_escape_type: use 'slab' or 'voigt'")
1344 if(fl%rad_escape_tau_cutoff > 0.0d0)
then
1345 factor = factor * exp(-tau / fl%rad_escape_tau_cutoff)
1354 integer,
intent(in) :: ixI^L, ixO^L
1355 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
1356 double precision,
intent(inout) :: w(ixI^S,1:nw)
1358 double precision,
intent(out) :: res(ixI^S)
1360 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),L1,Tlocal2
1361 double precision :: Te(ixI^S)
1362 double precision :: emin, Lmax
1363 double precision :: Y1, Y2
1364 double precision :: de, emax,fact
1365 double precision :: ne(ixI^S), nH_arr(ixI^S), rho2_factor(ixI^S)
1366 double precision :: taper
1368 double precision :: nH_val, log_nH, log_p_nH
1369 double precision :: eint_current
1370 double precision :: y_l, T_l
1373 call fl%get_pthermal_equi(wct,x,ixi^l,ixo^l,pth)
1374 call fl%get_rho_equi(wct,x,ixi^l,ixo^l,rho)
1375 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1378 call fl%get_temperature_equi(wct,x,ixi^l,ixo^l,te)
1379 call fl%get_ne_nH_equi(ixi^l, ixo^l, wct, x, ne, nh_arr)
1384 fact = fl%lref*qdt/fl%tref
1385 {
do ix^db = ixo^lim^db\}
1386 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)*invgam
1388 nh_val = rho(ix^d) / fl%nH2rhoFactor
1389 log_nh = dlog10(nh_val)
1391 if (fl%method_analytic)
then
1393 y_l = wct(ix^d, iw_ne) / nh_val
1394 eint_current = 1.5d0 * (1.0d0 + y_l) * nh_val * t_l &
1395 + y_l * fl%eion_per_nH * nh_val
1398 log_p_nh = dlog10(pth(ix^d) / nh_val)
1399 eint_current = pth(ix^d) * fl%p2eint(log_nh, log_p_nh)
1401 lmax = max(zero, (eint_current - emin) / qdt)
1402 emax = max(zero, eint_current - emin)
1404 lmax = max(zero,(pth(ix^d)*invgam-emin)/qdt)
1405 emax = max(zero, pth(ix^d)*invgam-emin)
1412 if( te(ix^d)<=fl%tcoolmin )
then
1414 else if( te(ix^d)>=fl%tcoolmax )
then
1416 if (fl%lambda_needs_nenh_table)
then
1417 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1419 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1422 l1 = min(rho2_factor(ix^d)*l1,lmax)
1428 call findy(te(ix^d),y1,fl)
1429 if (fl%lambda_needs_nenh_table)
then
1430 y2 = y1 + rho2_factor(ix^d)*fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1431 / (rho(ix^d) * rfactor(ix^d))
1433 y2 = y1 + rho2_factor(ix^d)*fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1434 / (rho(ix^d) * rfactor(ix^d))
1436 call findt(tlocal2,y2,fl)
1438 if (fl%Y_mod_built .and.
rc_variable_cv(fl, te(ix^d), tlocal2))
then
1439 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1440 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1441 y2 = y1 + rho2_factor(ix^d)*qdt
1442 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1446 if(tlocal2<=fl%tcoolmin)
then
1449 de = (fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1450 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val
1453 de = (te(ix^d)-tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
1461 res(ix^d) = res(ix^d) * taper
1469 integer,
intent(in) :: ixI^L, ixO^L
1470 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
1471 double precision,
intent(inout) :: w(ixI^S,1:nw)
1473 double precision :: Y1, Y2
1474 double precision :: L1, pth(ixI^S), Tlocal2, pnew(ixI^S)
1475 double precision :: rho(ixI^S), Te(ixI^S), rhonew(ixI^S), Rfactor(ixI^S)
1476 double precision :: emin, Lmax, fact
1477 double precision :: de, emax
1478 double precision :: ne(ixI^S), nH_arr(ixI^S), rho2_factor(ixI^S)
1479 double precision :: taper
1481 double precision :: nH_val, log_nH
1482 double precision :: eint_w(ixI^S)
1483 double precision :: de_thin, de_thick, emax_rem
1484 double precision :: T1, T2, p1(ixI^S), tau, xi
1485 double precision :: xi_arr(ixI^S), emax_rem_arr(ixI^S)
1486 double precision :: cool_fac, fip_prim, frac_lowFIP, fip_factor
1489 call fl%get_rho(wct,x,ixi^l,ixo^l,rho)
1490 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1491 call fl%get_Te(wct,x,ixi^l,ixo^l,te)
1492 call fl%get_ne_nH(ixi^l, ixo^l, wct, x, ne, nh_arr)
1494 call fl%get_pthermal(w,x,ixi^l,ixo^l,pnew)
1495 call fl%get_rho(w,x,ixi^l,ixo^l,rhonew)
1496 if (fl%ionE) eint_w(ixo^s) =
phys_get_ei(w, ixi^l, ixo^l)
1498 fact = fl%lref*qdt/fl%tref
1502 {
do ix^db = ixo^lim^db\}
1503 emin = rhonew(ix^d)*fl%tlow*rfactor(ix^d)*invgam
1506 nh_val = rhonew(ix^d) / fl%nH2rhoFactor
1507 log_nh = dlog10(nh_val)
1510 if (.not. fl%method_analytic) emin =
rc_eint_floor(fl, log_nh, nh_val)
1511 lmax = max(zero, eint_w(ix^d) - emin) / qdt
1512 emax = max(zero, eint_w(ix^d) - emin)
1514 lmax = max(zero,pnew(ix^d)*invgam-emin)/qdt
1515 emax = max(zero,pnew(ix^d)*invgam-emin)
1519 if (te(ix^d) <= fl%tcoolmin) cycle
1524 if (fl%rad_newton)
then
1525 xi = exp(-pnew(ix^d) / fl%rad_newton_pthick)
1526 xi = min(max(xi, zero), one)
1530 cool_fac = xi*rho2_factor(ix^d)
1532 if (fl%fip_ > 0)
then
1533 fip_prim = min(
maxfip, max(
minfip, wctprim(ix^d,fl%fip_)))
1536 fip_factor = one - frac_lowfip + fip_prim * frac_lowfip
1537 cool_fac = cool_fac * fip_factor
1541 if (
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) <= xprobmin1 + fl%rad_damp_height)
then
1542 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmin1-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1545 if (
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) >= xprobmax1 - fl%rad_damp_height)
then
1546 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmax1+fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1550 if( te(ix^d)>=fl%tcoolmax )
then
1552 if (fl%lambda_needs_nenh_table)
then
1553 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1555 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1564 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
1572 call findy(te(ix^d),y1,fl)
1573 if (fl%lambda_needs_nenh_table)
then
1574 y2 = y1 + cool_fac * fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1575 / (rho(ix^d) * rfactor(ix^d))
1577 y2 = y1 + cool_fac * fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1578 / (rho(ix^d) * rfactor(ix^d))
1580 call findt(tlocal2,y2,fl)
1585 if (fl%Y_mod_built .and.
rc_variable_cv(fl, te(ix^d), tlocal2))
then
1586 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1587 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1588 y2 = y1 + cool_fac * qdt
1589 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1593 if(tlocal2<=fl%tcoolmin)
then
1597 de = (fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1598 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val
1602 de = (te(ix^d)-tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
1610 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
1614 if (fl%rad_newton)
then
1616 emax_rem_arr(ix^d) = max(zero, emax - de_thin)
1621 if (fl%rad_newton)
then
1622 call fl%get_pthermal(w, x, ixi^l, ixo^l, p1)
1623 {
do ix^db = ixo^lim^db\}
1624 t1 = p1(ix^d) / (rho(ix^d) * rfactor(ix^d))
1625 tau = max(0.1d0 * sqrt( fl%rad_newton_rhosurf / rho(ix^d)), 4.d0 * qdt)
1626 t2 = fl%rad_newton_trad + (t1 - fl%rad_newton_trad) * exp(-qdt / tau)
1627 de_thick = min((one - xi_arr(ix^d)) * (t1 - t2) * rho(ix^d) * rfactor(ix^d) * invgam, emax_rem_arr(ix^d))
1628 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thick
1637 double precision,
intent(IN) :: tpoint
1638 double precision,
intent(OUT) :: lpoint
1642 lpoint =fl%l_PPL(fl%n_PPL) * ( tpoint / fl%t_PPL(fl%n_PPL) )**fl%a_PPL(fl%n_PPL)
1644 lpoint = fl%Lcool(fl%ncool) * sqrt( tpoint / fl%tcoolmax)
1651 double precision,
intent(in) :: tpoint
1654 double precision :: lgtp
1657 if (tpoint <= fl%tcool(1))
then
1660 else if (tpoint >= fl%tcool(fl%ncool))
then
1665 lgtp = dlog10(tpoint)
1666 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
1667 jl = max(1, min(fl%ncool-1, jl))
1670 + (tpoint - fl%tcool(jl)) &
1671 * (fl%frac_lowFIP(jl+1) - fl%frac_lowFIP(jl)) &
1672 / (fl%tcool(jl+1) - fl%tcool(jl))
1680 double precision,
intent(IN) :: tpoint
1681 double precision,
intent(OUT) :: Lpoint
1684 double precision :: lgtp
1688 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
1689 lpoint = fl%l_PPL(i) * (tpoint / fl%t_PPL(i))**fl%a_PPL(i)
1691 lgtp = dlog10(tpoint)
1692 jl = int((lgtp - fl%lgtcoolmin) /fl%lgstep) + 1
1693 lpoint = fl%Lcool(jl)+ (tpoint-fl%tcool(jl)) &
1694 * (fl%Lcool(jl+1)-fl%Lcool(jl)) &
1695 / (fl%tcool(jl+1)-fl%tcool(jl))
1698 end subroutine findl
1704 double precision,
intent(IN) :: tpoint
1705 double precision,
intent(OUT) :: Ypoint
1708 double precision :: lgtp
1709 double precision :: y_extra,factor
1713 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
1714 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
1715 if(fl%a_PPL(i)==1.d0)
then
1716 y_extra = log( fl%t_PPL(i) / tpoint )
1718 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / tpoint )**(fl%a_PPL(i)-1) )
1720 ypoint = fl%y_PPL(i) + factor*y_extra
1722 lgtp = dlog10(tpoint)
1723 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
1725 if(jl < 1 .or. jl >= fl%ncool)
then
1726 write(*,
'(a,es14.6,a,i0,a,2es14.6)') &
1727 'findY: tpoint=',tpoint,
' jl=',jl,
' out of bounds [1,ncool-1]; tcoolmin/max=', &
1728 fl%tcoolmin,fl%tcoolmax
1729 call mpistop(
'findY: temperature index out of bounds')
1731 ypoint = fl%Yc(jl)+ (tpoint-fl%tcool(jl)) &
1732 * (fl%Yc(jl+1)-fl%Yc(jl)) &
1733 / (fl%tcool(jl+1)-fl%tcool(jl))
1736 end subroutine findy
1745 double precision,
intent(OUT) :: tpoint
1746 double precision,
intent(IN) :: Ypoint
1749 double precision :: factor
1750 integer :: jl,jc,jh,i
1753 i = minloc(fl%y_PPL, dim=1, mask=fl%y_PPL>ypoint)
1754 factor = fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1) / (fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i))
1755 if(fl%a_PPL(i)==1.d0)
then
1756 tpoint = fl%t_PPL(i) * exp( -1.d0 * factor * ( ypoint - fl%y_PPL(i)))
1758 tpoint = fl%t_PPL(i) * (1 - (1 - fl%a_PPL(i)) * factor * (ypoint - fl%y_PPL(i)))**(1 / (1 - fl%a_PPL(i)))
1761 if(ypoint >= fl%Yc(1))
then
1762 tpoint = fl%tcoolmin
1763 else if (ypoint == fl%Yc(fl%ncool))
then
1764 tpoint = fl%tcoolmax
1771 if(ypoint <= fl%Yc(jc))
then
1778 tpoint = fl%tcool(jl)+ (ypoint-fl%Yc(jl)) &
1779 * (fl%tcool(jl+1)-fl%tcool(jl)) &
1780 / (fl%Yc(jl+1)-fl%Yc(jl))
1783 end subroutine findt
1791 double precision,
intent(IN) :: tpoint
1792 double precision,
intent(OUT) :: dLpoint
1795 double precision :: lgtp
1798 lgtp = dlog10(tpoint)
1799 jl = int((lgtp -fl%lgtcoolmin) / fl%lgstep) + 1
1800 dlpoint = fl%dLdtcool(jl)+ (tpoint-fl%tcool(jl)) &
1801 * (fl%dLdtcool(jl+1)-fl%dLdtcool(jl)) &
1802 / (fl%tcool(jl+1)-fl%tcool(jl))
1863 type(
rc_fluid),
intent(inout) :: fl
1865 integer :: i, j, k, n_nH, ncool, N_sub
1866 double precision :: log_nH_j, nH_j_code, u_lo, u_hi, du_total, du_step
1867 double precision :: u_s, log_u_s, T_s, y_s, ne_s, Lambda_s, integ
1868 double precision,
allocatable :: u_at_T(:), f_node(:)
1869 double precision :: Y_max_global, Y_min_global
1879 if (.not. fl%ionE)
return
1880 if (fl%isPPL)
return
1881 if (fl%Y_mod_built)
return
1887 n_nh = fl%Y_mod_n_nH
1889 if (
mype == 0)
write(*,*)
' build_Y_mod_table: no (rho,T) inverse table allocated; skipping'
1894 select case (trim(fl%Y_mod_quadrature))
1895 case (
'simpson',
'boole')
1898 call mpistop(
'build_Y_mod_table: rc_Y_mod_quadrature must be simpson or boole')
1902 n_sub = max(2, fl%Y_mod_N_sub)
1904 if (trim(fl%Y_mod_quadrature) ==
'boole')
then
1905 if (mod(n_sub, 4) /= 0) n_sub = n_sub + (4 - mod(n_sub, 4))
1908 if (mod(n_sub, 2) /= 0) n_sub = n_sub + 1
1911 fl%Y_mod_n_nH = n_nh
1913 fl%Y_mod_lg_nH_step_inv = dble(n_nh - 1) &
1914 / (fl%Y_mod_lg_nH_max - fl%Y_mod_lg_nH_min)
1915 fl%Y_mod_lg_nH_step = 1.0d0/fl%Y_mod_lg_nH_step_inv
1917 fl%Y_mod_lg_nH_step_inv = 0.0d0
1918 fl%Y_mod_lg_nH_step = 0.0d0
1921 allocate(fl%Y_mod(n_nh, ncool))
1922 allocate(fl%Y_mod_max_per_row(n_nh))
1923 allocate(u_at_t(ncool))
1924 allocate(f_node(0:n_sub))
1927 log_nh_j = fl%Y_mod_lg_nH_min &
1928 + dble(j - 1) * (fl%Y_mod_lg_nH_max - fl%Y_mod_lg_nH_min) / dble(max(1, n_nh - 1))
1929 nh_j_code = 10.0d0**log_nh_j
1933 u_at_t(i) = fl%eint_from_T(log_nh_j, dlog10(fl%tcool(i)))
1936 fl%Y_mod(j, ncool) = 0.0d0
1939 do i = ncool - 1, 1, -1
1941 u_hi = u_at_t(i + 1)
1942 du_total = u_hi - u_lo
1943 if (du_total <= 0.0d0)
then
1945 fl%Y_mod(j, i) = fl%Y_mod(j, i + 1)
1948 du_step = du_total / dble(n_sub)
1952 u_s = u_lo + dble(k) * du_step
1953 if (u_s <= 0.0d0)
then
1957 log_u_s = dlog10(u_s)
1958 t_s = fl%T_from_eint(log_nh_j, log_u_s)
1959 if (fl%lambda_needs_nenh_table)
then
1968 y_s = fl%y_from_eint(log_nh_j, log_u_s)
1969 ne_s = y_s * nh_j_code
1971 if (t_s <= fl%tcoolmin)
then
1975 else if (t_s >= fl%tcoolmax)
then
1978 call findl(t_s, lambda_s, fl)
1980 if (ne_s * lambda_s > 0.0d0)
then
1981 f_node(k) = 1.0d0 / (ne_s * lambda_s)
1987 select case (trim(fl%Y_mod_quadrature))
1994 fl%Y_mod(j, i) = fl%Y_mod(j, i + 1) + integ
1997 fl%Y_mod_max_per_row(j) = fl%Y_mod(j, 1)
2003 fl%Y_mod_built = .true.
2006 y_max_global = maxval(fl%Y_mod_max_per_row)
2007 y_min_global = minval(fl%Y_mod_max_per_row)
2008 write(*,
'(A,I0,A,I0,A,A,A,I0)') &
2009 ' Y_mod table built: ', n_nh,
' nH x ', ncool,
' T quadrature=', &
2010 trim(fl%Y_mod_quadrature),
' N_sub=', n_sub
2011 write(*,
'(A,F8.4,A,F8.4)') &
2012 ' log10 nH range = ', fl%Y_mod_lg_nH_min,
' to ', fl%Y_mod_lg_nH_max
2013 write(*,
'(A,ES12.4,A,ES12.4,A)') &
2014 ' Y_max per row range = [', y_min_global,
', ', y_max_global,
'] code time'
2015 write(*,
'(A)')
' inverse=bisect (row-interpolated, O(log ncool))'
2022 integer,
intent(in) :: n
2023 double precision,
intent(in) :: f(0:n), h
2024 double precision :: s
2028 s = s + 4.0d0 * f(k)
2031 s = s + 2.0d0 * f(k)
2039 integer,
intent(in) :: n
2040 double precision,
intent(in) :: f(0:n), h
2041 double precision :: s
2045 s = s + 7.0d0 * f(k) &
2046 + 32.0d0 * f(k + 1) &
2047 + 12.0d0 * f(k + 2) &
2048 + 32.0d0 * f(k + 3) &
2051 s = s * 2.0d0 * h / 45.0d0
2059 integer,
intent(in) :: ncool
2060 double precision,
intent(in) :: y_row(ncool), t_grid(ncool), y_target
2061 double precision :: log_t_out
2062 integer :: jl, jh, jc
2063 double precision :: f_lo, f_hi
2065 if (y_target <= y_row(ncool))
then
2066 log_t_out = dlog10(t_grid(ncool))
2069 if (y_target >= y_row(1))
then
2070 log_t_out = dlog10(t_grid(1))
2078 if (jh - jl <= 1)
exit
2080 if (y_row(jc) >= y_target)
then
2088 if (f_lo == f_hi)
then
2089 log_t_out = 0.5d0 * (dlog10(t_grid(jl)) + dlog10(t_grid(jh)))
2092 log_t_out = dlog10(t_grid(jl)) &
2093 + (y_target - f_lo) / (f_hi - f_lo) &
2094 * (dlog10(t_grid(jh)) - dlog10(t_grid(jl)))
2101 double precision,
intent(in) :: te_loc, nh_loc
2103 double precision :: y_out
2104 double precision :: log_nh, log_t, ry, rx
2105 integer :: jy, jy1, jx, jx1
2106 double precision :: fy, fx, wlo, whi
2108 log_nh = dlog10(nh_loc)
2109 log_t = dlog10(te_loc)
2112 ry = (log_nh - fl%Y_mod_lg_nH_min) * fl%Y_mod_lg_nH_step_inv
2113 ry = max(0.0d0, min(ry, dble(fl%Y_mod_n_nH - 1)))
2115 jy1 = min(jy + 1, fl%Y_mod_n_nH - 1)
2118 rx = (log_t - fl%lgtcoolmin) / fl%lgstep
2119 rx = max(0.0d0, min(rx, dble(fl%ncool - 1)))
2121 jx1 = min(jx + 1, fl%ncool - 1)
2125 y_out = wlo * ((1.0d0 - fx) * fl%Y_mod(jy + 1, jx + 1) &
2126 + fx * fl%Y_mod(jy + 1, jx1 + 1)) &
2127 + whi * ((1.0d0 - fx) * fl%Y_mod(jy1 + 1, jx + 1) &
2128 + fx * fl%Y_mod(jy1 + 1, jx1 + 1))
2137 double precision,
intent(in) :: y_target, nh_loc
2139 double precision :: t_out
2140 double precision :: log_nh, ry, fy
2142 double precision :: log_t_lo, log_t_hi
2143 integer :: jl, jh, jc, ncool
2144 double precision :: yc_lo, yc_hi, wlo, whi
2146 log_nh = dlog10(nh_loc)
2147 ry = (log_nh - fl%Y_mod_lg_nH_min) * fl%Y_mod_lg_nH_step_inv
2148 ry = max(0.0d0, min(ry, dble(fl%Y_mod_n_nH - 1)))
2150 jy1 = min(jy + 1, fl%Y_mod_n_nH - 1)
2155 yc_lo = wlo * fl%Y_mod(jy + 1, 1) + whi * fl%Y_mod(jy1 + 1, 1)
2156 yc_hi = wlo * fl%Y_mod(jy + 1, ncool) + whi * fl%Y_mod(jy1 + 1, ncool)
2157 if (y_target >= yc_lo)
then
2161 if (y_target <= yc_hi)
then
2168 if (jh - jl <= 1)
exit
2170 if ((wlo * fl%Y_mod(jy + 1, jc) + whi * fl%Y_mod(jy1 + 1, jc)) &
2177 yc_lo = wlo * fl%Y_mod(jy + 1, jl) + whi * fl%Y_mod(jy1 + 1, jl)
2178 yc_hi = wlo * fl%Y_mod(jy + 1, jh) + whi * fl%Y_mod(jy1 + 1, jh)
2179 log_t_lo = dlog10(fl%tcool(jl))
2180 log_t_hi = dlog10(fl%tcool(jh))
2181 if (yc_lo == yc_hi)
then
2182 t_out = fl%tcool(jl)
2184 t_out = 10.0d0**(log_t_lo &
2185 + (y_target - yc_lo) / (yc_hi - yc_lo) * (log_t_hi - log_t_lo))
2192 double precision,
intent(in) :: fy
2194 double precision,
intent(out) :: wlo, whi
2195 wlo = (1.0d0 - fy) * 10.0d0**(-fy*fl%Y_mod_lg_nH_step)
2196 whi = fy * 10.0d0**((1.0d0 - fy)*fl%Y_mod_lg_nH_step)
Scalar EoS inverse, e.g. fleint_from_T(log_nH, log_T).
Optional local multiplier for density-squared radiative losses.
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
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.
logical lb_diagnose
Per-rank load-balance timing diagnostic toggle (off by default). When .true., per-rank wall times are...
integer, parameter unitpar
file handle for IO
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
double precision unit_temperature
Physical scaling factor for temperature.
logical phys_trac
Use TRAC for MHD or 1D HD.
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
This module defines the procedures of a physics module. It contains function pointers for the various...
procedure(sub_get_ei), pointer phys_get_ei
module radiative cooling – add optically thin radiative cooling
double precision function voigt_profile_ratio(a, x)
Voigt profile ratio phi(x)/phi(0) using Humlicek (1982) Region I/II approx. For the small-a regime (a...
subroutine voigt_gauss_legendre(a, b, n, x, w)
Gauss-Legendre quadrature nodes and weights on [a,b]. Uses the Golub-Welsch algorithm for n points.
subroutine getvar_cooling(ixil, ixol, w, x, coolrate, fl)
double precision function invert_row_bisect(y_row, t_grid, ncool, y_target)
Bisection on a single Y_mod row to find log10(T) such that Y_mod_row(i) = y_target....
subroutine radiative_cooling_rho2_factor(ixil, ixol, w, x, fl, factor)
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine findl(tpoint, lpoint, fl)
double precision function findt_mod(y_target, nh_loc, fl)
Inverse Y_mod lookup: given Y_target and nH, return T such that Y_mod(log10 nH, log10 T) = Y_target....
double precision function rc_eint_floor(fl, log_nh, nh_val)
Internal energy per volume at the floor temperature tlow, ionisation included.
subroutine get_cool_equi(qdt, ixil, ixol, wct, w, x, fl, res)
subroutine radiative_cooling_init(fl, read_params)
subroutine finddldt(tpoint, dlpoint, fl)
subroutine voigt_escape_init_table()
Build the Voigt escape probability lookup table. Called once (guarded by voigt_table_ready flag)....
subroutine y_mod_row_weights(fy, fl, wlo, whi)
weights between the nH rows jy and jy+1: nH*Y is interpolated linearly in log10 nH,...
double precision, public lb_cool_accum
Per-rank cooling-only compute accumulator for lb_diagnose. Sums the wall time spent inside radiative_...
logical function rc_variable_cv(fl, t1, t2)
True where ionisation buffers the cooling step, so that c_V varies: a large change of T below the tem...
double precision, parameter rc_t_ymod_max_k
Temperature in K above which c_V is constant, the upper end of the Y_mod path.
subroutine create_y_ppl(fl)
double precision function boole_composite(f, n, h)
Composite Boole's rule on (N+1) equally spaced samples (N a multiple of 4). Each 4-step block contrib...
subroutine build_y_mod_table(fl)
===================================================================
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
subroutine calc_l_extended(tpoint, lpoint, fl)
double precision function lowfip_fraction(tpoint, fl)
double precision function findy_mod(te_loc, nh_loc, fl)
Forward Y_mod lookup in (log10 nH, log10 T), both axes uniform in log space; along nH the product nH*...
subroutine cool_exact(qdt, ixil, ixol, wct, wctprim, w, x, fl)
subroutine findt(tpoint, ypoint, fl)
double precision function voigt_escape_lookup(tau)
Look up the Voigt escape probability for a given tau. Uses linear interpolation in log10(tau) space.
subroutine floortemperature(qdt, ixil, ixol, wct, w, x, fl)
double precision function rc_trac_factor(fl, ixd, te_val)
TRAC factor (T/Tcoff)^(5/2) of the losses below Tcoff, and 1 without TRAC or where a user TRAC mask s...
subroutine getvar_cooling_exact(qdt, ixil, ixol, wct, w, x, coolrate, fl)
subroutine radiative_cooling_taper(ixd, x_ndim, rho_val, te_val, rf_val, fl, factor)
double precision function simpson_composite(f, n, h)
Composite Simpson's rule on (N+1) equally spaced samples (N even). N must be a positive even integer;...
subroutine findy(tpoint, ypoint, fl)
module containing all optically thin radiative cooling tables
double precision, dimension(1:101) l_dere_corona
double precision, dimension(1:71) t_mlsolar1
double precision, dimension(1:151) l_cl_solar
double precision, dimension(1:5) t_fm
double precision, dimension(1:14) a_spex_dm_fine
double precision, dimension(1:9) a_rosner
double precision, dimension(1:110) l_spex
double precision, dimension(1:51) l_mb
double precision, dimension(1:10) t_rosner
double precision, dimension(1:5) a_hildner
double precision, dimension(1:9) x_rosner
double precision, dimension(1:7) x_klimchuk
double precision, dimension(1:151) l_composite
double precision, dimension(1:151) l_cl_ism
double precision, dimension(1:8) t_spex_dm_rough
double precision, dimension(1:110) nenh_spex
double precision, dimension(1:110) t_spex
double precision, dimension(1:76) l_dm_2
double precision, dimension(1:151) t_composite
double precision, dimension(1:15) t_spex_dm_fine
double precision, dimension(1:7) x_spex_dm_rough
double precision, dimension(1:14) x_spex_dm_fine
double precision, dimension(1:71) l_mlsolar1
double precision, dimension(1:45) t_jccorona
double precision, dimension(1:5) x_hildner
double precision, dimension(1:71) t_mlcosmol
double precision, dimension(1:151) t_cl_ism
double precision, dimension(1:151) t_cl_solar
double precision, dimension(1:51) t_mb
double precision, dimension(1:8) t_klimchuk
double precision, dimension(1:55) t_colgan
double precision, dimension(1:55) l_colgan
double precision, dimension(1:4) a_fm
double precision, dimension(1:101) l_dere_photo
double precision, dimension(1:45) l_jccorona
double precision, dimension(1:71) l_mlwc
double precision, dimension(1:71) l_dm
double precision, dimension(1:71) t_mlwc
double precision, dimension(1:7) a_spex_dm_rough
double precision, dimension(1:71) t_dm
double precision, dimension(1:7) a_klimchuk
double precision, dimension(1:71) l_mlcosmol
double precision, dimension(1:76) t_dm_2
double precision, dimension(1:6) t_hildner
double precision, dimension(1:4) x_fm
double precision, dimension(1:101) t_dere
double precision, dimension(1:101) lowfip_frac
Public face of the short-characteristics (SC) radiative transfer and its coupling to the (M)HD.
pure elemental double precision function, public rt_sc_thin_weight(te_code, y_code, p_code)
Share of the radiative losses taken by the optically thin treatment, with SC taking the rest,...