scijit.interpolate.RectSphereBivariateSpline

scijit.interpolate.RectSphereBivariateSpline(u, v, r, s=0.0, pole_continuity=False, pole_values=None, pole_exact=False, pole_flat=False, r0=nan, r1=nan, ider0=-9, ider1=-9, ider2=-9, ider3=-9, iopt2=-9, iopt3=-9, validate=True)

Build a spline on a spherical grid.

Parameters:
u1-D float64 ndarray, length mu

Colatitudes of the grid, strictly increasing, strictly inside (0, pi).

v1-D float64 ndarray, length mv

Longitudes, strictly increasing, with v[0] in [-pi, pi) and v[-1] <= v[0] + 2*pi.

r2-D float64 ndarray, shape (mu, mv)

Grid values.

sfloat, optional

Smoothing factor. Default 0.0.

pole_continuitybool or (bool, bool), optional

Continuity at the south and north pole. Default False.

pole_valuesfloat or (float, float), optional

Data value at the poles. None (the default) means unknown at both; a scalar is broadcast to both. (None, 0.0) is accepted. A NaN in a slot is a literal pole value.

pole_exactbool or (bool, bool), optional

Whether pole_values is exact or a data value to be smoothed. Default False. Ignored where pole_values is unknown.

pole_flatbool or (bool, bool), optional

Whether the surface should be flat at the poles. Default False.

r0, r1float, optional

RAW FITPACK pole values, overriding pole_values. NaN, the default, means “not overridden”.

ider0, ider1, ider2, ider3int, optional

RAW FITPACK ider codes, overriding pole_exact and pole_flat. -9, the default, means “not overridden”.

iopt2, iopt3int, optional

RAW FITPACK iopt(2)/iopt(3), overriding pole_continuity. -9, the default, means “not overridden”.

validatebool, optional

Raise when FITPACK returns NaN coefficients under a success status, rather than handing back a spline that evaluates to NaN everywhere. Default True. One np.isnan over the coefficient array, run once at construction. See the note on pole_continuity=True below for what produces that state. Set False to receive the spline and test np.isnan(spl.c).any() directly.

Attributes:
tx, ty1-D float64 ndarray

Knot vectors in colatitude and longitude.

c1-D float64 ndarray

Coefficients in FITPACK’s flat bivariate layout.

kx, kyint

Both 3. BICUBIC ONLY.

fpfloat

Sum of squared residuals, also returned by get_residual().

ierint

FITPACK status. Any value outside {0, -1, -2} has already raised.

Methods

eval_grid(u, v, dtheta, dphi)

Grid evaluation, the equivalent of spl(theta, phi).

ev(ui, vi, dtheta, dphi), ev_one(u, v, dtheta, dphi),

partial_derivative(u, v, dtheta, dphi), get_knots(), get_coeffs(),

get_residual()

Returns:
spl_RectSphereBivariateSpline

A jitclass instance carrying the attributes and methods below.

Raises:
ValueError

u not strictly inside (0, pi), v[0] outside [-pi, pi), v[-1] > v[0] + 2*pi, non-increasing u or v, an r whose dimensions do not match, pole_continuity False with pole_flat True, s < 0, and every FITPACK status outside {0, -1, -2}. Also NaN coefficients under a success status, unless validate=False, which skips the check and returns the NaN spline.

TypeError

A scalar pole_continuity, pole_exact or pole_flat that is not a bool, and a scalar pole_values that is not a float. The scalar reaches a subscript or an unpack: pole_continuity=1 is 'int' object is not subscriptable and pole_flat=1 is cannot unpack non-iterable int object. A pair of ints is accepted.

See also

scipy.interpolate.RectSphereBivariateSpline

The scipy class this mirrors.

Notes

  • spl(u, v) runs eval_grid, scipy’s grid=True default, for every pair of scalars and arrays, so two scalars give a (1, 1) grid. ev(ui, vi) is scipy’s grid=False and ev_one(u, v) the single-point scalar spelling, both reached by name.

  • .partial_derivative returns a new object in scipy; here it evaluates on a grid directly.

  • ev_one returns a SCALAR where scipy’s .ev on scalars returns a length-1 array.

  • pole_values=(None, 0.0) is accepted; (np.nan, 0.0) means the same thing.

  • r0, r1 and the six raw codes are extra arguments scipy does not have. A scipy-shaped call never passes them; they reach FITPACK options scipy’s four booleans cannot express.

  • scipy’s .v0 attribute is absent.

Defaults work in both worlds. RectSphereBivariateSpline is a plain @njit factory, not the jitclass itself, so RectSphereBivariateSpline(u, v, r) compiles and runs inside @njit as well as from Python. The class it returns, _RectSphereBivariateSpline, takes every argument explicitly, because a jitclass constructor’s defaults are Python-only.

pole_continuity=True REACHES A NONDETERMINISTIC PATH IN FITPACK, on this library and on scipy alike. The same input, in a fresh process, gives different answers from run to run. At least three outcomes occur on a 12x14 grid at s = 0.5:

nt = (20, 21) fp = 0.0 NaN coefficients, status -1 nt = (8, 11) fp = 0.5000435091 finite, status 0 nt = (9, 11) fp = 0.4995522302 finite, status 0

nt is (len(tu), len(tv)), the two knot counts, and fp is the weighted sum of squared residuals.

The two finite outcomes are both correct. spgrid stops when abs(fp - s) <= tol * s with tol = 0.001 fixed in the source, so at s = 0.5 any fp within 5.0e-04 of 0.5 is accepted. The two differ from s by 4.35e-05 and 4.48e-04, both inside that band, and from each other by 4.91e-04, which is 0.98 of the band width. They are two knot placements that satisfy the same smoothing request, not a right and a wrong answer.

The NaN outcome is the defect. fp = 0.0 against s = 0.5 means the fit fell through to interpolation, and its coefficients are not finite.

The proportions are not stable between samples, so no single ratio describes it. Measured as the first call in a fresh process, 8 runs each: this library 3 NaN and 5 finite, scipy 4 NaN and 4 finite, scipy’s values identical to this library’s. An earlier 9-run sample of this library gave 9 NaN, which is why an earlier version of this note reported the path as always returning NaN here; that was a small sample, not determinism.

Nothing distinguishes the outcomes from the status code, and status -1 means “interpolating spline”, not an error. validate, on by default, detects the NaN outcome and issues a RuntimeWarning; the spline is returned either way, as scipy returns it. validate=False silences the warning and leaves np.isnan(spl.c).any() to the caller.

The cause is upstream, not in this wrapper: scipy 1.18 reaches FITPACK through its own C translation, sharing no code with this package, and reproduces the same outcomes with the same numbers. Every workspace array here is zero-filled and sized by the documented spgrid formula. scipy.interpolate.RectSphereBivariateSpline’s own documentation does not mention it.

pole_continuity=False, the default, is stable.

Accuracy against scipy.interpolate.RectSphereBivariateSpline on scipy 1.18.0, 12x14 grid, default pole arguments, in knots, coefficients, fp and grid values: exactly 0.0 at s = 0, 0.5 and 10.0. At s = 1e-6 the two choose a different number of longitude knots, 20 against 21, which is a structurally different spline that no tolerance expresses.

Which s values land in which régime is a property of the DATA, not of s: a second 12x14 fixture put the mismatch at s = 0.01 instead (11 latitude knots against 12). Treat the knot counts above as an example, and compare knot counts before comparing values.

prange-safe: yes.

Examples

>>> import numpy as np
>>> from numba import njit
>>> from scijit.interpolate import RectSphereBivariateSpline
>>> u = np.linspace(0.1, np.pi - 0.1, 12)
>>> v = np.linspace(0, 2 * np.pi, 15)[:-1]
>>> r = np.outer(np.sin(u), np.cos(v)) + 2.0
>>> spl = RectSphereBivariateSpline(u, v, r, s=0.5)     # fit once
>>> spl.ier
0
>>> float(np.round(spl(1.5, 1.0)[0, 0], 6))     # spl(u, v) is the grid form; [0, 0] takes the point
2.442246

Inside compiled code, the largest value over a coarse query grid:

>>> @njit
... def gridmax(spl):
...     return np.max(spl(np.linspace(0.5, 2.5, 5), np.linspace(0.5, 5.5, 5)))
>>> float(np.round(gridmax(spl), 6))
2.781747