49 select case (
eos%method_id)
61 eos%update_eos => update_eos_lte
63 eos%get_temperature_from_eint => get_temperature_from_eint_lte
64 eos%get_Te => get_te_lte
67 eos%get_Rfactor => rfactor_from_lte
68 select case (
eos%method_id)
76 subroutine update_eos_lte(ixI^L, ixO^L, w, x)
79 integer,
intent(in) :: ixi^
l,ixo^
l
80 double precision,
intent(in) :: x(ixi^s,1:
ndim)
81 double precision,
intent(inout) :: w(ixi^s,1:nw)
83 double precision :: wlocal(ixi^s,1:nw)
84 double precision :: new_y(ixi^s)
85 double precision :: pth(ixi^s)
86 double precision :: nh_in(ixi^s), nh(ixi^s), eint_in(ixi^s)
87 double precision :: rfactor_fi
88 double precision :: yy
91 wlocal(ixi^s,1:nw)=w(ixi^s,1:nw)
94 pth(ixo^s) =
eos%gamma_minus_1 * wlocal(ixo^s,iw_e)
96 call eos%get_nH(w, x, ixi^
l, ixo^
l, nh)
103 wlocal(ixo^s,iw_e) = max(wlocal(ixo^s,iw_e), nh(ixo^s)*
eos%eint_nH_min)
105 nh_in(ixo^s) = dlog10(nh(ixo^s))
106 eint_in(ixo^s) = dlog10(wlocal(ixo^s,iw_e)) - nh_in(ixo^s)
111 rfactor_fi =
eos%n_per_nH_FI /
eos%nH2rhoFactor
113 {
do ix^db=ixomin^db,ixomax^db\}
114 if (wlocal(ix^
d,iw_e) / w(ix^
d,iw_rho) >
eos%eint_rho_FI_threshold)
then
116 new_y(ix^
d) =
eos%neOnH_FI
119 w(ix^
d,iw_te) =
eos%gamma_minus_1 &
120 * (wlocal(ix^
d,iw_e) -
eos%eion_per_nH * nh(ix^
d)) &
121 / (rfactor_fi * w(ix^
d,iw_rho))
123 w(ix^
d,iw_te) = pth(ix^
d) / (nh(ix^
d) * (1.0d0 +
eos%He_abundance + new_y(ix^
d)))
130 wlocal(ix^
d,iw_e) / nh(ix^
d), &
135 if (.not.
eos%ionE)
then
137 w(ix^
d,iw_te) = pth(ix^
d) / (nh(ix^
d) * (1.0d0 +
eos%He_abundance + new_y(ix^
d)))
142 call t_and_y_from_nh_eint(nh_in(ix^
d), eint_in(ix^
d), &
146 if (eint_in(ix^
d) <
eos%T%var2_max)
then
147 call t_and_y_from_nh_eint(nh_in(ix^
d), eint_in(ix^
d), &
152 new_y(ix^
d) =
eos%neOnH_FI
153 w(ix^
d,iw_te) =
eos%gamma_minus_1 &
154 * (wlocal(ix^
d,iw_e) -
eos%eion_per_nH * nh(ix^
d)) &
155 / (rfactor_fi * w(ix^
d,iw_rho))
162 w(ixo^s,iw_ne) = new_y(ixo^s) * nh(ixo^s)
164 end subroutine update_eos_lte
173 subroutine rfactor_from_lte(w,x,ixI^L,ixO^L,Rfactor)
175 integer,
intent(in) :: ixi^
l, ixo^
l
176 double precision,
intent(in) :: w(ixi^s,1:nw)
177 double precision,
intent(in) :: x(ixi^s,1:
ndim)
178 double precision,
intent(out):: rfactor(ixi^s)
180 double precision :: y_nh
183 {
do ix^db=ixomin^db,ixomax^db\}
184 y_nh = w(ix^
d, iw_ne) * eos%nH2rhoFactor / w(ix^
d, iw_rho)
185 rfactor(ix^
d) = (1.0d0 + eos%He_abundance + y_nh) / eos%nH2rhoFactor
188 end subroutine rfactor_from_lte
197 subroutine get_te_lte(w,x,ixI^L,ixO^L,T)
199 integer,
intent(in) :: ixi^
l, ixo^
l
200 double precision,
intent(in) :: w(ixi^s,1:nw)
201 double precision,
intent(in) :: x(ixi^s,1:
ndim)
202 double precision,
intent(out) :: t(ixi^s)
204 t(ixo^s) = w(ixo^s,iw_te)
206 end subroutine get_te_lte
208 subroutine get_temperature_from_eint_lte(w, x, ixI^L, ixO^L, res)
212 integer,
intent(in) :: ixi^l,ixo^l
213 double precision,
intent(in) :: x(ixi^s,1:ndim)
214 double precision,
intent(in) :: w(ixi^s,1:nw)
215 double precision,
intent(out) :: res(ixi^s)
217 double precision :: nh(ixi^s),nh_in(ixi^s), eint_in(ixi^s)
218 double precision :: rfactor_fi, t_loc, y_loc
221 rfactor_fi = eos%n_per_nH_FI / (1.0d0 + 4.0d0*eos%He_abundance)
223 call eos%get_nH(w, x, ixi^l, ixo^l, nh)
224 nh_in(ixo^s) = dlog10(nh(ixo^s))
225 eint_in(ixo^s) = dlog10(w(ixo^s,iw_e)) - nh_in(ixo^s)
227 {
do ix^db=ixomin^db,ixomax^db\}
228 if (w(ix^d,iw_e) / w(ix^d,iw_rho) > eos%eint_rho_FI_threshold)
then
230 res(ix^d) = eos%gamma_minus_1 &
231 * (w(ix^d,iw_e) - eos%eion_per_nH * nh(ix^d)) &
232 / (rfactor_fi * w(ix^d,iw_rho))
233 else if (eos%method_id == eos_analytic)
then
234 call saha_t_from_nh_eint(nh(ix^d), &
235 w(ix^d,iw_e) / nh(ix^d), t_loc, y_loc)
242 end subroutine get_temperature_from_eint_lte
256 integer,
intent(in) :: ixi^l,ixo^l
257 double precision,
intent(in) :: x(ixi^s,1:ndim)
258 double precision,
intent(in) :: w(ixi^s,1:nw)
259 double precision,
intent(out) :: res(ixi^s)
260 double precision,
intent(out),
optional :: ciso2(ixi^s)
262 double precision :: inv_rfactor_fi, rfactor_fi, eion_rho_inv, inv_nh2rho, onephe
263 double precision :: log_nh_val, log_eint_nh_val
264 double precision :: fx, fy, rx, ry, nh_loc, t_loc, y_loc
265 integer :: jx, jy, jx1, jy1, ix^d
266 logical :: want_ciso2
267 double precision,
parameter :: ln10 = 2.302585092994046d0
269 if (eos%type_id /= eos_type_lte)
call mpistop(
"get_temperature_from_eint_fast_LTE called outside its eos_type (LTE)")
270 call eos_timer_start()
272 want_ciso2 =
present(ciso2)
275 inv_rfactor_fi = (1.0d0 + 4.0d0*eos%He_abundance) / eos%n_per_nH_FI
276 rfactor_fi = eos%n_per_nH_FI / (1.0d0 + 4.0d0*eos%He_abundance)
277 eion_rho_inv = eos%eion_per_nH / eos%nH2rhoFactor
278 inv_nh2rho = 1.0d0 / eos%nH2rhoFactor
279 onephe = 1.0d0 + eos%He_abundance
283 res(ixo^s) = eos%gamma_minus_1 * inv_rfactor_fi &
284 * (w(ixo^s,iw_e) - eion_rho_inv * w(ixo^s,iw_rho)) &
286 if (want_ciso2) ciso2(ixo^s) = rfactor_fi * res(ixo^s)
289 {
do ix^db=ixomin^db,ixomax^db\}
290 if (w(ix^d,iw_e) <= eos%eint_rho_FI_threshold * w(ix^d,iw_rho))
then
291 if (eos%method_id == eos_analytic)
then
292 nh_loc = w(ix^d, iw_rho) / eos%nH2rhoFactor
293 call saha_t_from_nh_eint(nh_loc, &
294 w(ix^d,iw_e) / nh_loc, t_loc, y_loc)
296 if (want_ciso2) ciso2(ix^d) = (onephe + y_loc) * inv_nh2rho * t_loc
297 else if (eos%method_id == eos_entropy)
then
298 if (iw_log_nh > 0)
then
299 log_nh_val = block%wextra(ix^d, iw_log_nh)
301 log_nh_val = dlog10(w(ix^d, iw_rho) / eos%nH2rhoFactor)
303 log_eint_nh_val = dlog10(w(ix^d, iw_e)) - log_nh_val
305 call entropy_t_and_y_from_nh_eint(log_nh_val, log_eint_nh_val, &
308 ciso2(ix^d) = (onephe + y_loc) * inv_nh2rho * t_loc
310 res(ix^d) = entropy_t_from_nh_eint(log_nh_val, log_eint_nh_val)
313 if (iw_log_nh > 0)
then
314 log_nh_val = block%wextra(ix^d, iw_log_nh)
316 log_nh_val = dlog10(w(ix^d, iw_rho) / eos%nH2rhoFactor)
318 log_eint_nh_val = dlog10(w(ix^d, iw_e)) - log_nh_val
320 if (eos%T%is_uniform)
then
322 ry = max(0.0d0, min((log_nh_val - eos%T%var1_min) * eos%T%step_inv_1, &
324 rx = max(0.0d0, min((log_eint_nh_val - eos%T%var2_min) * eos%T%step_inv_2, &
326 jy = int(ry); jx = int(rx)
327 jy1 = min(jy+1, eos%T%dim1-1)
328 jx1 = min(jx+1, eos%T%dim2-1)
329 fy = ry - dble(jy); fx = rx - dble(jx)
330 res(ix^d) = dexp(ln10 * ( &
331 (1.0d0-fy)*((1.0d0-fx)*eos%T%table(jy+1,jx+1) &
332 + fx *eos%T%table(jy+1,jx1+1)) &
333 + fy *((1.0d0-fx)*eos%T%table(jy1+1,jx+1) &
334 + fx *eos%T%table(jy1+1,jx1+1))))
339 res(ix^d) = dexp(ln10 * bilinear_lookup( &
340 log_nh_val, log_eint_nh_val, eos%T))
342 if (want_ciso2) ciso2(ix^d) = (onephe &
343 +
y_from_nh_eint(log_nh_val, log_eint_nh_val)) * inv_nh2rho * res(ix^d)
348 call eos_timer_stop(timeeos_tfromei)
356 double precision,
intent(in) :: nh, eint_nh
357 double precision,
parameter :: ln10 = 2.302585092994046d0
358 double precision :: t_loc, y_loc, eint_rho
360 if (eos%type_id /= eos_type_lte)
call mpistop(
"y_from_nH_eint called outside its eos_type (LTE)")
361 if (eos%method_id == eos_analytic)
then
363 eint_rho = 10.0d0**eint_nh / eos%nH2rhoFactor
364 if (eint_rho > eos%eint_rho_FI_threshold)
then
365 result_val = eos%neOnH_FI
368 call saha_t_from_nh_eint(10.0d0**nh, 10.0d0**eint_nh, t_loc, y_loc)
370 else if (eos%method_id == eos_entropy)
then
371 result_val = entropy_y_from_nh_eint(nh, eint_nh)
373 result_val = dexp(ln10 * bicubic_lookup(nh, eint_nh, eos%neOnH))
379 double precision,
intent(in) :: nh, eint_nh
380 double precision,
parameter :: ln10 = 2.302585092994046d0
381 double precision :: t_loc, y_loc, eint_rho
383 if (eos%type_id /= eos_type_lte)
call mpistop(
"T_from_nH_eint called outside its eos_type (LTE)")
384 if (eos%method_id == eos_analytic)
then
386 eint_rho = 10.0d0**eint_nh / eos%nH2rhoFactor
387 if (eint_rho > eos%eint_rho_FI_threshold)
then
388 result_val = eos%gamma_minus_1 &
389 * (10.0d0**eint_nh - eos%eion_per_nH) / eos%n_per_nH_FI
392 call saha_t_from_nh_eint(10.0d0**nh, 10.0d0**eint_nh, t_loc, y_loc)
394 else if (eos%method_id == eos_entropy)
then
395 result_val = entropy_t_from_nh_eint(nh, eint_nh)
397 result_val = dexp(ln10 * bicubic_lookup(nh, eint_nh, eos%T))
403 subroutine t_and_y_from_nh_eint(log_nH, log_eint_nH, T_out, y_out)
404 double precision,
intent(in) :: log_nh, log_eint_nh
405 double precision,
intent(out) :: t_out, y_out
406 double precision,
parameter :: ln10 = 2.302585092994046d0
407 double precision :: results(3)
409 if (eos%method_id == eos_analytic)
then
410 call saha_t_from_nh_eint(10.0d0**log_nh, 10.0d0**log_eint_nh, t_out, y_out)
411 else if (eos%method_id == eos_entropy)
then
412 call entropy_t_and_y_from_nh_eint(log_nh, log_eint_nh, t_out, y_out)
413 else if (
allocated(eos%table_eint_il))
then
415 if (eos%T%is_uniform)
then
416 call interp_pchip_interleaved(log_nh, log_eint_nh, &
417 eos%table_eint_il, 3, eos%T%dim2, eos%T%dim1, &
418 eos%T%var1_min, eos%T%var1_max, &
419 eos%T%var2_min, eos%T%var2_max, results)
421 call interp_pchip_interleaved_nu(log_nh, log_eint_nh, &
422 eos%table_eint_il, 3, eos%T%dim2, eos%T%dim1, &
423 eos%T%var1_nodes, eos%T%var2_nodes, &
424 eos%T%guard_1, eos%T%guard_M_1, eos%T%guard_scale_1, &
425 eos%T%guard_2, eos%T%guard_M_2, eos%T%guard_scale_2, &
428 t_out = dexp(ln10 * results(1))
429 y_out = dexp(ln10 * results(2))
431 t_out = dexp(ln10 * bicubic_lookup(log_nh, log_eint_nh, eos%T))
432 y_out = dexp(ln10 * bicubic_lookup(log_nh, log_eint_nh, eos%neOnH))
434 end subroutine t_and_y_from_nh_eint
438 double precision,
intent(in) :: nh, ponh
439 double precision :: nh_code, p_code, t_loc, y_loc, eint_nh_loc, p_rho
441 if (eos%type_id /= eos_type_lte)
call mpistop(
"p2eint_from_nH_p called outside its eos_type (LTE)")
442 if (eos%method_id == eos_analytic)
then
444 p_code = nh_code * 10.0d0**ponh
446 p_rho = p_code / (nh_code * eos%nH2rhoFactor)
447 if (p_rho > eos%p_rho_FI_threshold)
then
448 result_val = eos%inv_gamma_minus_1 &
449 + eos%eion_per_nH * nh_code / p_code
452 call saha_state_from_nh_p(nh_code, p_code, t_loc, y_loc, eint_nh_loc)
453 result_val = eint_nh_loc * nh_code / p_code
454 else if (eos%method_id == eos_entropy)
then
455 result_val = entropy_eint_from_nh_p(nh, ponh)
457 result_val = bicubic_lookup(nh, ponh, eos%p2eint)
463 double precision,
intent(in) :: log_nh, log_p_nh
464 if (eos%type_id /= eos_type_lte)
call mpistop(
"gamma1_from_nH_p called outside its eos_type (LTE)")
465 if (eos%method_id == eos_entropy)
then
466 g1 = entropy_gamma1_from_nh_p(log_nh, log_p_nh)
468 g1 = bicubic_lookup(log_nh, log_p_nh, eos%gamma1_p)
475 double precision,
intent(in) :: pres, rho_val
476 double precision :: nh_val
477 if (pres/rho_val > eos%p_rho_FI_threshold)
then
480 nh_val = rho_val/eos%nH2rhoFactor
486 double precision function log_p_from_nh_eint(log_nH, log_eint_nH)
result(lp)
487 double precision,
intent(in) :: log_nh, log_eint_nh
488 lp = bicubic_lookup(log_nh, log_eint_nh, eos%log_p)
489 end function log_p_from_nh_eint
493 double precision,
intent(in) :: log_nh, log_eint_nh
494 double precision,
parameter :: ln10 = 2.302585092994046d0
495 double precision :: t_loc, y_loc
497 if (eos%type_id /= eos_type_lte)
call mpistop(
"p_nH_from_eint called outside its eos_type (LTE)")
498 if (eos%method_id == eos_analytic)
then
499 call saha_t_from_nh_eint(10.0d0**log_nh, 10.0d0**log_eint_nh, t_loc, y_loc)
500 p_nh = (1.0d0 + eos%He_abundance + y_loc) * t_loc
501 else if (eos%method_id == eos_entropy)
then
502 p_nh = entropy_p_nh_from_eint(log_nh, log_eint_nh)
504 p_nh = dexp(ln10 * bicubic_lookup(log_nh, log_eint_nh, eos%p_over_nH))
511 double precision,
intent(in) :: log_nh, log_t
512 double precision,
parameter :: ln10 = 2.302585092994046d0
513 double precision :: log_e_nh
515 if (eos%type_id /= eos_type_lte)
call mpistop(
"eint_nH_from_T called outside its eos_type (LTE)")
516 if (eos%method_id == eos_entropy)
then
517 log_e_nh = entropy_eint_from_nh_t(log_nh, log_t)
518 eint_nh = 10.0d0**log_e_nh
519 else if (
allocated(eos%eint_from_T%table))
then
520 eint_nh = dexp(ln10 * bicubic_lookup(log_nh, log_t, eos%eint_from_T))
522 eint_nh = saha_eint_from_nh_t(10.0d0**log_nh, 10.0d0**log_t)
540 subroutine log_p_bisect_cached(log_nH, log_p_target, &
541 log_eint_lo, log_eint_hi, max_iter, log_eint_result)
543 double precision,
intent(in) :: log_nh, log_p_target
544 double precision,
intent(inout) :: log_eint_lo, log_eint_hi
545 integer,
intent(in) :: max_iter
546 double precision,
intent(out) :: log_eint_result
548 integer :: nx, ny, ix, iy, iter, ii
549 integer :: i0, i1, i2, i3, j0, j1, j2, j3
550 double precision :: tx, ty, rx, ry
551 double precision :: xstep_inv, ystep_inv
552 double precision :: vmin_x, vmax_x, vmin_y, vmax_y
553 double precision :: log_eint_mid, log_p_eval
557 double precision :: tv(4,4)
563 is_unif = eos%log_p%is_uniform
566 vmin_x = eos%log_p%var2_min
567 vmax_x = eos%log_p%var2_max
568 vmin_y = eos%log_p%var1_min
569 vmax_y = eos%log_p%var1_max
570 xstep_inv = dble(nx-1) / (vmax_x - vmin_x)
571 ystep_inv = dble(ny-1) / (vmax_y - vmin_y)
576 ry = (log_nh - vmin_y) * ystep_inv
577 ry = max(0.0d0, min(ry, dble(ny-1)))
582 if (log_nh <= eos%log_p%var1_nodes(1))
then
584 else if (log_nh >= eos%log_p%var1_nodes(ny))
then
585 iy = ny - 2; ty = 1.0d0
587 ii = find_index_guard(eos%log_p%var1_nodes, ny, log_nh, &
588 eos%log_p%guard_1, eos%log_p%guard_M_1, eos%log_p%guard_scale_1)
589 iy = max(0, min(ii - 2, ny - 2))
590 ty = (log_nh - eos%log_p%var1_nodes(iy+1)) &
591 / (eos%log_p%var1_nodes(iy+2) - eos%log_p%var1_nodes(iy+1))
592 ty = max(0.0d0, min(ty, 1.0d0))
597 j0 = max(0, min(ny-1, iy-1))
598 j1 = max(0, min(ny-1, iy ))
599 j2 = max(0, min(ny-1, iy+1))
600 j3 = max(0, min(ny-1, iy+2))
604 do iter = 1, max_iter
605 log_eint_mid = 0.5d0 * (log_eint_lo + log_eint_hi)
609 rx = (log_eint_mid - vmin_x) * xstep_inv
610 rx = max(0.0d0, min(rx, dble(nx-1)))
615 if (log_eint_mid <= eos%log_p%var2_nodes(1))
then
617 else if (log_eint_mid >= eos%log_p%var2_nodes(nx))
then
618 ix = nx - 2; tx = 1.0d0
620 ii = find_index_guard(eos%log_p%var2_nodes, nx, log_eint_mid, &
621 eos%log_p%guard_2, eos%log_p%guard_M_2, eos%log_p%guard_scale_2)
622 ix = max(0, min(ii - 2, nx - 2))
623 tx = (log_eint_mid - eos%log_p%var2_nodes(ix+1)) &
624 / (eos%log_p%var2_nodes(ix+2) - eos%log_p%var2_nodes(ix+1))
625 tx = max(0.0d0, min(tx, 1.0d0))
630 if (ix /= ix_cached)
then
631 i0 = max(0, min(nx-1, ix-1))
632 i1 = max(0, min(nx-1, ix ))
633 i2 = max(0, min(nx-1, ix+1))
634 i3 = max(0, min(nx-1, ix+2))
636 tv(1,1) = eos%log_p%table(j0+1, i0+1)
637 tv(1,2) = eos%log_p%table(j0+1, i1+1)
638 tv(1,3) = eos%log_p%table(j0+1, i2+1)
639 tv(1,4) = eos%log_p%table(j0+1, i3+1)
640 tv(2,1) = eos%log_p%table(j1+1, i0+1)
641 tv(2,2) = eos%log_p%table(j1+1, i1+1)
642 tv(2,3) = eos%log_p%table(j1+1, i2+1)
643 tv(2,4) = eos%log_p%table(j1+1, i3+1)
644 tv(3,1) = eos%log_p%table(j2+1, i0+1)
645 tv(3,2) = eos%log_p%table(j2+1, i1+1)
646 tv(3,3) = eos%log_p%table(j2+1, i2+1)
647 tv(3,4) = eos%log_p%table(j2+1, i3+1)
648 tv(4,1) = eos%log_p%table(j3+1, i0+1)
649 tv(4,2) = eos%log_p%table(j3+1, i1+1)
650 tv(4,3) = eos%log_p%table(j3+1, i2+1)
651 tv(4,4) = eos%log_p%table(j3+1, i3+1)
657 log_p_eval = pchip_2d_from_cache(tv, tx, ty)
659 if (log_p_eval < log_p_target)
then
660 log_eint_lo = log_eint_mid
662 log_eint_hi = log_eint_mid
665 if (dabs(log_eint_hi - log_eint_lo) < 1.0d-14)
exit
668 log_eint_result = 0.5d0 * (log_eint_lo + log_eint_hi)
672 pure double precision function pchip_1d(p0, p1, p2, p3, t)
result(v)
673 double precision,
intent(in) :: p0, p1, p2, p3, t
674 double precision :: d0, d1, d2, m1, m2, s, a1, a2, lim
675 double precision :: tt, ttt, h00, h10, h01, h11
677 d0 = p1 - p0; d1 = p2 - p1; d2 = p3 - p2
679 if (d1 == 0.0d0)
then
680 m1 = 0.0d0; m2 = 0.0d0
682 if (d0*d1 <= 0.0d0)
then
685 m1 = 2.0d0*d0*d1 / (d0 + d1)
687 if (d1*d2 <= 0.0d0)
then
690 m2 = 2.0d0*d1*d2 / (d1 + d2)
694 if (a1 < 0.0d0) a1 = 0.0d0
695 if (a2 < 0.0d0) a2 = 0.0d0
697 if (a1 > lim) a1 = lim
698 if (a2 > lim) a2 = lim
703 h00 = 2.0d0*ttt - 3.0d0*tt + 1.0d0
704 h10 = ttt - 2.0d0*tt + t
705 h01 = -2.0d0*ttt + 3.0d0*tt
707 v = h00*p1 + h10*m1 + h01*p2 + h11*m2
710 pure double precision function pchip_2d_from_cache(c, tx, ty)
result(z)
711 double precision,
intent(in) :: c(4,4), tx, ty
712 double precision :: g0, g1, g2, g3
714 g0 =
pchip_1d(c(1,1), c(1,2), c(1,3), c(1,4), tx)
715 g1 =
pchip_1d(c(2,1), c(2,2), c(2,3), c(2,4), tx)
716 g2 =
pchip_1d(c(3,1), c(3,2), c(3,3), c(3,4), tx)
717 g3 =
pchip_1d(c(4,1), c(4,2), c(4,3), c(4,4), tx)
720 end function pchip_2d_from_cache
722 end subroutine log_p_bisect_cached
729 double precision,
intent(in) :: log_nh_val, log_p_val
730 double precision,
intent(out) :: log_eint_nh_out
732 double precision :: log_p_target, p2eint_ratio, log_eint_guess
733 double precision :: log_p_at_guess, log_eint_lo, log_eint_hi
734 double precision :: f_bracket, margin
735 double precision :: eint_lim_lo, eint_lim_hi
738 if (eos%type_id /= eos_type_lte)
call mpistop(
"eint_from_p_bisect called outside its eos_type (LTE)")
739 log_p_target = log_p_val - log_nh_val
743 if (eos%log_p%is_uniform)
then
744 eint_lim_lo = eos%log_p%var2_min
745 eint_lim_hi = eos%log_p%var2_max
747 eint_lim_lo = eos%log_p%var2_nodes(1)
748 eint_lim_hi = eos%log_p%var2_nodes(eos%log_p%dim2)
753 log_eint_guess = dlog10(p2eint_ratio) + log_p_target
755 log_eint_guess = max(log_eint_guess, eint_lim_lo)
756 log_eint_guess = min(log_eint_guess, eint_lim_hi)
758 log_p_at_guess = log_p_from_nh_eint(log_nh_val, log_eint_guess)
762 if (log_p_at_guess < log_p_target)
then
763 log_eint_lo = log_eint_guess
764 log_eint_hi = min(log_eint_guess + margin, eint_lim_hi)
765 f_bracket = log_p_from_nh_eint(log_nh_val, log_eint_hi) - log_p_target
767 log_eint_lo = max(log_eint_guess - margin, eint_lim_lo)
768 log_eint_hi = log_eint_guess
769 f_bracket = -(log_p_from_nh_eint(log_nh_val, log_eint_lo) - log_p_target)
772 if (f_bracket >= 0.0d0)
then
775 log_eint_lo = eint_lim_lo
776 log_eint_hi = eint_lim_hi
780 call log_p_bisect_cached(log_nh_val, log_p_target, &
781 log_eint_lo, log_eint_hi, max_iter, log_eint_nh_out)
795 integer,
intent(out) :: n_nh
796 double precision,
intent(out) :: lg_nh_min, lg_nh_max
798 if (eos%type_id /= eos_type_lte)
call mpistop(
"eos_get_eintT_grid called outside its eos_type (LTE)")
799 if (
allocated(eos%eint_from_T%table))
then
800 n_nh = eos%eint_from_T%dim1
801 lg_nh_min = eos%eint_from_T%var1_min
802 lg_nh_max = eos%eint_from_T%var1_max
803 else if (
allocated(eos%eintT%table))
then
804 n_nh = eos%eintT%dim1
805 lg_nh_min = eos%eintT%var1_min
806 lg_nh_max = eos%eintT%var1_max
816 double precision function lte_p_from_eint(eint_val,nH_val,log_nH_val,inv_rho)
result(pres)
817 double precision,
intent(in) :: eint_val, nh_val, log_nh_val, inv_rho
818 double precision :: e_use
819 if (.not. eos%ionE)
then
820 pres = eos%gamma_minus_1 * eint_val
824 e_use = max(eint_val, nh_val*eos%eint_nH_min, smalldouble)
825 if (e_use*inv_rho > eos%eint_rho_FI_threshold)
then
826 pres = eos%gamma_minus_1*(e_use - eos%eion_per_nH*nh_val)
827 else if (eos%method_id == eos_entropy)
then
828 pres = entropy_p_from_eint(log_nh_val, dlog10(e_use) - log_nh_val)
830 pres = nh_val *
p_nh_from_eint(log_nh_val, dlog10(e_use) - log_nh_val)
835 double precision function lte_eint_from_p(pres,nH_val,log_nH_val,rho_val)
result(eint)
836 double precision,
intent(in) :: pres, nh_val, log_nh_val, rho_val
837 double precision :: t_solve, y_solve, eint_nh_solve, log_eint_mid
838 if (.not. eos%ionE)
then
839 eint = pres*eos%inv_gamma_minus_1
842 if (pres/rho_val > eos%p_rho_FI_threshold)
then
843 eint = pres*eos%inv_gamma_minus_1 + eos%eion_per_nH*nh_val
844 else if (eos%method_id == eos_analytic)
then
845 call saha_state_from_nh_p(nh_val, pres, t_solve, y_solve, eint_nh_solve)
846 eint = eint_nh_solve*nh_val
847 else if (eos%p2eint_bisect)
then
848 if (eos%method_id == eos_entropy)
then
849 call entropy_eint_from_p_bisect(log_nh_val, dlog10(pres) - log_nh_val, log_eint_mid)
850 eint = nh_val*10.0d0**log_eint_mid
853 eint = nh_val*max(10.0d0**log_eint_mid, eos%eint_nH_min)
pure double precision function pchip_1d(p0, p1, p2, p3, t)
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
EoS state container – the single thermodynamic authority for AMRVAC.
integer, parameter, public eos_analytic
integer, parameter, public eos_entropy
type(eos_container), allocatable, public eos
The single EoS state object, allocated in eos_init and shared (read-mostly) across all EoS sub-module...
Interpolation kernels for the EoS tables (pure math; no EoS state).
Entropy-method LTE EoS: every query is ONE bicubic Hermite evaluation.
subroutine, public finalise_entropy_lte()
Entropy-method finalise: shift each loaded table's axes from CGS to code units and run the standard p...
subroutine, public load_entropy_lte()
Forward (log nH, log eint/nH) -> thermodynamic state.
Analytic hydrogen Saha EoS with neutral helium (eos_method == 'analytic').
subroutine, public finalise_analytic_lte()
Analytic-method finalise: no table unit conversion needed; build the Gamma1 table only for 'exact' mo...
subroutine, public saha_t_from_nh_eint(nh_code, eint_nh_code, t_out, y_out)
Temperature and ionisation fraction from (nH, eint/nH) in code units, by bisection.
subroutine, public load_analytic_lte()
Analytic-method load: no binary tables (on-the-fly Saha solve); just announce the method.
'state' method (eos_method='state', legacy 'tables') of the LTE EoS family.
subroutine, public finalise_state_lte()
Table-based method finalise: shift the loaded T/neOnH (and ionE-derived) tables to code units,...
subroutine, public load_state_lte()
state arms of the eos_init / eos_finalise dispatchers (mod_eos_lte)
Shared LTE lookup-table infrastructure (build/IO; not on the hot path).
LTE (Saha-table) EoS kernels and finalise for the eos% family.
double precision function, public lte_eint_from_p(pres, nh_val, log_nh_val, rho_val)
LTE internal energy from pressure in one cell: FI bypass, else eint(nH, p).
double precision function, public p_nh_from_eint(log_nh, log_eint_nh)
p/nH = (1 + He + y) T from (log10 nH, log10 eint/nH)
subroutine, public get_temperature_from_eint_fast_lte(w, x, ixil, ixol, res, ciso2)
double precision function, public p2eint_from_nh_p(nh, ponh)
Ratio eint/p from (log10 nH, log10 p/nH).
subroutine, public eos_finalise_lte()
LTE arm of eos_finalise: wire the LTE runtime pointer targets, then dispatch on eos_method to the per...
double precision function, public eint_nh_from_t(log_nh, log_t)
eint/nH from (log10 nH, log10 T), from the inverse table when one is built and the Saha solve otherwi...
subroutine, public eint_from_p_bisect(log_nh_val, log_p_val, log_eint_nh_out)
Given log10(nH) and log10(p), find log10(eint/nH) by table-guessed bisection on the forward pressure ...
double precision function, public y_from_nh_eint(nh, eint_nh)
Scalar EoS kernels: one cell on (log10 nH, log10 eint/nH) or (log10 nH, log10 p/nH),...
subroutine, public eos_get_eintt_grid(n_nh, lg_nh_min, lg_nh_max)
####################################################################### Table-metadata helpers: expos...
double precision function, public lte_gamma1_from_p(pres, rho_val)
Gamma_1 of one cell from (p, rho): the ideal value where fully ionised, else the pressure- indexed ta...
double precision function, public gamma1_from_nh_p(log_nh, log_p_nh)
Gamma_1 from (log10 nH, log10 p/nH), one lookup on the pressure-indexed table.
subroutine, public eos_init_lte()
update_eos_LTE, get_Te_LTE, get_temperature_from_eint_LTE and Rfactor_from_LTE are PRIVATE: all bound...
double precision function, public t_from_nh_eint(nh, eint_nh)
Temperature from (log10 nH, log10 eint/nH).
double precision function, public lte_p_from_eint(eint_val, nh_val, log_nh_val, inv_rho)
LTE pressure from internal energy in one cell: ideal without ionE, else the table floor,...
Shared EoS accessors (EoS-type-agnostic) for the eos% family.
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer, parameter ndim
Number of spatial dimensions for grid variables.
double precision, dimension(:), allocatable, parameter d
A Fortran 90 module for creating 1D and 2D lookup tables. These tables can be used to efficiently int...
pure integer function, public find_index_bsearch(list, val)
Binary search of sorted list for the smallest ix such that list(ix) >= val. On failure,...
This module defines the procedures of a physics module. It contains function pointers for the various...
procedure(sub_e_to_ei), pointer phys_e_to_ei
subroutine eos_timer_start()
Open an EoS timing window; inside an OpenMP parallel region the EoS is not timed.
subroutine eos_timer_stop(acc)
Close an EoS timing window, adding its time to acc when it is the outermost.
double precision timeeos_tfromei