Skip to content

Commit 01204af

Browse files
Bessel zero finding cleanup (#596)
* docstring for besselj_zeros * rest of docstrings * remove pdb import * second order differences comment * comments and docstring for num_besselj_zeros * formatting * tiny fixes; * docstring fixes * NumPy * NumPy again * sanity check * parentheses inside sentence
1 parent 05b561f commit 01204af

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/aspire/basis/basis.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ def _getfbzeros(self):
6161

6262
# generate zeros of Bessel functions for each ell
6363
for ell in range(upper_bound):
64+
# for each ell, num_besselj_zeros returns the zeros of the
65+
# order ell Bessel function which are less than 2*pi*c*R = nres*pi/2,
66+
# the truncation rule for the Fourier-Bessel expansion
6467
_n, _zeros = num_besselj_zeros(
6568
ell + (self.ndim - 2) / 2, self.nres * np.pi / 2
6669
)

src/aspire/basis/basis_utils.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,47 @@
1616

1717

1818
def check_besselj_zeros(nu, z):
19+
"""
20+
Sanity-check a sequence of estimated zeros of the Bessel function with order `nu`.
21+
:param nu: The real number order of the Bessel function.
22+
:param z: (Array-like) A sequence of postulated zeros.
23+
:return result: True or False.
24+
"""
25+
# Compute first and second order differences of the sequence of zeros
1926
dz = np.diff(z)
2027
ddz = np.diff(dz)
2128

29+
# Check criteria for acceptable zeros
2230
result = True
31+
# Real roots
2332
result = result and all(np.isreal(z))
33+
# All roots should be > 0, check first of increasing sequence
2434
result = result and z[0] > 0
35+
# Spacing between zeros is greater than 3
2536
result = result and all(dz > 3)
2637

38+
# Second order differences should be zero or just barely increasing to
39+
# within 16x machine precision.
2740
if nu >= 0.5:
2841
result = result and all(ddz < 16 * np.spacing(z[1:-1]))
42+
# For nu < 0.5 the spacing will be slightly decreasing, so flip the sign
2943
else:
3044
result = result and all(ddz > -16 * np.spacing(z[1:-1]))
3145

3246
return result
3347

3448

3549
def besselj_newton(nu, z0, max_iter=10):
50+
"""
51+
Uses the Newton-Raphson method to compute the zero(s) of the
52+
Bessel function with order `nu` with initial guess(es) `z0`.
53+
54+
:param nu: The real number order of the Bessel function.
55+
:param z0: (Array-like) The initial guess(es) for the root-finding algorithm.
56+
:param max_iter: Maximum number of iterations for Newton-Raphson
57+
(default: 10).
58+
:return z: (Array-like) The estimated root(s).
59+
"""
3660
z = z0
3761

3862
# Factor worse than machine precision
@@ -157,6 +181,14 @@ def real_sph_harmonic(j, m, theta, phi):
157181

158182

159183
def besselj_zeros(nu, k):
184+
"""
185+
Finds the first `k` zeros of the Bessel function of order `nu`, i.e. J_nu.
186+
Adapted from "zerobess.m" by Jonas Lundgren <[email protected]>
187+
188+
:param nu: The real number order of the Bessel function (must be positive and <1e7).
189+
:param k: The number of zeros to return (must be >= 3).
190+
:return z: A 1D NumPy array of the first `k` zeros.
191+
"""
160192
assert k >= 3, "k must be >= 3"
161193
assert 0 <= nu <= 1e7, "nu must be between 0 and 1e7"
162194

@@ -216,12 +248,24 @@ def besselj_zeros(nu, k):
216248

217249

218250
def num_besselj_zeros(ell, r):
251+
"""
252+
Compute the zeros of the order `ell` Bessel function which are less than `r`.
253+
254+
:param ell: The real number order of the Bessel function.
255+
:param r: The upper bound for zeros returned.
256+
:return n, r0: The number of zeros and the zeros themselves
257+
as a NumPy array.
258+
"""
219259
k = 4
260+
# get the first 4 zeros
220261
r0 = besselj_zeros(ell, k)
221262
while all(r0 < r):
263+
# increase the number of zeros sought
264+
# until one of the zeros is greater than `r`
222265
k *= 2
223266
r0 = besselj_zeros(ell, k)
224267
r0 = r0[r0 < r]
268+
# return the number of zeros and the zeros themselves
225269
return len(r0), r0
226270

227271

0 commit comments

Comments
 (0)