Source code for UFalcon.bessel
import numpy as np
from scipy import special, optimize
[docs]def get_jl(x, ell):
"""
Returns the spherical bessel function at x for mode ell.
:param x: x coordinate.
:type x: float
:param ell: Desired spherical Bessel mode.
:type ell: int
:return: Spherical Bessel Function value at x for mode ell.
:rtype: float
"""
return special.spherical_jn(ell, x)
[docs]def get_der_jl(x, ell):
"""
Returns the spherical bessel function derivative at x for mode ell.
:param x: x coordinate.
:type x: float
:param ell: Desired spherical Bessel mode.
:type ell: int
:return: Derivative of the Spherical Bessel Function value at x for mode ell.
:rtype: float
"""
return special.spherical_jn(ell, x, derivative=True)
[docs]def get_qln(ell, nmax, nstop=100, zerolminus2=None, zerolminus1=None):
"""
Returns the zeros of the spherical Bessel function. Begins by assuming
that the zeros of the spherical Bessel function for l lie exactly between
the zeros of the Bessel function between l and l+1. This allows us to use
scipy's jn_zeros function. However, this function fails to return for high n.
To work around this we estimate the first 100 zeros using scipy's jn_zero
function and then iteratively find the roots of the next zero by assuming the
next zero occurs pi away from the last one. Brent's method is then used to
find a zero between pi/2 and 3pi/2 from the last zero.
:param ell: Desired spherical Bessel mode.
:type ell: int
:param nmax: The maximum zero found for the spherical Bessel Function.
:type nmax: int
:param nstop: For n <= nstop we use scipy's jn_zeros to guess where the first nstop zeros are. These estimates are improved using Brent's method and assuming zeros lie between -pi/2 and pi/2 from the estimates.
:type nstop: int
:return: Derivative of the Spherical Bessel Function value at x for mode ell.
:rtype: float
"""
if nmax <= nstop:
nstop = nmax
if zerolminus2 is None and zerolminus1 is None:
z1 = special.jn_zeros(ell, nstop)
z2 = special.jn_zeros(ell + 1, nstop)
zeros_approx = np.ndarray.tolist(0.5 * (z1 + z2))
zeros = []
for i in range(0, len(zeros_approx)):
a = zeros_approx[i] - 0.5 * np.pi
b = zeros_approx[i] + 0.5 * np.pi
val = optimize.brentq(get_jl, a, b, args=(ell))
zeros.append(val)
if nstop != nmax:
n = nstop
while n < nmax:
zero_last = zeros[-1]
a = zero_last + 0.5 * np.pi
b = zero_last + 1.5 * np.pi
val = optimize.brentq(get_jl, a, b, args=(ell))
zeros.append(val)
n += 1
else:
dz = zerolminus1 - zerolminus2
z1 = zerolminus1 + 0.5 * dz
z2 = zerolminus2 + 1.5 * dz
zeros_approx = np.ndarray.tolist(0.5 * (z1 + z2))
zeros = []
for i in range(0, len(zeros_approx)):
a = zeros_approx[i] - 0.5 * np.pi
b = zeros_approx[i] + 0.5 * np.pi
val = optimize.brentq(get_jl, a, b, args=(ell))
zeros.append(val)
zeros = np.array(zeros)
return zeros
[docs]def get_der_qln(ell, nmax, nstop=100, zerolminus2=None, zerolminus1=None):
"""
Returns the zeros of the spherical Bessel function derivative. Begins by
assuming that the zeros of the spherical Bessel function for l lie exactly
between the zeros of the Bessel function between l and l+1. This allows us
to use scipy's jn_zeros function. However, this function fails to return for
high n. To work around this we estimate the first 100 zeros using scipy's
jn_zero function and then iteratively find the roots of the next zero by
assuming the next zero occurs pi away from the last one. Brent's method is
then used to find a zero between pi/2 and 3pi/2 from the last zero.
:param ell: Desired spherical Bessel mode.
:type ell: int
:param nmax: The maximum zero found for the spherical Bessel Function.
:type nmax: int
:param nstop: For n <= nstop we use scipy's jn_zeros to guess where the first nstop zeros are. These estimates are improved using Brent's method and assuming zeros lie between -pi/2 and pi/2 from the estimates.
:type nstop: int
:return: Derivative of the Spherical Bessel Function value at x for mode ell.
:rtype: float
"""
if nmax <= nstop:
nstop = nmax
if zerolminus2 is None and zerolminus1 is None:
z1 = special.jnp_zeros(ell, nstop)
z2 = special.jnp_zeros(ell + 1, nstop)
zeros_approx = np.ndarray.tolist(0.5 * (z1 + z2))
zeros = []
for i in range(0, len(zeros_approx)):
a = zeros_approx[i] - 0.5 * np.pi
b = zeros_approx[i] + 0.5 * np.pi
val = optimize.brentq(get_der_jl, a, b, args=(ell))
zeros.append(val)
if nstop != nmax:
n = nstop
while n < nmax:
zero_last = zeros[-1]
a = zero_last + 0.5 * np.pi
b = zero_last + 1.5 * np.pi
val = optimize.brentq(get_der_jl, a, b, args=(ell))
zeros.append(val)
n += 1
else:
dz = zerolminus1 - zerolminus2
z1 = zerolminus1 + 0.5 * dz
z2 = zerolminus2 + 1.5 * dz
zeros_approx = np.ndarray.tolist(0.5 * (z1 + z2))
zeros = []
for i in range(0, len(zeros_approx)):
a = zeros_approx[i] - 0.5 * np.pi
b = zeros_approx[i] + 0.5 * np.pi
val = optimize.brentq(get_der_jl, a, b, args=(ell))
zeros.append(val)
zeros = np.array(zeros)
return zeros