113113# z axis in 4D ⟵ 3D padding.
114114_HUGE_LENGTH = 1.0e30
115115
116+ # Public coordinate arrays are 2-D with three columns: ``(x, y, t)`` in
117+ # cartesian mode, ``(lon, lat, t)`` in geographic mode.
118+ _COORDS_NDIM = 2
119+ _COORDS_NCOLS = 3
120+
116121
117122def _kernel_from_r2 (r2 : np .ndarray , kernel : CovarianceFunction ) -> np .ndarray :
118123 """Evaluate an anisotropic covariance kernel from squared scaled distance.
@@ -127,26 +132,25 @@ def _kernel_from_r2(r2: np.ndarray, kernel: CovarianceFunction) -> np.ndarray:
127132 Covariance values with the same shape as ``r2``.
128133
129134 """
135+ d = np .sqrt (r2 )
130136 if kernel == "gaussian" :
131- return np .exp (- r2 )
132- if kernel == "cauchy" :
133- return 1.0 / (1.0 + r2 )
134- if kernel == "matern_12" :
135- return np .exp (- np .sqrt (r2 ))
136- if kernel == "matern_32" :
137- d = np .sqrt (r2 )
138- return (1.0 + _SQRT3 * d ) * np .exp (- _SQRT3 * d )
139- if kernel == "matern_52" :
140- d = np .sqrt (r2 )
141- return (1.0 + _SQRT5 * d + (5.0 / 3.0 ) * r2 ) * np .exp (- _SQRT5 * d )
142- if kernel == "spherical" :
143- d = np .sqrt (r2 )
144- return np .where (d < 1.0 , 1.0 - 1.5 * d + 0.5 * d ** 3 , 0.0 )
145- if kernel == "wendland" :
146- d = np .sqrt (r2 )
147- return np .where (d < 1.0 , (1.0 - d ) ** 2 , 0.0 )
148- msg = f"Unknown covariance kernel: { kernel !r} "
149- raise ValueError (msg )
137+ result = np .exp (- r2 )
138+ elif kernel == "cauchy" :
139+ result = 1.0 / (1.0 + r2 )
140+ elif kernel == "matern_12" :
141+ result = np .exp (- d )
142+ elif kernel == "matern_32" :
143+ result = (1.0 + _SQRT3 * d ) * np .exp (- _SQRT3 * d )
144+ elif kernel == "matern_52" :
145+ result = (1.0 + _SQRT5 * d + (5.0 / 3.0 ) * r2 ) * np .exp (- _SQRT5 * d )
146+ elif kernel == "spherical" :
147+ result = np .where (d < 1.0 , 1.0 - 1.5 * d + 0.5 * d ** 3 , 0.0 )
148+ elif kernel == "wendland" :
149+ result = np .where (d < 1.0 , (1.0 - d ) ** 2 , 0.0 )
150+ else :
151+ msg = f"Unknown covariance kernel: { kernel !r} "
152+ raise ValueError (msg )
153+ return result
150154
151155
152156def _sample_scalar_or_grid (
@@ -200,7 +204,6 @@ def _lla_to_ecef(
200204 lon : np .ndarray , lat : np .ndarray , spheroid : Spheroid | None
201205) -> tuple [np .ndarray , np .ndarray , np .ndarray ]:
202206 """Convert (lon, lat, alt=0) → (x, y, z) ECEF in meters."""
203-
204207 sph = spheroid if spheroid is not None else _S ()
205208 coords = Coordinates (sph )
206209 alt = np .zeros_like (lon )
@@ -320,15 +323,16 @@ def __init__(
320323 spheroid : Spheroid | None = None ,
321324 time_scale : float = 1.0 ,
322325 ) -> None :
326+ """Index the observations and build the internal 4D R-tree."""
323327 obs_coords = np .ascontiguousarray (obs_coords , dtype = np .float64 )
324328 obs_values = np .ascontiguousarray (obs_values , dtype = np .float64 )
325329 obs_sigma2 = np .ascontiguousarray (obs_sigma2 , dtype = np .float64 )
326330
327- if obs_coords . ndim != 2 or obs_coords . shape [ 1 ] != 3 :
328- msg = (
329- " obs_coords must have shape (N, 3); got "
330- f" { obs_coords . shape } "
331- )
331+ if (
332+ obs_coords . ndim != _COORDS_NDIM
333+ or obs_coords . shape [ 1 ] != _COORDS_NCOLS
334+ ):
335+ msg = f"obs_coords must have shape (N, 3); got { obs_coords . shape } "
332336 raise ValueError (msg )
333337 n = obs_coords .shape [0 ]
334338 if obs_values .shape != (n ,):
@@ -407,7 +411,7 @@ def n_observations(self) -> int:
407411 """Number of indexed observations."""
408412 return self ._obs_coords .shape [0 ]
409413
410- def __call__ (
414+ def __call__ ( # noqa: PLR0915
411415 self ,
412416 query_coords : NDArray2DFloat64 ,
413417 * ,
@@ -452,7 +456,10 @@ def __call__(
452456
453457 """
454458 query_coords = np .ascontiguousarray (query_coords , dtype = np .float64 )
455- if query_coords .ndim != 2 or query_coords .shape [1 ] != 3 :
459+ if (
460+ query_coords .ndim != _COORDS_NDIM
461+ or query_coords .shape [1 ] != _COORDS_NCOLS
462+ ):
456463 msg = (
457464 "query_coords must have shape (M, 3); got "
458465 f"{ query_coords .shape } "
0 commit comments