Skip to content

API Docs

API Docs

Python bindings to the interpn Rust library for N-dimensional interpolation and extrapolation.

MulticubicRectilinear

Bases: BaseModel

Multicubic interpolation on a rectilinear grid in up to 8 dimensions.

This method uses a symmetrized Hermite spline interpolant, which provides a continuous value and first derivative. Unlike a B-spline, the second derivative is not continuous; however, also unlike a B-spline, the first derivatives are maintained to more exactly match the data as estimated by a central difference.

If linearize_extrapolation is set, dimensions on which extrapolation is occurring (but not other dimensions) are extrapolated linearly from the last two grid points on that dimension.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous and have size at least 4.

Source code in src/interpn/multicubic_rectilinear.py
class MulticubicRectilinear(BaseModel):
    """
    Multicubic interpolation on a rectilinear grid in up to 8 dimensions.

    This method uses a symmetrized Hermite spline interpolant,
    which provides a continuous value and first derivative.
    Unlike a B-spline, the second derivative is not continuous;
    however, also unlike a B-spline, the first derivatives are
    maintained to more exactly match the data as estimated by
    a central difference.

    If `linearize_extrapolation` is set, dimensions on which extrapolation is occurring
    (but not other dimensions) are extrapolated linearly from the last
    two grid points on that dimension.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous and have size at least 4.
    """

    # Immutable after initialization checks
    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    grids: list[Array]
    vals: Array
    linearize_extrapolation: bool

    @classmethod
    def new(
        cls, grids: list[NDArray], vals: NDArray, linearize_extrapolation: bool = True
    ) -> MulticubicRectilinear:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            grids: 1D arrays of grid coordinate values.
                   All grids must be monotonically increasing.
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")
            linearize_extrapolation: Whether to fall back to a linear
                interpolant outside the grid

        Returns:
            A new MultilinearRectilinear interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = MulticubicRectilinear(
            grids=[arrtype(data=x) for x in grids],
            vals=arrtype(data=vals.flatten()),
            linearize_extrapolation=linearize_extrapolation,
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        dims = self.dims()
        ndims = self.ndims()
        assert ndims <= 8 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 8"
        )
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, dims), (
            "Size of value array does not match grid dims"
        )
        assert all([np.all(np.diff(x.data) > 0.0) for x in self.grids]), (
            "All grids must be monotonically increasing"
        )
        assert all([x.data.dtype == self.vals.data.dtype for x in self.grids]), (
            "All grid inputs must be of the same data type (np.float32 or np.float64)"
        )
        assert (
            all([x.data.data.contiguous for x in self.grids])
            and self.vals.data.data.contiguous
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.grids)

    def dims(self) -> list[int]:
        return [x.data.size for x in self.grids]

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        # Allocate output if it was not provided,
        # then check data type and contiguousness
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_cubic_rectilinear_f64(
                [x.data for x in self.grids],
                self.vals.data,
                self.linearize_extrapolation,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_cubic_rectilinear_f32(
                [x.data for x in self.grids],
                self.vals.data,
                self.linearize_extrapolation,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_rectilinear_f64(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_rectilinear_f32(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/multicubic_rectilinear.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_rectilinear_f64(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_rectilinear_f32(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multicubic_rectilinear.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    # Allocate output if it was not provided,
    # then check data type and contiguousness
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multicubic_rectilinear.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_cubic_rectilinear_f64(
            [x.data for x in self.grids],
            self.vals.data,
            self.linearize_extrapolation,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_cubic_rectilinear_f32(
            [x.data for x in self.grids],
            self.vals.data,
            self.linearize_extrapolation,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(grids, vals, linearize_extrapolation=True) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
grids list[NDArray]

1D arrays of grid coordinate values. All grids must be monotonically increasing.

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required
linearize_extrapolation bool

Whether to fall back to a linear interpolant outside the grid

True

Returns:

Type Description
MulticubicRectilinear

A new MultilinearRectilinear interpolator instance.

Source code in src/interpn/multicubic_rectilinear.py
@classmethod
def new(
    cls, grids: list[NDArray], vals: NDArray, linearize_extrapolation: bool = True
) -> MulticubicRectilinear:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        grids: 1D arrays of grid coordinate values.
               All grids must be monotonically increasing.
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")
        linearize_extrapolation: Whether to fall back to a linear
            interpolant outside the grid

    Returns:
        A new MultilinearRectilinear interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = MulticubicRectilinear(
        grids=[arrtype(data=x) for x in grids],
        vals=arrtype(data=vals.flatten()),
        linearize_extrapolation=linearize_extrapolation,
    )

    return interpolator

MulticubicRegular

Bases: BaseModel

Multicubic interpolation on a regular grid in up to 8 dimensions.

This method uses a symmetrized Hermite spline interpolant, which provides a continuous value and first derivative. Unlike a B-spline, the second derivative is not continuous; however, also unlike a B-spline, the first derivatives are maintained to more exactly match the data as estimated by a central difference.

If linearize_extrapolation is set, dimensions on which extrapolation is occurring (but not other dimensions) are extrapolated linearly from the last two grid points on that dimension.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous and have size at least 4.

Source code in src/interpn/multicubic_regular.py
class MulticubicRegular(BaseModel):
    """
    Multicubic interpolation on a regular grid in up to 8 dimensions.

    This method uses a symmetrized Hermite spline interpolant,
    which provides a continuous value and first derivative.
    Unlike a B-spline, the second derivative is not continuous;
    however, also unlike a B-spline, the first derivatives are
    maintained to more exactly match the data as estimated by
    a central difference.

    If `linearize_extrapolation` is set, dimensions on which extrapolation is occurring
    (but not other dimensions) are extrapolated linearly from the last
    two grid points on that dimension.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous and have size at least 4.
    """

    # Immutable after initialization checks
    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    dims: list[int]
    starts: Array
    steps: Array
    vals: Array
    linearize_extrapolation: bool

    @classmethod
    def new(
        cls,
        dims: list[int],
        starts: NDArray,
        steps: NDArray,
        vals: NDArray,
        linearize_extrapolation: bool = True,
    ) -> MulticubicRegular:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            dims: Number of elements on each dimension of the grid
            starts: Starting point of each dimension of the grid
            steps: Step size on each dimension of the grid
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")
            linearize_extrapolation: Whether to fall back to a linear
                interpolant outside the grid

        Returns:
            A new MulticubicRegular interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = MulticubicRegular(
            dims=dims,
            starts=arrtype(data=starts.flatten()),
            steps=arrtype(data=steps.flatten()),
            vals=arrtype(data=vals.flatten()),
            linearize_extrapolation=linearize_extrapolation,
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        ndims = self.ndims()
        assert ndims <= 8 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 8"
        )
        assert self.starts.data.size == ndims, "Grid dimension mismatch"
        assert self.steps.data.size == ndims, "Grid dimension mismatch"
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, self.dims), (
            "Size of value array does not match grid dims"
        )
        assert all([x > 0.0 for x in self.steps.data]), (
            "All grid steps must be positive and nonzero"
        )
        assert all(
            [x.data.dtype == self.vals.data.dtype for x in [self.steps, self.vals]]
        ), "All grid inputs must be of the same data type (np.float32 or np.float64)"
        assert all(
            [x.data.data.contiguous for x in [self.starts, self.steps, self.vals]]
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.dims)

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        # Allocate output if it was not provided
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_cubic_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                self.linearize_extrapolation,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_cubic_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                self.linearize_extrapolation,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/multicubic_regular.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multicubic_regular.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    # Allocate output if it was not provided
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multicubic_regular.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_cubic_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            self.linearize_extrapolation,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_cubic_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            self.linearize_extrapolation,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(dims, starts, steps, vals, linearize_extrapolation=True) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
dims list[int]

Number of elements on each dimension of the grid

required
starts NDArray

Starting point of each dimension of the grid

required
steps NDArray

Step size on each dimension of the grid

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required
linearize_extrapolation bool

Whether to fall back to a linear interpolant outside the grid

True

Returns:

Type Description
MulticubicRegular

A new MulticubicRegular interpolator instance.

Source code in src/interpn/multicubic_regular.py
@classmethod
def new(
    cls,
    dims: list[int],
    starts: NDArray,
    steps: NDArray,
    vals: NDArray,
    linearize_extrapolation: bool = True,
) -> MulticubicRegular:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        dims: Number of elements on each dimension of the grid
        starts: Starting point of each dimension of the grid
        steps: Step size on each dimension of the grid
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")
        linearize_extrapolation: Whether to fall back to a linear
            interpolant outside the grid

    Returns:
        A new MulticubicRegular interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = MulticubicRegular(
        dims=dims,
        starts=arrtype(data=starts.flatten()),
        steps=arrtype(data=steps.flatten()),
        vals=arrtype(data=vals.flatten()),
        linearize_extrapolation=linearize_extrapolation,
    )

    return interpolator

MultilinearRectilinear

Bases: BaseModel

Multilinear interpolation on a rectilinear grid in up to 8 dimensions.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous.

Source code in src/interpn/multilinear_rectilinear.py
class MultilinearRectilinear(BaseModel):
    """
    Multilinear interpolation on a rectilinear grid in up to 8 dimensions.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous.
    """

    # Immutable after initialization checks
    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    grids: list[Array]
    vals: Array

    @classmethod
    def new(cls, grids: list[NDArray], vals: NDArray) -> MultilinearRectilinear:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            grids: 1D arrays of grid coordinate values.
                   All grids must be monotonically increasing.
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")

        Returns:
            A new MultilinearRectilinear interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = MultilinearRectilinear(
            grids=[arrtype(data=x) for x in grids],
            vals=arrtype(data=vals.flatten()),
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        dims = self.dims()
        ndims = self.ndims()
        assert ndims <= 8 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 8"
        )
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, dims), (
            "Size of value array does not match grid dims"
        )
        assert all([np.all(np.diff(x.data) > 0.0) for x in self.grids]), (
            "All grids must be monotonically increasing"
        )
        assert all([x.data.dtype == self.vals.data.dtype for x in self.grids]), (
            "All grid inputs must be of the same data type (np.float32 or np.float64)"
        )
        assert (
            all([x.data.data.contiguous for x in self.grids])
            and self.vals.data.data.contiguous
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.grids)

    def dims(self) -> list[int]:
        return [x.data.size for x in self.grids]

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        # Allocate output if it was not provided,
        # then check data type and contiguousness
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_linear_rectilinear_f64(
                [x.data for x in self.grids],
                self.vals.data,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_linear_rectilinear_f32(
                [x.data for x in self.grids],
                self.vals.data,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_rectilinear_f64(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_rectilinear_f32(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/multilinear_rectilinear.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_rectilinear_f64(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_rectilinear_f32(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multilinear_rectilinear.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    # Allocate output if it was not provided,
    # then check data type and contiguousness
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multilinear_rectilinear.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_linear_rectilinear_f64(
            [x.data for x in self.grids],
            self.vals.data,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_linear_rectilinear_f32(
            [x.data for x in self.grids],
            self.vals.data,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(grids, vals) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
grids list[NDArray]

1D arrays of grid coordinate values. All grids must be monotonically increasing.

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required

Returns:

Type Description
MultilinearRectilinear

A new MultilinearRectilinear interpolator instance.

Source code in src/interpn/multilinear_rectilinear.py
@classmethod
def new(cls, grids: list[NDArray], vals: NDArray) -> MultilinearRectilinear:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        grids: 1D arrays of grid coordinate values.
               All grids must be monotonically increasing.
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")

    Returns:
        A new MultilinearRectilinear interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = MultilinearRectilinear(
        grids=[arrtype(data=x) for x in grids],
        vals=arrtype(data=vals.flatten()),
    )

    return interpolator

MultilinearRegular

Bases: BaseModel

Multilinear interpolation on a regular grid in up to 8 dimensions.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous.

Source code in src/interpn/multilinear_regular.py
class MultilinearRegular(BaseModel):
    """
    Multilinear interpolation on a regular grid in up to 8 dimensions.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous.
    """

    # Immutable after initialization checks
    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    dims: list[int]
    starts: Array
    steps: Array
    vals: Array

    @classmethod
    def new(
        cls, dims: list[int], starts: NDArray, steps: NDArray, vals: NDArray
    ) -> MultilinearRegular:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            dims: Number of elements on each dimension of the grid
            starts: Starting point of each dimension of the grid
            steps: Step size on each dimension of the grid
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")

        Returns:
            A new MultilinearRegular interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = MultilinearRegular(
            dims=dims,
            starts=arrtype(data=starts.flatten()),
            steps=arrtype(data=steps.flatten()),
            vals=arrtype(data=vals.flatten()),
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        ndims = self.ndims()
        assert ndims <= 8 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 8"
        )
        assert self.starts.data.size == ndims, "Grid dimension mismatch"
        assert self.steps.data.size == ndims, "Grid dimension mismatch"
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, self.dims), (
            "Size of value array does not match grid dims"
        )
        assert all([x > 0.0 for x in self.steps.data]), (
            "All grid steps must be positive and nonzero"
        )
        assert all(
            [x.data.dtype == self.vals.data.dtype for x in [self.steps, self.vals]]
        ), "All grid inputs must be of the same data type (np.float32 or np.float64)"
        assert all(
            [x.data.data.contiguous for x in [self.starts, self.steps, self.vals]]
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.dims)

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        # Allocate output if it was not provided
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_linear_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_linear_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/multilinear_regular.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multilinear_regular.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    # Allocate output if it was not provided
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/multilinear_regular.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_linear_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_linear_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(dims, starts, steps, vals) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
dims list[int]

Number of elements on each dimension of the grid

required
starts NDArray

Starting point of each dimension of the grid

required
steps NDArray

Step size on each dimension of the grid

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required

Returns:

Type Description
MultilinearRegular

A new MultilinearRegular interpolator instance.

Source code in src/interpn/multilinear_regular.py
@classmethod
def new(
    cls, dims: list[int], starts: NDArray, steps: NDArray, vals: NDArray
) -> MultilinearRegular:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        dims: Number of elements on each dimension of the grid
        starts: Starting point of each dimension of the grid
        steps: Step size on each dimension of the grid
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")

    Returns:
        A new MultilinearRegular interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = MultilinearRegular(
        dims=dims,
        starts=arrtype(data=starts.flatten()),
        steps=arrtype(data=steps.flatten()),
        vals=arrtype(data=vals.flatten()),
    )

    return interpolator

NearestRectilinear

Bases: BaseModel

Nearest-neighbor interpolation on a rectilinear grid in up to 6 dimensions.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous.

Source code in src/interpn/nearest_rectilinear.py
class NearestRectilinear(BaseModel):
    """
    Nearest-neighbor interpolation on a rectilinear grid in up to 6 dimensions.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous.
    """

    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    grids: list[Array]
    vals: Array

    @classmethod
    def new(cls, grids: list[NDArray], vals: NDArray) -> NearestRectilinear:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            grids: 1D arrays of grid coordinate values.
                   All grids must be monotonically increasing.
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")

        Returns:
            A new NearestRectilinear interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = NearestRectilinear(
            grids=[arrtype(data=x) for x in grids],
            vals=arrtype(data=vals.flatten()),
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        dims = self.dims()
        ndims = self.ndims()
        assert ndims <= 6 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 6"
        )
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, dims), (
            "Size of value array does not match grid dims"
        )
        assert all([np.all(np.diff(x.data) > 0.0) for x in self.grids]), (
            "All grids must be monotonically increasing"
        )
        assert all([x.data.dtype == self.vals.data.dtype for x in self.grids]), (
            "All grid inputs must be of the same data type (np.float32 or np.float64)"
        )
        assert (
            all([x.data.data.contiguous for x in self.grids])
            and self.vals.data.data.contiguous
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.grids)

    def dims(self) -> list[int]:
        return [x.data.size for x in self.grids]

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_nearest_rectilinear_f64(
                [x.data for x in self.grids],
                self.vals.data,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_nearest_rectilinear_f32(
                [x.data for x in self.grids],
                self.vals.data,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_rectilinear_f64(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_rectilinear_f32(
                [x.data for x in self.grids],
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/nearest_rectilinear.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_rectilinear_f64(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_rectilinear_f32(
            [x.data for x in self.grids],
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/nearest_rectilinear.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/nearest_rectilinear.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_nearest_rectilinear_f64(
            [x.data for x in self.grids],
            self.vals.data,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_nearest_rectilinear_f32(
            [x.data for x in self.grids],
            self.vals.data,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(grids, vals) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
grids list[NDArray]

1D arrays of grid coordinate values. All grids must be monotonically increasing.

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required

Returns:

Type Description
NearestRectilinear

A new NearestRectilinear interpolator instance.

Source code in src/interpn/nearest_rectilinear.py
@classmethod
def new(cls, grids: list[NDArray], vals: NDArray) -> NearestRectilinear:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        grids: 1D arrays of grid coordinate values.
               All grids must be monotonically increasing.
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")

    Returns:
        A new NearestRectilinear interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = NearestRectilinear(
        grids=[arrtype(data=x) for x in grids],
        vals=arrtype(data=vals.flatten()),
    )

    return interpolator

NearestRegular

Bases: BaseModel

Nearest-neighbor interpolation on a regular grid in up to 6 dimensions.

All array inputs must be of the same type, either np.float32 or np.float64 and must be 1D and contiguous.

Source code in src/interpn/nearest_regular.py
class NearestRegular(BaseModel):
    """
    Nearest-neighbor interpolation on a regular grid in up to 6 dimensions.

    All array inputs must be of the same type, either np.float32 or np.float64
    and must be 1D and contiguous.
    """

    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

    dims: list[int]
    starts: Array
    steps: Array
    vals: Array

    @classmethod
    def new(
        cls, dims: list[int], starts: NDArray, steps: NDArray, vals: NDArray
    ) -> NearestRegular:
        """
        Initialize interpolator and check types and dimensions, casting other arrays
        to the same type as `vals` if they do not match, and flattening and/or
        reallocating into contiguous storage if necessary.

        This method exists primarily to remove boilerplate introduced by
        mixing pydantic and numpy.

        Args:
            dims: Number of elements on each dimension of the grid
            starts: Starting point of each dimension of the grid
            steps: Step size on each dimension of the grid
            vals: Values at grid points in C-style ordering,
                  as obtained from np.meshgrid(..., indexing="ij")

        Returns:
            A new NearestRegular interpolator instance.
        """
        dtype = vals.dtype
        arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
        interpolator = NearestRegular(
            dims=dims,
            starts=arrtype(data=starts.flatten()),
            steps=arrtype(data=steps.flatten()),
            vals=arrtype(data=vals.flatten()),
        )

        return interpolator

    @model_validator(mode="after")
    def _validate_model(self):
        """Check that all inputs are contiguous and of the same data type,
        and that the grid dimensions and values make sense."""
        ndims = self.ndims()
        assert ndims <= 6 and ndims >= 1, (
            "Number of dimensions must be at least 1 and no more than 6"
        )
        assert self.starts.data.size == ndims, "Grid dimension mismatch"
        assert self.steps.data.size == ndims, "Grid dimension mismatch"
        assert self.vals.data.size == reduce(lambda acc, x: acc * x, self.dims), (
            "Size of value array does not match grid dims"
        )
        assert all([x > 0.0 for x in self.steps.data]), (
            "All grid steps must be positive and nonzero"
        )
        assert all(
            [
                x.data.dtype == self.vals.data.dtype
                for x in [self.starts, self.steps, self.vals]
            ]
        ), "All grid inputs must be of the same data type (np.float32 or np.float64)"
        assert all(
            [x.data.data.contiguous for x in [self.starts, self.steps, self.vals]]
        ), "Grid data must be contiguous"

        return self

    def ndims(self) -> int:
        return len(self.dims)

    def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array.

        This function does not reallocate inputs, and will error if the
        inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64
            AssertionError: If input data is not contiguous or dimensions do not match

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        out_inner = out if out is not None else np.zeros_like(obs[0])
        self.eval_unchecked(obs, out_inner)

        return out_inner

    def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
        """Evaluate the interpolator at a set of observation points,
        optionally writing the output into a preallocated array,
        and skipping checks on the dimensionality and contiguousness
        of the inputs.

        This function does not reallocate inputs, and will error in a lower-level
        function if the inputs are not contiguous or are of the wrong data type.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            out: Optional preallocated array for output. Defaults to None.

        Raises:
            TypeError: If data type is not np.float32 or np.float64

        Returns:
            Array of evaluated values in the same shape and data type as obs[0]
        """
        dtype = self.vals.data.dtype
        out_inner = out if out is not None else np.zeros_like(obs[0])

        if dtype == np.float64:
            interpn_nearest_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                obs,
                out_inner,
            )
        elif dtype == np.float32:
            interpn_nearest_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                self.vals.data,
                obs,
                out_inner,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out_inner

    def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
        """
        Check if the observation points violated the bounds on each dimension.

        This performs a (small) allocation for the output.

        Args:
            obs: [x, y, ...] coordinates of observation points.
            atol: Absolute tolerance on bounds.

        Raises:
            TypeError: If an unexpected data type is encountered

        Returns:
            An array of flags for each dimension, each True if that dimension's
            bounds were violated.
        """
        ndims = self.ndims()
        out = np.array([False] * ndims)

        dtype = self.vals.data.dtype
        if dtype == np.float64:
            check_bounds_regular_f64(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        elif dtype == np.float32:
            check_bounds_regular_f32(
                self.dims,
                self.starts.data,
                self.steps.data,
                [x.flatten() for x in obs],
                atol,
                out,
            )
        else:
            raise TypeError(f"Unexpected data type: {dtype}")

        return out

check_bounds(obs, atol)

Check if the observation points violated the bounds on each dimension.

This performs a (small) allocation for the output.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
atol float

Absolute tolerance on bounds.

required

Raises:

Type Description
TypeError

If an unexpected data type is encountered

Returns:

Type Description
NDArray[bool_]

An array of flags for each dimension, each True if that dimension's

NDArray[bool_]

bounds were violated.

Source code in src/interpn/nearest_regular.py
def check_bounds(self, obs: list[NDArray], atol: float) -> NDArray[np.bool_]:
    """
    Check if the observation points violated the bounds on each dimension.

    This performs a (small) allocation for the output.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        atol: Absolute tolerance on bounds.

    Raises:
        TypeError: If an unexpected data type is encountered

    Returns:
        An array of flags for each dimension, each True if that dimension's
        bounds were violated.
    """
    ndims = self.ndims()
    out = np.array([False] * ndims)

    dtype = self.vals.data.dtype
    if dtype == np.float64:
        check_bounds_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    elif dtype == np.float32:
        check_bounds_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            [x.flatten() for x in obs],
            atol,
            out,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out

eval(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array.

This function does not reallocate inputs, and will error if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

AssertionError

If input data is not contiguous or dimensions do not match

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/nearest_regular.py
def eval(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array.

    This function does not reallocate inputs, and will error if the
    inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64
        AssertionError: If input data is not contiguous or dimensions do not match

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    out_inner = out if out is not None else np.zeros_like(obs[0])
    self.eval_unchecked(obs, out_inner)

    return out_inner

eval_unchecked(obs, out=None)

Evaluate the interpolator at a set of observation points, optionally writing the output into a preallocated array, and skipping checks on the dimensionality and contiguousness of the inputs.

This function does not reallocate inputs, and will error in a lower-level function if the inputs are not contiguous or are of the wrong data type.

Parameters:

Name Type Description Default
obs list[NDArray]

[x, y, ...] coordinates of observation points.

required
out NDArray | None

Optional preallocated array for output. Defaults to None.

None

Raises:

Type Description
TypeError

If data type is not np.float32 or np.float64

Returns:

Type Description
NDArray

Array of evaluated values in the same shape and data type as obs[0]

Source code in src/interpn/nearest_regular.py
def eval_unchecked(self, obs: list[NDArray], out: NDArray | None = None) -> NDArray:
    """Evaluate the interpolator at a set of observation points,
    optionally writing the output into a preallocated array,
    and skipping checks on the dimensionality and contiguousness
    of the inputs.

    This function does not reallocate inputs, and will error in a lower-level
    function if the inputs are not contiguous or are of the wrong data type.

    Args:
        obs: [x, y, ...] coordinates of observation points.
        out: Optional preallocated array for output. Defaults to None.

    Raises:
        TypeError: If data type is not np.float32 or np.float64

    Returns:
        Array of evaluated values in the same shape and data type as obs[0]
    """
    dtype = self.vals.data.dtype
    out_inner = out if out is not None else np.zeros_like(obs[0])

    if dtype == np.float64:
        interpn_nearest_regular_f64(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            obs,
            out_inner,
        )
    elif dtype == np.float32:
        interpn_nearest_regular_f32(
            self.dims,
            self.starts.data,
            self.steps.data,
            self.vals.data,
            obs,
            out_inner,
        )
    else:
        raise TypeError(f"Unexpected data type: {dtype}")

    return out_inner

new(dims, starts, steps, vals) classmethod

Initialize interpolator and check types and dimensions, casting other arrays to the same type as vals if they do not match, and flattening and/or reallocating into contiguous storage if necessary.

This method exists primarily to remove boilerplate introduced by mixing pydantic and numpy.

Parameters:

Name Type Description Default
dims list[int]

Number of elements on each dimension of the grid

required
starts NDArray

Starting point of each dimension of the grid

required
steps NDArray

Step size on each dimension of the grid

required
vals NDArray

Values at grid points in C-style ordering, as obtained from np.meshgrid(..., indexing="ij")

required

Returns:

Type Description
NearestRegular

A new NearestRegular interpolator instance.

Source code in src/interpn/nearest_regular.py
@classmethod
def new(
    cls, dims: list[int], starts: NDArray, steps: NDArray, vals: NDArray
) -> NearestRegular:
    """
    Initialize interpolator and check types and dimensions, casting other arrays
    to the same type as `vals` if they do not match, and flattening and/or
    reallocating into contiguous storage if necessary.

    This method exists primarily to remove boilerplate introduced by
    mixing pydantic and numpy.

    Args:
        dims: Number of elements on each dimension of the grid
        starts: Starting point of each dimension of the grid
        steps: Step size on each dimension of the grid
        vals: Values at grid points in C-style ordering,
              as obtained from np.meshgrid(..., indexing="ij")

    Returns:
        A new NearestRegular interpolator instance.
    """
    dtype = vals.dtype
    arrtype = ArrayF64 if dtype == np.float64 else ArrayF32
    interpolator = NearestRegular(
        dims=dims,
        starts=arrtype(data=starts.flatten()),
        steps=arrtype(data=steps.flatten()),
        vals=arrtype(data=vals.flatten()),
    )

    return interpolator