27 double precision,
private :: he_abundance
30 double precision,
private :: rc_gamma
33 double precision,
private :: rc_gamma_1
36 double precision,
private :: invgam
47 integer,
parameter,
private :: n_voigt_table = 500
48 double precision,
parameter,
private :: voigt_logtau_min = -2.0d0
49 double precision,
parameter,
private :: voigt_logtau_max = 8.0d0
50 double precision,
parameter,
private :: voigt_a_ref = 4.7
d-4
51 double precision,
parameter,
private :: voigt_xmax = 6.0d0
52 double precision,
private :: voigt_e_table(n_voigt_table)
53 double precision,
private :: voigt_logtau_step
54 logical,
private :: voigt_table_ready = .false.
59 integer,
intent(in) :: ixI^L, ixO^L
60 double precision,
intent(in) :: w(ixI^S,nw)
61 double precision,
intent(in) :: x(ixI^S,1:ndim)
62 double precision,
intent(out):: res(ixI^S)
67 integer,
intent(in) :: ixI^L, ixO^L
68 double precision,
intent(in) :: w(ixI^S, nw)
69 double precision,
intent(out):: ne(ixI^S), nH(ixI^S)
74 double precision,
intent(in) :: a, b
80 double precision :: rad_damp_height
81 double precision :: rad_damp_scale
84 double precision,
allocatable :: tcool(:), lcool(:), dldtcool(:)
85 double precision,
allocatable :: yc(:)
86 double precision :: tref, lref, tcoolmin,tcoolmax
87 double precision :: lgtcoolmin, lgtcoolmax, lgstep
91 double precision,
allocatable :: y_ppl(:), t_ppl(:), l_ppl(:), a_ppl(:)
94 double precision :: tlow
113 logical :: isppl = .false.
119 double precision :: rad_suppress_temp = 0.0d0
122 double precision :: suppress_temp_code = 0.0d0
124 logical :: rad_modify
126 logical :: rad_modify_sym
128 double precision :: rad_cut_hgt = 0.0d0
130 double precision :: rad_cut_dey = 0.15d0
132 double precision :: cfrac = 0.1d0
137 logical :: has_equi = .false.
139 logical :: subtract_equi = .false.
141 double precision,
allocatable :: frac_lowfip(:)
145 logical :: rad_newton = .false.
146 double precision :: rad_newton_pthick = 25.d0
147 double precision :: rad_newton_trad = 0.006d0
148 double precision :: rad_newton_rhosurf = 1.d4
151 double precision :: rad_taper_rho
153 double precision :: rad_taper_dey
156 logical :: rad_escape_prob = .false.
158 double precision :: rad_kappa_eff = 0.0d0
160 double precision :: rad_kappa_tcutoff = 0.0d0
162 double precision :: rad_kappa_alpha = 4.0d0
164 character(len=10) :: rad_escape_type =
'slab'
166 double precision :: rad_escape_tau_cutoff = 0.0d0
168 double precision :: rad_escape_height = 0.0d0
170 integer :: iw_colmass_ = -1
173 character(len=std_len) :: coolcurve
175 procedure(
get_subr1),
pointer,
nopass :: get_rho => null()
176 procedure(
get_subr1),
pointer,
nopass :: get_te => null()
177 procedure(
get_subr1),
pointer,
nopass :: get_rho_equi => null()
178 procedure(
get_subr1),
pointer,
nopass :: get_pthermal => null()
179 procedure(
get_subr1),
pointer,
nopass :: get_pthermal_equi => null()
180 procedure(
get_subr1),
pointer,
nopass :: get_var_rfactor => null()
182 procedure(
get_subr1),
pointer,
nopass :: get_temperature_equi => null()
185 logical :: ione = .false.
186 character(len=20) :: method =
'tables'
187 double precision :: inv_gamma_minus_1
188 double precision :: nh2rhofactor
189 double precision :: eion_per_nh
214 double precision,
allocatable :: y_mod(:,:)
215 double precision,
allocatable :: y_mod_max_per_row(:)
216 integer :: y_mod_n_nh = 0
217 double precision :: y_mod_lg_nh_min = 0.0d0
218 double precision :: y_mod_lg_nh_max = 0.0d0
219 double precision :: y_mod_lg_nh_step_inv = 0.0d0
222 logical :: y_mod_built = .false.
224 character(len=8) :: y_mod_quadrature =
'boole'
226 integer :: y_mod_n_sub = 16
254 logical :: lambda_needs_nenh_table = .false.
255 double precision,
allocatable :: nenh_eq_table(:)
264 double precision,
intent(in) :: phys_gamma,He_abund
267 he_abundance=he_abund
278 integer,
parameter :: nquad = 64
279 double precision :: xq(nquad), wq(nquad)
280 double precision :: logtau, tau0, phi0, gx, integrand, E_val
281 double precision :: a_rep
284 if(voigt_table_ready)
return
287 voigt_logtau_step = (voigt_logtau_max - voigt_logtau_min) / dble(n_voigt_table - 1)
296 phi0 = 1.0d0 / sqrt(dpi)
304 do i = 1, n_voigt_table
305 logtau = voigt_logtau_min + dble(i-1) * voigt_logtau_step
306 tau0 = 10.0d0**logtau
308 if(tau0 < 1.0
d-6)
then
309 voigt_e_table(i) = 1.0d0
317 if(tau0 * gx > 500.0d0)
then
318 integrand = integrand + wq(k) * 1.0d0
319 else if(tau0 * gx < 1.0
d-10)
then
320 integrand = integrand + wq(k) * tau0 * gx
322 integrand = integrand + wq(k) * (1.0d0 - exp(-tau0 * gx))
326 e_val = 2.0d0 * phi0 / tau0 * integrand
328 voigt_e_table(i) = max(0.0d0, min(1.0d0, e_val))
331 voigt_table_ready = .true.
342 double precision,
intent(in) :: a, x
343 double precision :: gauss_part, lorentz_part, phi_x, phi_0
346 phi_0 = 1.0d0 / sqrt(dpi)
351 gauss_part = exp(-x*x) / sqrt(dpi)
352 if(x*x + a*a > 1.0
d-30)
then
353 lorentz_part = a / (dpi * (x*x + a*a))
357 phi_x = gauss_part + lorentz_part
367 double precision,
intent(in) :: tau
368 double precision :: logtau, frac
371 if(tau < 1.0d-6)
then
378 if(logtau <= voigt_logtau_min)
then
383 if(logtau >= voigt_logtau_max)
then
386 * (10.0d0**voigt_logtau_max) / tau
391 frac = (logtau - voigt_logtau_min) / voigt_logtau_step
393 idx = max(1, min(idx, n_voigt_table - 1))
394 frac = frac - dble(idx - 1)
397 + voigt_e_table(idx + 1) * frac
406 double precision,
intent(in) :: a, b
407 integer,
intent(in) :: n
408 double precision,
intent(out) :: x(n), w(n)
409 double precision :: xi, wi, p0, p1, p2, pp, z, z1
410 integer :: i, j, k, m
416 z = cos(dpi * (dble(i) - 0.25d0) / (dble(n) + 0.5d0))
425 p0 = ((2.0d0*dble(k) - 1.0d0) * z * p1 - (dble(k) - 1.0d0) * p2) / dble(k)
428 pp = dble(n) * (z * p0 - p1) / (z*z - 1.0d0)
431 if(abs(z - z1) < 1.0
d-15)
exit
435 xi = 0.5d0 * ((b - a) * z + (b + a))
436 wi = (b - a) / ((1.0d0 - z*z) * pp*pp)
440 x(n + 1 - i) = a + b - xi
449 subroutine read_params(fl)
454 end subroutine read_params
459 double precision,
dimension(:),
allocatable :: t_table
460 double precision,
dimension(:),
allocatable :: L_table
461 double precision,
dimension(:),
allocatable :: f_table
462 double precision :: ratt, fact1, fact2, fact3, dL1, dL2
463 double precision :: tstep, Lstep
464 integer :: ntable, i, j
466 Character(len=65) :: PPL_curves(1:6)
469 fl%coolcurve=
'JCcorona'
473 fl%rad_suppress_temp=0.0d0
475 fl%rad_cut_dey=0.15d0
476 fl%rad_modify=.false.
477 fl%rad_modify_sym=.false.
478 fl%rad_taper_rho=bigdouble
479 fl%rad_taper_dey=0.0d0
481 fl%rad_damp_height=0.5d0
482 fl%rad_damp_scale=0.15d0
486 if(fl%rad_escape_prob .and. fl%rad_escape_type ==
'voigt')
then
489 write(*,
'(A,I0,A,ES9.2,A,F4.1,A)') &
490 ' Voigt escape table: ', n_voigt_table,
' points, a_ref=', &
491 voigt_a_ref,
', x_max=', voigt_xmax,
' Doppler widths'
495 if (fl%fip_ > 0)
then
496 select case (trim(fl%coolcurve))
497 case (
'Dere_photo',
'Dere_photo_DM')
499 call mpistop(
"FIP cooling requires coolcurve='Dere_photo' or 'Dere_photo_DM'")
503 if(fl%rc_split) any_source_split=.true.
506 ppl_curves = [
Character(len=65) ::
'Hildner',
'FM',
'Rosner',
'Klimchuk',
'SPEX_DM_rough',
'SPEX_DM_fine']
507 do i=1,
size(ppl_curves)
508 if (ppl_curves(i)==fl%coolcurve)
then
516 select case(fl%coolcurve)
520 print *,
'Use Hildner (1974) piecewise power law'
522 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
523 allocate(fl%a_PPL(1:fl%n_PPL))
526 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)
530 print *,
'Use Forbes and Malherbe (1991)-like piecewise power law'
532 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
533 allocate(fl%a_PPL(1:fl%n_PPL))
534 fl%t_PPL(1:fl%n_PPL+1) =
t_fm(1:
n_fm+1)
536 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)
540 print *,
'Use piecewise power law according to Rosner (1978)'
542 print *,
'and extended by Priest (1982) from Van Der Linden (1991)'
544 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
545 allocate(fl%a_PPL(1:fl%n_PPL))
548 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)
552 print *,
'Use Klimchuk (2008) piecewise power law'
554 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
555 allocate(fl%a_PPL(1:fl%n_PPL))
558 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)
560 case(
'SPEX_DM_rough')
562 print *,
'Use the rough piece wise power law fit to the SPEX_DM curve (2009)'
564 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
565 allocate(fl%a_PPL(1:fl%n_PPL))
572 print *,
'Use the fine, detailed piece wise power law fit to the SPEX_DM curve (2009)'
574 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
575 allocate(fl%a_PPL(1:fl%n_PPL))
581 call mpistop(
"This piecewise power law is unknown")
585 fl%t_PPL(1:fl%n_PPL+1) = 10.d0**fl%t_PPL(1:fl%n_PPL+1)
587 if (si_unit) fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * 10.0d0**(-13)
590 fl%t_PPL(1:fl%n_PPL+1) = fl%t_PPL(1:fl%n_PPL+1) / unit_temperature
591 fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * unit_numberdensity**2 * unit_time / unit_pressure
594 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)
595 fl%lref = fl%l_PPL(fl%n_PPL+1)
596 fl%tref = fl%t_PPL(fl%n_PPL+1)
599 fl%tcoolmin = fl%t_PPL(1)
600 fl%tcoolmax = fl%t_PPL(fl%n_PPL+1)
602 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
609 allocate(fl%tcool(1:fl%ncool), fl%Lcool(1:fl%ncool), fl%dLdtcool(1:fl%ncool))
610 allocate(fl%Yc(1:fl%ncool))
611 if(fl%fip_ > 0)
allocate(fl%frac_lowFIP(1:fl%ncool))
613 fl%tcool(1:fl%ncool) = zero
614 fl%Lcool(1:fl%ncool) = zero
615 fl%dLdtcool(1:fl%ncool) = zero
618 select case(fl%coolcurve)
622 print *,
'Use Colgan & Feldman (2008) cooling curve'
624 print *,
'This version only till 10000 K, beware for floor T treatment'
626 allocate(t_table(1:ntable))
627 allocate(l_table(1:ntable))
633 print *,
'Use Dalgarno & McCray (1972) cooling curve'
635 allocate(t_table(1:ntable))
636 allocate(l_table(1:ntable))
642 write(*,
'(3a)')
'Use MacDonald & Bailey (1981) cooling curve '&
643 ,
'as implemented in ZEUS-3D, with the values '&
644 ,
'from Dalgarno & McCRay (1972) for low temperatures.'
646 allocate(t_table(1:ntable))
647 allocate(l_table(1:ntable))
648 t_table(1:ntable) =
t_dm(1:21)
649 l_table(1:ntable) =
l_dm(1:21)
655 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
656 ,
'for zero metallicity '
658 allocate(t_table(1:ntable))
659 allocate(l_table(1:ntable))
665 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
666 ,
'for WC-star metallicity '
668 allocate(t_table(1:ntable))
669 allocate(l_table(1:ntable))
675 print *,
'Use Mellema & Lundqvist (2002) cooling curve '&
676 ,
'for solar metallicity '
678 allocate(t_table(1:ntable))
679 allocate(l_table(1:ntable))
685 print *,
'Use Cloudy based cooling curve '&
686 ,
'for ism metallicity '
688 allocate(t_table(1:ntable))
689 allocate(l_table(1:ntable))
695 print *,
'Use Cloudy based cooling curve '&
696 ,
'for solar metallicity '
698 allocate(t_table(1:ntable))
699 allocate(l_table(1:ntable))
703 case(
'composite_solar')
705 print *,
'Use composite cooling curve for solar metallicity:'
706 print *,
' T > 12 kK: Dere/Colgan/SPEX weighted average'
707 print *,
' 7-12 kK: SPEX CIE through the Lya transition'
708 print *,
' T < 7 kK: cloudy_solar fine-structure/molecular'
711 allocate(t_table(1:ntable))
712 allocate(l_table(1:ntable))
718 print *,
'Use SPEX cooling curve (Schure et al. 2009) '&
719 ,
'for solar metallicity '
721 allocate(t_table(1:ntable))
722 allocate(l_table(1:ntable))
733 fl%lambda_needs_nenh_table = .true.
737 print *,
'Use SPEX cooling curve for solar metallicity above 10^4 K. '
738 print *,
'At lower temperatures,use Dalgarno & McCray (1972), '
739 print *,
'with a pre-set ionization fraction of 10^-3. '
740 print *,
'as described by Schure et al. (2009). '
743 allocate(t_table(1:ntable))
744 allocate(l_table(1:ntable))
757 fl%lambda_needs_nenh_table = .true.
761 print *,
'Use Dere (2009) cooling curve for solar corona'
763 allocate(t_table(1:ntable))
764 allocate(l_table(1:ntable))
768 case(
'Dere_corona_DM')
770 print *,
'Combination of Dere_corona (2009) for high temperatures and'
772 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
774 allocate(t_table(1:ntable))
775 allocate(l_table(1:ntable))
783 print *,
'Use Dere (2009) cooling curve for solar photophere'
785 allocate(t_table(1:ntable))
786 allocate(l_table(1:ntable))
787 if (fl%fip_ > 0)
allocate(f_table(1:ntable))
792 case(
'Dere_photo_DM')
794 print *,
'Combination of Dere_photo (2009) for high temperatures and'
796 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
798 allocate(t_table(1:ntable))
799 allocate(l_table(1:ntable))
800 if (fl%fip_ > 0)
allocate(f_table(1:ntable))
805 if (fl%fip_ > 0)
then
806 f_table(1:
n_dm_2-1) = zero
812 print *,
'Use Colgan (2008) cooling curve'
814 allocate(t_table(1:ntable))
815 allocate(l_table(1:ntable))
821 print *,
'Combination of Colgan (2008) for high temperatures and'
823 print *,
'Dalgarno & McCray (1972), DM2, for low temperatures'
825 allocate(t_table(1:ntable))
826 allocate(l_table(1:ntable))
833 call mpistop(
"This coolingcurve is unknown")
838 fl%tcoolmax = t_table(ntable)
839 fl%tcoolmin = t_table(1)
840 ratt = (fl%tcoolmax-fl%tcoolmin)/( dble(fl%ncool-1) + smalldouble)
842 fl%tcool(1) = fl%tcoolmin
843 fl%Lcool(1) = l_table(1)
845 fl%tcool(fl%ncool) = fl%tcoolmax
846 fl%Lcool(fl%ncool) = l_table(ntable)
848 if (fl%fip_ > 0)
then
849 fl%frac_lowFIP(1) = f_table(1)
850 fl%frac_lowFIP(fl%ncool) = f_table(ntable)
854 fl%tcool(i) = fl%tcool(i-1)+ratt
858 if(fl%tcool(i) < t_table(j+1))
then
859 if(j.eq. ntable-1 )
then
860 fact1 = (fl%tcool(i)-t_table(j+1)) &
861 /(t_table(j)-t_table(j+1))
862 fact2 = (fl%tcool(i)-t_table(j)) &
863 /(t_table(j+1)-t_table(j))
864 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
865 if (fl%fip_ > 0)
then
866 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
870 dl1 = l_table(j+1)-l_table(j)
871 dl2 = l_table(j+2)-l_table(j+1)
872 jump =(max(dabs(dl1),dabs(dl2)) > 2*min(dabs(dl1),dabs(dl2)))
875 fact1 = (fl%tcool(i)-t_table(j+1)) &
876 /(t_table(j)-t_table(j+1))
877 fact2 = (fl%tcool(i)-t_table(j)) &
878 /(t_table(j+1)-t_table(j))
879 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
880 if (fl%fip_ > 0)
then
881 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
885 fact1 = ((fl%tcool(i)-t_table(j+1)) &
886 * (fl%tcool(i)-t_table(j+2))) &
887 / ((t_table(j)-t_table(j+1)) &
888 * (t_table(j)-t_table(j+2)))
889 fact2 = ((fl%tcool(i)-t_table(j)) &
890 * (fl%tcool(i)-t_table(j+2))) &
891 / ((t_table(j+1)-t_table(j)) &
892 * (t_table(j+1)-t_table(j+2)))
893 fact3 = ((fl%tcool(i)-t_table(j)) &
894 * (fl%tcool(i)-t_table(j+1))) &
895 / ((t_table(j+2)-t_table(j)) &
896 * (t_table(j+2)-t_table(j+1)))
897 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2 &
899 if (fl%fip_ > 0)
then
900 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2 &
910 fl%tcool(1:fl%ncool) = 10.0d0**fl%tcool(1:fl%ncool)
911 fl%Lcool(1:fl%ncool) = 10.0d0**fl%Lcool(1:fl%ncool)
914 if (si_unit) fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * 10.0d0**(-13)
917 fl%tcool(1:fl%ncool) = fl%tcool(1:fl%ncool) / unit_temperature
918 fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * unit_numberdensity**2 * unit_time / unit_pressure
920 fl%tcoolmin = fl%tcool(1)+smalldouble
922 if(fl%rad_suppress_temp > 0.0d0)
then
923 fl%suppress_temp_code = fl%rad_suppress_temp / unit_temperature
925 write(*,
'(A,ES10.3,A)')
' Cooling suppression active: disabled below T = ', &
926 fl%rad_suppress_temp,
' K within rad_cut_hgt'
930 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
931 fl%tcoolmax = fl%tcool(fl%ncool)
932 fl%lgtcoolmin = dlog10(fl%tcoolmin)
933 fl%lgtcoolmax = dlog10(fl%tcoolmax)
934 fl%lgstep = (fl%lgtcoolmax-fl%lgtcoolmin) * 1.d0 / (fl%ncool-1)
935 fl%dLdtcool(1) = (fl%Lcool(2)-fl%Lcool(1))/(fl%tcool(2)-fl%tcool(1))
936 fl%dLdtcool(fl%ncool) = (fl%Lcool(fl%ncool)-fl%Lcool(fl%ncool-1))/(fl%tcool(fl%ncool)-fl%tcool(fl%ncool-1))
939 fl%dLdtcool(i) = (fl%Lcool(i+1)-fl%Lcool(i-1))/(fl%tcool(i+1)-fl%tcool(i-1))
944 if (
allocated(f_table))
deallocate(f_table)
946 fl%tref = fl%tcoolmax
947 fl%lref = fl%Lcool(fl%ncool)
948 fl%Yc(fl%ncool) = zero
949 do i=fl%ncool-1, 1, -1
950 fl%Yc(i) = fl%Yc(i+1)
952 tstep = 1.0d-2*(fl%tcool(i+1)-fl%tcool(i))
953 call findl(fl%tcool(i+1)-j*tstep, lstep, fl)
954 fl%Yc(i) = fl%Yc(i) + fl%lref/fl%tref*tstep/lstep
959 rc_gamma_1=rc_gamma-1.d0
960 invgam = 1.d0/rc_gamma_1
970 double precision :: y_extra, factor
973 allocate(fl%y_PPL(1:fl%n_PPL+1))
975 fl%y_PPL(1:fl%n_PPL+1) = zero
978 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
979 if (fl%a_PPL(i) == 1.d0)
then
980 y_extra = log( fl%t_PPL(i) / fl%t_PPL(i+1) )
982 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / fl%t_PPL(i+1) )**(fl%a_PPL(i)-1) )
984 fl%y_PPL(i) = fl%y_PPL(i+1) - factor*y_extra
995 integer,
intent(in) :: ixI^L,ixO^L
996 double precision,
intent(in) :: x(ixI^S,1:ndim)
997 double precision :: w(ixI^S,1:nw)
998 double precision,
intent(out):: coolrate(ixI^S)
1001 double precision :: pth(ixI^S),rho(ixI^S)
1002 double precision :: L1,Te(ixI^S),Rfactor(ixI^S)
1003 double precision :: ne(ixI^S), nH_arr(ixI^S)
1004 double precision :: taper
1008 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1011 call fl%get_Te(w,x,ixi^l,ixo^l,te)
1012 call fl%get_ne_nH(ixi^l, ixo^l, w, ne, nh_arr)
1014 {
do ix^db = ixo^lim^db\}
1016 if(te(ix^d) <= fl%tcoolmin)
then
1018 else if(te(ix^d) >= fl%tcoolmax)
then
1020 l1 = l1*ne(ix^d)*nh_arr(ix^d)
1022 call findl(te(ix^d),l1,fl)
1023 l1 = l1*ne(ix^d)*nh_arr(ix^d)
1025 if(
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height)
then
1026 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1038 integer,
intent(in) :: ixI^L, ixO^L
1039 double precision,
intent(in) :: qdt, x(ixI^S, 1:ndim), wCT(ixI^S, 1:nw)
1040 double precision :: w(ixI^S, 1:nw)
1041 double precision,
intent(out) :: coolrate(ixI^S)
1043 double precision :: y1, y2, l1, tlocal2
1044 double precision :: Te(ixI^S), pnew(ixI^S), rho(ixI^S), rhonew(ixI^S)
1045 double precision :: emin, Lmax, fact, Rfactor(ixI^S), pth(ixI^S)
1046 double precision :: ne(ixI^S), nH_arr(ixI^S)
1047 double precision :: taper
1049 double precision :: nH_val, log_nH, log_p_nH
1050 double precision :: eint_current
1051 double precision :: y_l, T_l
1054 call fl%get_pthermal(wct, x, ixi^l, ixo^l, pth)
1055 call fl%get_rho(wct, x, ixi^l, ixo^l, rho)
1056 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1057 call fl%get_Te(wct, x, ixi^l, ixo^l, te)
1058 call fl%get_ne_nH(ixi^l, ixo^l, wct, ne, nh_arr)
1061 call fl%get_pthermal(w, x, ixi^l, ixo^l, pnew)
1062 call fl%get_rho(w, x, ixi^l, ixo^l, rhonew)
1064 fact=fl%lref*qdt/fl%tref
1066 {
do ix^db = ixo^lim^db\}
1067 emin = rhonew(ix^d) * fl%tlow * rfactor(ix^d) * invgam
1069 nh_val = rhonew(ix^d) / fl%nH2rhoFactor
1070 log_nh = dlog10(nh_val)
1071 if (fl%method ==
'analytic')
then
1073 y_l = wct(ix^d, iw_ne) / nh_val
1074 eint_current = fl%inv_gamma_minus_1 * (1.0d0 + y_l) * nh_val * t_l &
1075 + y_l * fl%eion_per_nH * nh_val
1077 log_p_nh = dlog10(pnew(ix^d) / nh_val)
1078 eint_current = pnew(ix^d) * fl%p2eint(log_nh, log_p_nh)
1080 lmax = max(zero, (eint_current - emin) / qdt)
1082 lmax = max(zero, ( pnew(ix^d)*invgam - emin ) / qdt)
1087 if( te(ix^d)<= fl%tcoolmin)
then
1089 else if( te(ix^d)>= fl%tcoolmax )
then
1091 if (fl%lambda_needs_nenh_table)
then
1092 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1094 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1100 call findy(te(ix^d), y1, fl)
1101 if (fl%lambda_needs_nenh_table)
then
1102 y2 = y1 + fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1103 / (rho(ix^d) * rfactor(ix^d))
1105 y2 = y1 + fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1106 / (rho(ix^d) * rfactor(ix^d))
1108 call findt(tlocal2, y2, fl)
1110 if (fl%ionE .and. fl%Y_mod_built .and. &
1111 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1112 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1113 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1115 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1119 if( tlocal2 <= fl%tcoolmin )
then
1121 else if (fl%ionE .and. &
1122 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1124 l1 = ((fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1125 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val) / qdt
1129 l1 = (te(ix^d)- tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam/qdt
1135 if(
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height)
then
1136 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1143 qsourcesplit,active,fl)
1146 integer,
intent(in) :: ixI^L, ixO^L
1147 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
1148 double precision,
intent(inout) :: w(ixI^S,1:nw)
1149 logical,
intent(in) :: qsourcesplit
1150 logical,
intent(inout) :: active
1152 double precision,
allocatable,
dimension(:^D&) :: Lequi
1153 double precision :: lb_t0_cool
1156 if(qsourcesplit .eqv.fl%rc_split)
then
1158 call cool_exact(qdt,ixi^l,ixo^l,wct,wctprim,w,x,fl)
1159 if(fl%subtract_equi)
then
1160 allocate(lequi(ixi^s))
1162 w(ixo^s,fl%e_) = w(ixo^s,fl%e_)+lequi(ixo^s)
1173 integer,
intent(in) :: ixI^L, ixO^L
1174 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
1175 double precision,
intent(inout) :: w(ixI^S,1:nw)
1177 double precision :: etherm(ixI^S), rho(ixI^S), Rfactor(ixI^S),emin
1180 call fl%get_pthermal(w,x,ixi^l,ixo^l,etherm)
1181 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1182 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1183 {
do ix^db = ixo^lim^db\}
1184 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)
1185 if(etherm(ix^d) < emin)
then
1186 w(ix^d,fl%e_)=w(ix^d,fl%e_)+(emin-etherm(ix^d))*invgam
1196 integer,
intent(in) :: ix^D
1197 double precision,
intent(in) :: x_ndim, rho_val, Te_val
1199 double precision,
intent(out) :: factor
1200 double precision :: d_boundary, tau, kappa_local
1207 if(fl%rad_modify_sym)
then
1208 d_boundary = min(x_ndim - xprobmin^nd, xprobmax^nd - x_ndim)
1210 d_boundary = x_ndim - xprobmin^nd
1212 if(d_boundary .le. fl%rad_cut_hgt)
then
1213 if(fl%suppress_temp_code > 0.0d0)
then
1216 if(te_val .lt. fl%suppress_temp_code)
then
1222 factor = factor * exp(-((d_boundary - fl%rad_cut_hgt) / fl%rad_cut_dey)**2)
1227 if(rho_val .gt. fl%rad_taper_rho)
then
1228 factor = factor * exp(-((rho_val - fl%rad_taper_rho) / fl%rad_taper_dey)**2)
1234 if(fl%rad_escape_prob .and. fl%iw_colmass_ > 0)
then
1235 kappa_local = fl%rad_kappa_eff
1236 if(fl%rad_kappa_Tcutoff > 0.0d0)
then
1237 kappa_local = kappa_local &
1238 / (1.0d0 + (te_val / fl%rad_kappa_Tcutoff)**fl%rad_kappa_alpha)
1240 tau = kappa_local *
block%wextra(ix^d, fl%iw_colmass_)
1241 if(tau > 1.0d-6)
then
1242 select case(fl%rad_escape_type)
1245 factor = factor * (1.0d0 - exp(-tau)) / tau
1251 call mpistop(
"Unknown rad_escape_type: use 'slab' or 'voigt'")
1255 if(fl%rad_escape_tau_cutoff > 0.0d0)
then
1256 factor = factor * exp(-tau / fl%rad_escape_tau_cutoff)
1265 integer,
intent(in) :: ixI^L, ixO^L
1266 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
1267 double precision,
intent(inout) :: w(ixI^S,1:nw)
1269 double precision,
intent(out) :: res(ixI^S)
1271 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),L1,Tlocal2
1272 double precision :: Te(ixI^S)
1273 double precision :: emin, Lmax
1274 double precision :: Y1, Y2
1275 double precision :: de, emax,fact
1276 double precision :: ne(ixI^S), nH_arr(ixI^S)
1277 double precision :: taper
1279 double precision :: nH_val, log_nH, log_p_nH
1280 double precision :: eint_current
1281 double precision :: y_l, T_l
1284 call fl%get_pthermal_equi(wct,x,ixi^l,ixo^l,pth)
1285 call fl%get_rho_equi(wct,x,ixi^l,ixo^l,rho)
1286 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1288 call fl%get_Te(wct,x,ixi^l,ixo^l,te)
1289 call fl%get_ne_nH(ixi^l, ixo^l, wct, ne, nh_arr)
1293 fact = fl%lref*qdt/fl%tref
1294 {
do ix^db = ixo^lim^db\}
1295 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)*invgam
1297 nh_val = rho(ix^d) / fl%nH2rhoFactor
1298 log_nh = dlog10(nh_val)
1299 if (fl%method ==
'analytic')
then
1301 y_l = wct(ix^d, iw_ne) / nh_val
1302 eint_current = 1.5d0 * (1.0d0 + y_l) * nh_val * t_l &
1303 + y_l * fl%eion_per_nH * nh_val
1305 log_p_nh = dlog10(pth(ix^d) / nh_val)
1306 eint_current = pth(ix^d) * fl%p2eint(log_nh, log_p_nh)
1308 lmax = max(zero, (eint_current - emin) / qdt)
1309 emax = max(zero, eint_current - emin)
1311 lmax = max(zero,(pth(ix^d)*invgam-emin)/qdt)
1312 emax = max(zero, pth(ix^d)*invgam-emin)
1319 if( te(ix^d)<=fl%tcoolmin )
then
1321 else if( te(ix^d)>=fl%tcoolmax )
then
1323 if (fl%lambda_needs_nenh_table)
then
1324 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1326 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1329 if(te(ix^d)<
block%wextra(ix^d,fl%Tcoff_))
then
1330 l1=l1*sqrt((te(ix^d)/
block%wextra(ix^d,fl%Tcoff_))**5)
1339 call findy(te(ix^d),y1,fl)
1340 if (fl%lambda_needs_nenh_table)
then
1341 y2 = y1 + fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1342 / (rho(ix^d) * rfactor(ix^d))
1344 y2 = y1 + fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1345 / (rho(ix^d) * rfactor(ix^d))
1347 call findt(tlocal2,y2,fl)
1349 if (fl%ionE .and. fl%Y_mod_built .and. &
1350 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1351 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1352 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1354 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1358 if(tlocal2<=fl%tcoolmin)
then
1360 else if (fl%ionE .and. &
1361 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1362 de = (fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1363 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val
1366 de = (te(ix^d)-tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
1369 if(te(ix^d)<
block%wextra(ix^d,fl%Tcoff_))
then
1370 de=de*sqrt((te(ix^d)/
block%wextra(ix^d,fl%Tcoff_))**5)
1377 res(ix^d) = res(ix^d) * taper
1385 integer,
intent(in) :: ixI^L, ixO^L
1386 double precision,
intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
1387 double precision,
intent(inout) :: w(ixI^S,1:nw)
1389 double precision :: Y1, Y2
1390 double precision :: L1, pth(ixI^S), Tlocal2, pnew(ixI^S)
1391 double precision :: rho(ixI^S), Te(ixI^S), rhonew(ixI^S), Rfactor(ixI^S)
1392 double precision :: emin, Lmax, fact
1393 double precision :: de, emax
1394 double precision :: ne(ixI^S), nH_arr(ixI^S)
1395 double precision :: taper
1397 double precision :: nH_val, log_nH, log_p_nH
1398 double precision :: eint_current
1399 double precision :: eint_w(ixI^S)
1400 double precision :: de_thin, de_thick, emax_rem
1401 double precision :: T1, T2, p1(ixI^S), tau, xi
1402 double precision :: xi_arr(ixI^S), emax_rem_arr(ixI^S)
1403 double precision :: cool_fac, fip_prim, frac_lowFIP, fip_factor
1404 double precision :: y_loc, T_loc
1407 call fl%get_rho(wct,x,ixi^l,ixo^l,rho)
1408 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
1409 call fl%get_Te(wct,x,ixi^l,ixo^l,te)
1410 call fl%get_ne_nH(ixi^l, ixo^l, wct, ne, nh_arr)
1411 call fl%get_pthermal(w,x,ixi^l,ixo^l,pnew)
1412 call fl%get_rho(w,x,ixi^l,ixo^l,rhonew)
1413 if (fl%ionE) eint_w(ixo^s) =
phys_get_ei(w, ixi^l, ixo^l)
1415 fact = fl%lref*qdt/fl%tref
1419 {
do ix^db = ixo^lim^db\}
1422 emin = rhonew(ix^d)*fl%tlow*rfactor(ix^d)*invgam
1425 nh_val = rhonew(ix^d) / fl%nH2rhoFactor
1426 log_nh = dlog10(nh_val)
1427 if (fl%method ==
'analytic')
then
1430 y_loc = wct(ix^d, iw_ne) / nh_val
1431 eint_current = fl%inv_gamma_minus_1 * (1.0d0 + y_loc) * nh_val * t_loc &
1432 + y_loc * fl%eion_per_nH * nh_val
1434 log_p_nh = dlog10(pnew(ix^d) / nh_val)
1435 eint_current = pnew(ix^d) * fl%p2eint(log_nh, log_p_nh)
1437 lmax = max(zero, eint_w(ix^d) - emin) / qdt
1438 emax = max(zero, eint_w(ix^d) - emin)
1440 lmax = max(zero,pnew(ix^d)*invgam-emin)/qdt
1441 emax = max(zero,pnew(ix^d)*invgam-emin)
1445 if (te(ix^d) <= fl%tcoolmin) cycle
1450 if (fl%rad_newton)
then
1451 xi = exp(-pnew(ix^d) / fl%rad_newton_pthick)
1452 xi = min(max(xi, zero), one)
1458 if (fl%fip_ > 0)
then
1459 fip_prim = min(
maxfip, max(
minfip, wctprim(ix^d,fl%fip_)))
1462 fip_factor = one - frac_lowfip + fip_prim * frac_lowfip
1463 cool_fac = cool_fac * fip_factor
1467 if (
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) <= xprobmin1 + fl%rad_damp_height)
then
1468 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmin1-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1471 if (
slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) >= xprobmax1 - fl%rad_damp_height)
then
1472 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmax1+fl%rad_damp_height)**2/fl%rad_damp_scale**2)
1476 if( te(ix^d)>=fl%tcoolmax )
then
1478 if (fl%lambda_needs_nenh_table)
then
1479 l1 = l1 * nh_arr(ix^d) * nh_arr(ix^d)
1481 l1 = l1 * ne(ix^d) * nh_arr(ix^d)
1485 if(te(ix^d)<
block%wextra(ix^d,fl%Tcoff_))
then
1486 l1=l1*sqrt((te(ix^d)/
block%wextra(ix^d,fl%Tcoff_))**5)
1493 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
1501 call findy(te(ix^d),y1,fl)
1502 if (fl%lambda_needs_nenh_table)
then
1503 y2 = y1 + cool_fac * fact * nh_arr(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1504 / (rho(ix^d) * rfactor(ix^d))
1506 y2 = y1 + cool_fac * fact * ne(ix^d) * nh_arr(ix^d) * rc_gamma_1 &
1507 / (rho(ix^d) * rfactor(ix^d))
1509 call findt(tlocal2,y2,fl)
1514 if (fl%ionE .and. fl%Y_mod_built .and. &
1515 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1516 y1 =
findy_mod(te(ix^d), nh_arr(ix^d), fl)
1517 if (y1 == y1 .and. abs(y1) < huge(1.0d0))
then
1518 y2 = y1 + cool_fac * qdt
1519 tlocal2 =
findt_mod(y2, nh_arr(ix^d), fl)
1523 if(tlocal2<=fl%tcoolmin)
then
1525 else if (fl%ionE .and. &
1526 dabs(te(ix^d) - tlocal2) > 1.0d-4 * te(ix^d))
then
1528 de = (fl%eint_from_T(log_nh, dlog10(te(ix^d))) &
1529 - fl%eint_from_T(log_nh, dlog10(tlocal2))) * nh_val
1533 de = (te(ix^d)-tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
1536 if(te(ix^d)<
block%wextra(ix^d,fl%Tcoff_))
then
1537 de=de*sqrt((te(ix^d)/
block%wextra(ix^d,fl%Tcoff_))**5)
1544 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
1548 if (fl%rad_newton)
then
1550 emax_rem_arr(ix^d) = max(zero, emax - de_thin)
1555 if (fl%rad_newton)
then
1556 call fl%get_pthermal(w, x, ixi^l, ixo^l, p1)
1557 {
do ix^db = ixo^lim^db\}
1558 t1 = p1(ix^d) / (rho(ix^d) * rfactor(ix^d))
1559 tau = max(0.1d0 * sqrt( fl%rad_newton_rhosurf / rho(ix^d)), 4.d0 * qdt)
1560 t2 = fl%rad_newton_trad + (t1 - fl%rad_newton_trad) * exp(-qdt / tau)
1561 de_thick = min((one - xi_arr(ix^d)) * (t1 - t2) * rho(ix^d) * rfactor(ix^d) * invgam, emax_rem_arr(ix^d))
1562 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thick
1571 double precision,
intent(IN) :: tpoint
1572 double precision,
intent(OUT) :: lpoint
1576 lpoint =fl%l_PPL(fl%n_PPL) * ( tpoint / fl%t_PPL(fl%n_PPL) )**fl%a_PPL(fl%n_PPL)
1578 lpoint = fl%Lcool(fl%ncool) * sqrt( tpoint / fl%tcoolmax)
1585 double precision,
intent(in) :: tpoint
1588 double precision :: lgtp
1591 if (tpoint <= fl%tcool(1))
then
1594 else if (tpoint >= fl%tcool(fl%ncool))
then
1599 lgtp = dlog10(tpoint)
1600 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
1601 jl = max(1, min(fl%ncool-1, jl))
1604 + (tpoint - fl%tcool(jl)) &
1605 * (fl%frac_lowFIP(jl+1) - fl%frac_lowFIP(jl)) &
1606 / (fl%tcool(jl+1) - fl%tcool(jl))
1614 double precision,
intent(IN) :: tpoint
1615 double precision,
intent(OUT) :: Lpoint
1618 double precision :: lgtp
1622 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
1623 lpoint = fl%l_PPL(i) * (tpoint / fl%t_PPL(i))**fl%a_PPL(i)
1625 lgtp = dlog10(tpoint)
1626 jl = int((lgtp - fl%lgtcoolmin) /fl%lgstep) + 1
1627 lpoint = fl%Lcool(jl)+ (tpoint-fl%tcool(jl)) &
1628 * (fl%Lcool(jl+1)-fl%Lcool(jl)) &
1629 / (fl%tcool(jl+1)-fl%tcool(jl))
1632 end subroutine findl
1638 double precision,
intent(IN) :: tpoint
1639 double precision,
intent(OUT) :: Ypoint
1642 double precision :: lgtp
1643 double precision :: y_extra,factor
1647 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
1648 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
1649 if(fl%a_PPL(i)==1.d0)
then
1650 y_extra = log( fl%t_PPL(i) / tpoint )
1652 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / tpoint )**(fl%a_PPL(i)-1) )
1654 ypoint = fl%y_PPL(i) + factor*y_extra
1656 lgtp = dlog10(tpoint)
1657 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
1659 if(jl < 1 .or. jl >= fl%ncool)
then
1660 write(*,
'(a,es14.6,a,i0,a,2es14.6)') &
1661 'findY: tpoint=',tpoint,
' jl=',jl,
' out of bounds [1,ncool-1]; tcoolmin/max=', &
1662 fl%tcoolmin,fl%tcoolmax
1663 call mpistop(
'findY: temperature index out of bounds')
1665 ypoint = fl%Yc(jl)+ (tpoint-fl%tcool(jl)) &
1666 * (fl%Yc(jl+1)-fl%Yc(jl)) &
1667 / (fl%tcool(jl+1)-fl%tcool(jl))
1670 end subroutine findy
1679 double precision,
intent(OUT) :: tpoint
1680 double precision,
intent(IN) :: Ypoint
1683 double precision :: factor
1684 integer :: jl,jc,jh,i
1687 i = minloc(fl%y_PPL, dim=1, mask=fl%y_PPL>ypoint)
1688 factor = fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1) / (fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i))
1689 if(fl%a_PPL(i)==1.d0)
then
1690 tpoint = fl%t_PPL(i) * exp( -1.d0 * factor * ( ypoint - fl%y_PPL(i)))
1692 tpoint = fl%t_PPL(i) * (1 - (1 - fl%a_PPL(i)) * factor * (ypoint - fl%y_PPL(i)))**(1 / (1 - fl%a_PPL(i)))
1695 if(ypoint >= fl%Yc(1))
then
1696 tpoint = fl%tcoolmin
1697 else if (ypoint == fl%Yc(fl%ncool))
then
1698 tpoint = fl%tcoolmax
1705 if(ypoint <= fl%Yc(jc))
then
1712 tpoint = fl%tcool(jl)+ (ypoint-fl%Yc(jl)) &
1713 * (fl%tcool(jl+1)-fl%tcool(jl)) &
1714 / (fl%Yc(jl+1)-fl%Yc(jl))
1717 end subroutine findt
1725 double precision,
intent(IN) :: tpoint
1726 double precision,
intent(OUT) :: dLpoint
1729 double precision :: lgtp
1732 lgtp = dlog10(tpoint)
1733 jl = int((lgtp -fl%lgtcoolmin) / fl%lgstep) + 1
1734 dlpoint = fl%dLdtcool(jl)+ (tpoint-fl%tcool(jl)) &
1735 * (fl%dLdtcool(jl+1)-fl%dLdtcool(jl)) &
1736 / (fl%tcool(jl+1)-fl%tcool(jl))
1797 type(
rc_fluid),
intent(inout) :: fl
1799 integer :: i, j, k, n_nH, ncool, N_sub
1800 double precision :: log_nH_j, nH_j_code, u_lo, u_hi, du_total, du_step
1801 double precision :: u_s, log_u_s, T_s, y_s, ne_s, Lambda_s, integ
1802 double precision,
allocatable :: u_at_T(:), f_node(:)
1803 double precision :: Y_max_global, Y_min_global
1813 if (.not. fl%ionE)
return
1814 if (fl%isPPL)
return
1815 if (fl%Y_mod_built)
return
1821 n_nh = fl%Y_mod_n_nH
1823 if (
mype == 0)
write(*,*)
' build_Y_mod_table: no (rho,T) inverse table allocated; skipping'
1828 select case (trim(fl%Y_mod_quadrature))
1829 case (
'simpson',
'boole')
1832 call mpistop(
'build_Y_mod_table: rc_Y_mod_quadrature must be simpson or boole')
1836 n_sub = max(2, fl%Y_mod_N_sub)
1838 if (trim(fl%Y_mod_quadrature) ==
'boole')
then
1839 if (mod(n_sub, 4) /= 0) n_sub = n_sub + (4 - mod(n_sub, 4))
1842 if (mod(n_sub, 2) /= 0) n_sub = n_sub + 1
1845 fl%Y_mod_n_nH = n_nh
1847 fl%Y_mod_lg_nH_step_inv = dble(n_nh - 1) &
1848 / (fl%Y_mod_lg_nH_max - fl%Y_mod_lg_nH_min)
1850 fl%Y_mod_lg_nH_step_inv = 0.0d0
1853 allocate(fl%Y_mod(n_nh, ncool))
1854 allocate(fl%Y_mod_max_per_row(n_nh))
1855 allocate(u_at_t(ncool))
1856 allocate(f_node(0:n_sub))
1859 log_nh_j = fl%Y_mod_lg_nH_min &
1860 + dble(j - 1) * (fl%Y_mod_lg_nH_max - fl%Y_mod_lg_nH_min) / dble(max(1, n_nh - 1))
1861 nh_j_code = 10.0d0**log_nh_j
1865 u_at_t(i) = fl%eint_from_T(log_nh_j, dlog10(fl%tcool(i)))
1868 fl%Y_mod(j, ncool) = 0.0d0
1871 do i = ncool - 1, 1, -1
1873 u_hi = u_at_t(i + 1)
1874 du_total = u_hi - u_lo
1875 if (du_total <= 0.0d0)
then
1877 fl%Y_mod(j, i) = fl%Y_mod(j, i + 1)
1880 du_step = du_total / dble(n_sub)
1884 u_s = u_lo + dble(k) * du_step
1885 if (u_s <= 0.0d0)
then
1889 log_u_s = dlog10(u_s)
1890 t_s = fl%T_from_eint(log_nh_j, log_u_s)
1891 if (fl%lambda_needs_nenh_table)
then
1900 y_s = fl%y_from_eint(log_nh_j, log_u_s)
1901 ne_s = y_s * nh_j_code
1903 if (t_s <= fl%tcoolmin)
then
1907 else if (t_s >= fl%tcoolmax)
then
1910 call findl(t_s, lambda_s, fl)
1912 if (ne_s * lambda_s > 0.0d0)
then
1913 f_node(k) = 1.0d0 / (ne_s * lambda_s)
1919 select case (trim(fl%Y_mod_quadrature))
1926 fl%Y_mod(j, i) = fl%Y_mod(j, i + 1) + integ
1929 fl%Y_mod_max_per_row(j) = fl%Y_mod(j, 1)
1935 fl%Y_mod_built = .true.
1938 y_max_global = maxval(fl%Y_mod_max_per_row)
1939 y_min_global = minval(fl%Y_mod_max_per_row)
1940 write(*,
'(A,I0,A,I0,A,A,A,I0)') &
1941 ' Y_mod table built: ', n_nh,
' nH x ', ncool,
' T quadrature=', &
1942 trim(fl%Y_mod_quadrature),
' N_sub=', n_sub
1943 write(*,
'(A,F8.4,A,F8.4)') &
1944 ' log10 nH range = ', fl%Y_mod_lg_nH_min,
' to ', fl%Y_mod_lg_nH_max
1945 write(*,
'(A,ES12.4,A,ES12.4,A)') &
1946 ' Y_max per row range = [', y_min_global,
', ', y_max_global,
'] code time'
1947 write(*,
'(A)')
' inverse=bisect (row-interpolated, O(log ncool))'
1954 integer,
intent(in) :: n
1955 double precision,
intent(in) :: f(0:n), h
1956 double precision :: s
1960 s = s + 4.0d0 * f(k)
1963 s = s + 2.0d0 * f(k)
1971 integer,
intent(in) :: n
1972 double precision,
intent(in) :: f(0:n), h
1973 double precision :: s
1977 s = s + 7.0d0 * f(k) &
1978 + 32.0d0 * f(k + 1) &
1979 + 12.0d0 * f(k + 2) &
1980 + 32.0d0 * f(k + 3) &
1983 s = s * 2.0d0 * h / 45.0d0
1991 integer,
intent(in) :: ncool
1992 double precision,
intent(in) :: y_row(ncool), t_grid(ncool), y_target
1993 double precision :: log_t_out
1994 integer :: jl, jh, jc
1995 double precision :: f_lo, f_hi
1997 if (y_target <= y_row(ncool))
then
1998 log_t_out = dlog10(t_grid(ncool))
2001 if (y_target >= y_row(1))
then
2002 log_t_out = dlog10(t_grid(1))
2010 if (jh - jl <= 1)
exit
2012 if (y_row(jc) >= y_target)
then
2020 if (f_lo == f_hi)
then
2021 log_t_out = 0.5d0 * (dlog10(t_grid(jl)) + dlog10(t_grid(jh)))
2024 log_t_out = dlog10(t_grid(jl)) &
2025 + (y_target - f_lo) / (f_hi - f_lo) &
2026 * (dlog10(t_grid(jh)) - dlog10(t_grid(jl)))
2033 double precision,
intent(in) :: te_loc, nh_loc
2035 double precision :: y_out
2036 double precision :: log_nh, log_t, ry, rx
2037 integer :: jy, jy1, jx, jx1
2038 double precision :: fy, fx
2040 log_nh = dlog10(nh_loc)
2041 log_t = dlog10(te_loc)
2044 ry = (log_nh - fl%Y_mod_lg_nH_min) * fl%Y_mod_lg_nH_step_inv
2045 ry = max(0.0d0, min(ry, dble(fl%Y_mod_n_nH - 1)))
2047 jy1 = min(jy + 1, fl%Y_mod_n_nH - 1)
2050 rx = (log_t - fl%lgtcoolmin) / fl%lgstep
2051 rx = max(0.0d0, min(rx, dble(fl%ncool - 1)))
2053 jx1 = min(jx + 1, fl%ncool - 1)
2056 y_out = (1.0d0 - fy) * ((1.0d0 - fx) * fl%Y_mod(jy + 1, jx + 1) &
2057 + fx * fl%Y_mod(jy + 1, jx1 + 1)) &
2058 + fy * ((1.0d0 - fx) * fl%Y_mod(jy1 + 1, jx + 1) &
2059 + fx * fl%Y_mod(jy1 + 1, jx1 + 1))
2068 double precision,
intent(in) :: y_target, nh_loc
2070 double precision :: t_out
2071 double precision :: log_nh, ry, fy
2073 double precision :: log_t_lo, log_t_hi
2074 integer :: jl, jh, jc, ncool
2075 double precision :: yc_lo, yc_hi
2077 log_nh = dlog10(nh_loc)
2078 ry = (log_nh - fl%Y_mod_lg_nH_min) * fl%Y_mod_lg_nH_step_inv
2079 ry = max(0.0d0, min(ry, dble(fl%Y_mod_n_nH - 1)))
2081 jy1 = min(jy + 1, fl%Y_mod_n_nH - 1)
2085 yc_lo = (1.0d0 - fy) * fl%Y_mod(jy + 1, 1) + fy * fl%Y_mod(jy1 + 1, 1)
2086 yc_hi = (1.0d0 - fy) * fl%Y_mod(jy + 1, ncool) + fy * fl%Y_mod(jy1 + 1, ncool)
2087 if (y_target >= yc_lo)
then
2091 if (y_target <= yc_hi)
then
2098 if (jh - jl <= 1)
exit
2100 if (((1.0d0 - fy) * fl%Y_mod(jy + 1, jc) + fy * fl%Y_mod(jy1 + 1, jc)) &
2107 yc_lo = (1.0d0 - fy) * fl%Y_mod(jy + 1, jl) + fy * fl%Y_mod(jy1 + 1, jl)
2108 yc_hi = (1.0d0 - fy) * fl%Y_mod(jy + 1, jh) + fy * fl%Y_mod(jy1 + 1, jh)
2109 log_t_lo = dlog10(fl%tcool(jl))
2110 log_t_hi = dlog10(fl%tcool(jh))
2111 if (yc_lo == yc_hi)
then
2112 t_out = fl%tcool(jl)
2114 t_out = 10.0d0**(log_t_lo &
2115 + (y_target - yc_lo) / (yc_hi - yc_lo) * (log_t_hi - log_t_lo))
Scalar EoS inverse, e.g. fleint_from_T(log_nH, log_T)
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
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_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....
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)....
double precision, public lb_cool_accum
Per-rank cooling-only compute accumulator for lb_diagnose. Sums the wall time spent inside radiative_...
subroutine radiative_cooling_taper(ixd, x_ndim, rho_val, te_val, fl, factor)
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: bilinear interpolation in (log10 nH, log10 T) on the precomputed Y_mod table....
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)
subroutine getvar_cooling_exact(qdt, ixil, ixol, wct, w, x, coolrate, fl)
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