Source code for pybamm.expression_tree.interpolant
#
# Interpolating class
#
import pybamm
from scipy import interpolate
[docs]class Interpolant(pybamm.Function):
"""
Interpolate data in 1D.
Parameters
----------
data : :class:`numpy.ndarray`
Numpy array of data to use for interpolation. Must have exactly two columns (x
and y data)
child : :class:`pybamm.Symbol`
Node to use when evaluating the interpolant
name : str, optional
Name of the interpolant. Default is None, in which case the name "interpolating
function" is given.
interpolator : str, optional
Which interpolator to use ("pchip" or "cubic spline"). Note that whichever
interpolator is used must be differentiable (for ``Interpolator._diff``).
Default is "cubic spline". Note that "pchip" may give slow results.
extrapolate : bool, optional
Whether to extrapolate for points that are outside of the parametrisation
range, or return NaN (following default behaviour from scipy). Default is True.
**Extends**: :class:`pybamm.Function`
"""
def __init__(
self,
data,
child,
name=None,
interpolator="cubic spline",
extrapolate=True,
entries_string=None,
):
if data.ndim != 2 or data.shape[1] != 2:
raise ValueError(
"""
data should have exactly two columns (x and y) but has shape {}
""".format(
data.shape
)
)
elif interpolator == "pchip":
interpolating_function = interpolate.PchipInterpolator(
data[:, 0], data[:, 1], extrapolate=extrapolate
)
elif interpolator == "cubic spline":
interpolating_function = interpolate.CubicSpline(
data[:, 0], data[:, 1], extrapolate=extrapolate
)
else:
raise ValueError("interpolator '{}' not recognised".format(interpolator))
# Set name
if name is not None and not name.startswith("interpolating function"):
name = "interpolating function ({})".format(name)
else:
name = "interpolating function"
self.data = data
self.entries_string = entries_string
super().__init__(
interpolating_function, child, name=name, derivative="derivative"
)
# Store information as attributes
self.x = data[:, 0]
self.y = data[:, 1]
self.interpolator = interpolator
self.extrapolate = extrapolate
@property
def entries_string(self):
return self._entries_string
@entries_string.setter
def entries_string(self, value):
# We must include the entries in the hash, since different arrays can be
# indistinguishable by class, name and domain alone
# Slightly different syntax for sparse and non-sparse matrices
if value is not None:
self._entries_string = value
else:
entries = self.data
self._entries_string = entries.tobytes()
[docs] def set_id(self):
""" See :meth:`pybamm.Symbol.set_id()`. """
self._id = hash(
(self.__class__, self.name, self.entries_string) + tuple(self.domain)
)
def _function_new_copy(self, children):
""" See :meth:`Function._function_new_copy()` """
return pybamm.Interpolant(
self.data,
*children,
name=self.name,
interpolator=self.interpolator,
extrapolate=self.extrapolate,
entries_string=self.entries_string
)