! ┓ ┏•┓ ┓┏┓ Licensed under the MIT License ! ┃┃┃┓┃┏┫┣ Copyright (c) 2025 Rodrigo Castro ! ┗┻┛┗┗┗┻┻ https://github.com/rodpcastro/wildf module wildf_exponential_integral !* # Exponential integral ! Exponential integrals. ! ! Procedures: ! ! - `ei`: Exponential integral \(\mathrm{Ei}(x)\) ! - `e1`: Exponential integral \(\mathrm{E}_1(x)\) or \(\mathrm{E}_1(z)\) ! ! ## References ! 1. Shanjie Zhang, Jianming Jin. 1996. Computation of Special Functions. !* Wiley, New York, NY. <https://search.worldcat.org/title/33971114> use wildf_kinds, only: i2, wp use wildf_constants, only: pi, gm, ninf, pinf use wildf_numerror, only: ismall implicit none private public :: ei, e1 interface e1 !! Exponential integral \(\mathrm{E}_1(x)\) or \(\mathrm{E}_1(z)\). module procedure e1x, e1z end interface e1 contains pure real(wp) function ei(x) !! Exponential integral \(\mathrm{Ei}(x)\). ! !! \(\lbrace x \in \mathbb{R} \mid x \neq 0 \rbrace\) real(wp), intent(in) :: x real(wp) :: r integer(i2) :: n if (x == 0.0_wp) then ei = ninf() else if (x < 0.0_wp) then ei = -e1x(-x) else if (x <= 40.0_wp) then ei = x r = x do n = 2, 101 r = r * x * (n-1) / n**2 ei = ei + r if (ismall(r, ei)) exit end do ei = ei + gm + log(x) else if (x <= 709.0_wp) then ei = 1.0_wp r = 1.0_wp do n = 1, 20 r = r * n / x ei = ei + r end do ei = exp(x) * ei / x else ei = pinf() end if end function ei pure real(wp) function e1x(x) !! Exponential integral \(\mathrm{E}_1(x)\). ! !! \(\lbrace x \in \mathbb{R} \mid x \gt 0 \rbrace\) real(wp), intent(in) :: x complex(wp) :: z, eoz real(wp) :: r integer(i2) :: n, m if (x == 0.0_wp) then e1x = pinf() else if (x < 0.0_wp) then z = cmplx(x, 0.0_wp, kind=wp) eoz = e1z(z) e1x = eoz%re else if (x <= 1.0_wp) then e1x = x r = x do n = 2, 26 r = r * x * (1-n) / n**2 e1x = e1x + r if (ismall(r, e1x)) exit end do e1x = e1x - gm - log(x) else if (x <= 738.0_wp) then m = int(20.0_wp + 80.0_wp/x, i2) r = 0.0_wp do n = m, 1, -1 r = n / (1.0_wp + n / (x + r)) end do e1x = exp(-x) / (x + r) else e1x = 0.0_wp end if end function e1x pure complex(wp) function e1z(z) !! Exponential integral \(\mathrm{E}_1(z)\). ! !! \(z \in \mathbb{C} \setminus \left( \lbrace z \in \mathbb{C} \mid \Re(z) \lt 0, !! \thinspace |\Im(z)| \lt 0.7 \rbrace \cup \lbrace 0 \rbrace \right)\) complex(wp), intent(in) :: z real(wp) :: zabs complex(wp) :: r integer(i2) :: n zabs = abs(z) if (zabs == 0.0_wp) then e1z = cmplx(pinf(), -pi, kind=wp) return else if (zabs <= 10.0_wp .or. z%re < 0.0_wp .and. zabs < 20.0_wp) then e1z = z r = z do n = 2, 151 r = r * z * (1-n) / n**2 e1z = e1z + r if (ismall(abs(r), abs(e1z))) exit end do e1z = e1z - gm - log(z) else if (z%re > 738.0_wp .or. (z%re >= 0 .and. abs(z%im) > huge(0.0_wp))) then e1z = (0.0_wp, 0.0_wp) return else if (z%re < -709.0_wp .and. z%im == 0.0_wp) then e1z = cmplx(ninf(), -pi, kind=wp) return else r = (0.0_wp, 0.0_wp) do n = 120, 1, -1 r = n / (1.0_wp + n / (z + r)) end do e1z = exp(-z) / (z + r) end if if (z%re < 0.0_wp .and. z%im == 0.0_wp) then e1z = cmplx(e1z%re, -pi, kind=wp) end if end function e1z end module wildf_exponential_integral