pytrunc.utils module#

Numerical utilities.

This module provides the numerical routines used by the phase and truncation modules: the Legendre polynomials and their derivatives, the Bessel functions of the first kind, and the Lobatto quadrature abscissas, weights and integration.

pytrunc.utils.bessel_j1(x: ArrayLike, acc: float = 1e-08, max_iter: int = 50) ndarray[tuple[Any, ...], dtype[float64]][source]#

The Bessel first kind function J1(x) of order 1

Parameters:
xndarray

The variable x of J1(x), it must be 1-D

accfloat, optional

The tolerance for numerical errors. Default is 1e-8

max_iterint, optional

The maximum number of iterations trying to improve the error accuracy. Default is 50

Returns:
ndarray

The values of the Bessel function J1(x), a 1-D ndarray with the same shape as x

Notes

The scipy equivalent -> scipy.special.j1(x)

Examples

>>> import numpy as np
>>> from pytrunc.utils import bessel_j1
>>> x = np.array([0.0, 1.0, 2.0])
>>> bessel_j1(x)
array([0.        , 0.44005059, 0.57672481])
pytrunc.utils.bessel_j1_derivative(x: ArrayLike, acc: float = 1e-08, max_iter: int = 50) ndarray[tuple[Any, ...], dtype[float64]][source]#

Compute the Bessel first kind derivative of order 1 d(J1(x))

Parameters:
xndarray

The variable x of d(J1(x)), it must be 1-D

accfloat, optional

The tolerance for numerical errors. Default is 1e-8

max_iterint, optional

The maximum number of iterations trying to improve the error accuracy. Default is 50

Returns:
ndarray

The values of the Bessel function derivative d(J1(x)), a 1-D ndarray with the same shape as x

Notes

The scipy equivalent -> scipy.special.jvp(1,x)

Examples

>>> import numpy as np
>>> from pytrunc.utils import bessel_j1_derivative
>>> x = np.array([0.0, 1.0, 2.0])
>>> bessel_j1_derivative(x)
array([ 0.5       ,  0.3251471 , -0.06447162])
pytrunc.utils.bessel_j1_roots(nb_roots: int, acc: float = 1e-08, max_iter: int = 50) ndarray[tuple[Any, ...], dtype[float64]][source]#

Find roots of Bessel first kind function j1(x) using Newton-Raphson iteration

  • First k approximations equation j1_roots ~ pi * (k + 1/4). See Baricz et al. (2025)

Parameters:
nb_rootsint

The number of j1(x)=0 to find

accfloat, optional

The tolerance for numerical errors. Default is 1e-8

max_iterint, optional

The maximum number of iterations trying to improve the error accuracy. Default is 50

Returns:
ndarray

The roots of j1(x), a 1-D ndarray of size nb_roots

Notes

The scipy equivalent -> scipy.special.jn_zeros(1,x)

References

Baricz, Á., Kumar, P., & Ponnusamy, S. (2025). Asymptotic behavior of zeros of Bessel function derivatives. arXiv preprint arXiv:2510.12353.

Examples

>>> from pytrunc.utils import bessel_j1_roots
>>> bessel_j1_roots(3)
array([ 3.83170597,  7.01558667, 10.17346814])
pytrunc.utils.bessel_jn(x: ArrayLike, n: int, acc: float = 1e-08, max_iter: int = 50) ndarray[tuple[Any, ...], dtype[float64]][source]#

The Bessel first kind function Jn(x) of order n

Parameters:
xndarray

The variable x of Jn(x), it must be 1-D

nint

The Bessel first kind function order

accfloat, optional

The tolerance for numerical errors. Default is 1e-8

max_iterint, optional

The maximum number of iterations trying to improve the error accuracy. Default is 50

Returns:
ndarray

The values of the Bessel function Jn(x), a 1-D ndarray with the same shape as x

Notes

The scipy equivalent -> scipy.special.jn(n,x)

Examples

>>> import numpy as np
>>> from pytrunc.utils import bessel_jn
>>> x = np.array([0.0, 1.0, 2.0])
>>> bessel_jn(x, n=2)
array([0.        , 0.11490348, 0.35283403])
pytrunc.utils.integrate_lobatto(f: ndarray[tuple[Any, ...], dtype[float64]], x: ndarray[tuple[Any, ...], dtype[float64]], lp: int | None = None, xk: ndarray[tuple[Any, ...], dtype[float64]] | None = None, wk: ndarray[tuple[Any, ...], dtype[float64]] | None = None, assume_sorted: bool = False) float[source]#

Integrate using lobatto quadrature

Parameters:
fndarray

The ordinates of the function (array to be integrated), it must be 1-D

xndarray

The abscissas, it must be 1-D

lpint or None, optional

The number of lobatto points for the integration. Default is None, meaning lp is equal to len(x)

xkndarray or None, optional

Force the Lobatto quadrature abscissas, it must be 1-D and of size lp. Considered only if wk is also provided

wkndarray or None, optional

Force the Lobatto weights, it must be 1-D and of size lp. Considered only if xk is also provided

assume_sortedbool, optional

If True, the x array is assumed to be sorted in ascending order. Default is False

Returns:
float

The estimated integral calculated using the Lobatto quadrature

Examples

>>> import numpy as np
>>> from pytrunc.utils import integrate_lobatto
>>> theta = np.linspace(0.0, np.pi, 1801)
>>> integrate_lobatto(np.sin(theta), theta, assume_sorted=True)
1.999999497717348
pytrunc.utils.legendre_polynomials(n: int, x: ArrayLike) ndarray[tuple[Any, ...], dtype[float64]][source]#

Use the recursion formulas to compute the Legendre polynomials Pn(x)

  • see Eq. 9 in Michels (1963)

Parameters:
nint

The Legendre polynomial order

xndarray

The x values of Pn(x), it must be 1-D

Returns:
ndarray

The Legendre series, a 1-D ndarray with the same shape as x

Notes

The numpy equivalent -> numpy.polynomial.legendre.Legendre.basis(n)(x)

References

Michels, H. (1963). Abscissas and weight coefficients for Lobatto quadrature. Mathematics of Computation, 17(83), 237-244.

Wiscombe, W. J. (1977). The delta-M method: Rapid yet accurate radiative flux calculations for strongly asymmetric phase functions. Journal of Atmospheric Sciences, 34(9), 1408-1422.

Examples

>>> import numpy as np
>>> from pytrunc.utils import legendre_polynomials
>>> x = np.array([-1.0, 0.0, 1.0])
>>> legendre_polynomials(2, x)
array([ 1. , -0.5,  1. ])
pytrunc.utils.legendre_polynomials_derivative(n: int, x: ArrayLike) ndarray[tuple[Any, ...], dtype[float64]][source]#

Use the recursion formulas to compute the derivative Legendre polynomials d(Pn(x))

  • see Eq. 10 in Michels (1963)

Parameters:
nint

The Legendre polynomial order

xndarray

The x values of d(Pn(x)), it must be 1-D

Returns:
ndarray

The derivative Legendre series, a 1-D ndarray with the same shape as x

Notes

The numpy equivalent -> numpy.polynomial.legendre.Legendre.basis(n).deriv(1)(x)

References

Michels, H. (1963). Abscissas and weight coefficients for Lobatto quadrature. Mathematics of Computation, 17(83), 237-244.

Wiscombe, W. J. (1977). The delta-M method: Rapid yet accurate radiative flux calculations for strongly asymmetric phase functions. Journal of Atmospheric Sciences, 34(9), 1408-1422.

Examples

>>> import numpy as np
>>> from pytrunc.utils import legendre_polynomials_derivative
>>> x = np.array([-1.0, 0.0, 1.0])
>>> legendre_polynomials_derivative(2, x)
array([-3.,  0.,  3.])
pytrunc.utils.legendre_polynomials_derivative_roots(n: int, acc: float = 1e-08, max_iter: int = 50) ndarray[tuple[Any, ...], dtype[float64]][source]#

Find roots of legendre polynomial derivative d(Pn(x)), for x > -1 and x < 1

  • Use of the Newton-Raphson iteration as in Michels (1963), see Eq. 7 and 8

Parameters:
nint

The Legendre polynomial order

accfloat, optional

The tolerance for numerical errors. Default is 1e-8

max_iterint, optional

The maximum number of iterations trying to improve the error accuracy. Default is 50

Returns:
ndarray

The roots of the legendre polynomial derivative d(Pn(x)), a 1-D ndarray of size n-1

Notes

  • The numpy equivalent -> Legendre.basis(n).deriv().roots()

  • Faster than the numpy equivalent!

References

Michels, H. (1963). Abscissas and weight coefficients for Lobatto quadrature. Mathematics of Computation, 17(83), 237-244.

Examples

>>> from pytrunc.utils import (
...     legendre_polynomials_derivative_roots,
... )
>>> legendre_polynomials_derivative_roots(4)
array([-0.65465367,  0.        ,  0.65465367])
pytrunc.utils.legendre_polynomials_second_derivative(n: int, x: ArrayLike) ndarray[tuple[Any, ...], dtype[float64]][source]#

Use the recursion formulas to compute the second derivative Legendre polynomials d²(Pn(x))

  • see Eq. 11 in Michels (1963)

Parameters:
nint

The Legendre polynomial order

xndarray

The x values of d²(Pn(x)), it must be 1-D

Returns:
ndarray

The second derivative Legendre series, a 1-D ndarray with the same shape as x

Notes

The numpy equivalent -> numpy.polynomial.legendre.Legendre.basis(n).deriv(2)(x)

References

Michels, H. (1963). Abscissas and weight coefficients for Lobatto quadrature. Mathematics of Computation, 17(83), 237-244.

Wiscombe, W. J. (1977). The delta-M method: Rapid yet accurate radiative flux calculations for strongly asymmetric phase functions. Journal of Atmospheric Sciences, 34(9), 1408-1422.

Examples

>>> import numpy as np
>>> from pytrunc.utils import (
...     legendre_polynomials_second_derivative,
... )
>>> x = np.array([-1.0, 0.0, 1.0])
>>> legendre_polynomials_second_derivative(3, x)
array([-15.,   0.,  15.])
pytrunc.utils.quadrature_lobatto(abscissa_min: float = -1, abscissa_max: float = 1, n: int = 100) tuple[ndarray[tuple[Any, ...], dtype[float64]], ndarray[tuple[Any, ...], dtype[float64]]][source]#

Compute the abscissas (sample points) and weights for Lobatto quadrature

Parameters:
abscissa_minfloat, optional

The min fixed abscissa. Default is -1

abscissa_maxfloat, optional

The max fixed abscissa. Default is 1

nint, optional

The number of abscissas / weights. Default is 100

Returns:
abscissasndarray

The Lobatto quadrature abscissas, a 1-D ndarray of size n

weightsndarray

The Lobatto quadrature weights, a 1-D ndarray of size n

References

Michels, H. (1963). Abscissas and weight coefficients for Lobatto quadrature. Mathematics of Computation, 17(83), 237-244.

Wiscombe, W. J. (1977). The delta-M method: Rapid yet accurate radiative flux calculations for strongly asymmetric phase functions. Journal of Atmospheric Sciences, 34(9), 1408-1422.

Examples

>>> from pytrunc.utils import quadrature_lobatto
>>> xk, wk = quadrature_lobatto(n=4)
>>> xk
array([-1.       , -0.4472136,  0.4472136,  1.       ])
>>> wk
array([0.16666667, 0.83333333, 0.83333333, 0.16666667])