Source code for pybamm.expression_tree.scalar
#
# Scalar class
#
from __future__ import annotations
from typing import Literal
import casadi
import numpy as np
import numpy.typing as npt
import sympy
import pybamm
from pybamm.type_definitions import Numeric
[docs]
class Scalar(pybamm.Symbol):
"""
A node in the expression tree representing a scalar value.
Parameters
----------
value : numeric
the value returned by the node when evaluated
name : str, optional
the name of the node. Defaulted to ``str(value)`` if not provided
"""
def __init__(
self,
value: Numeric,
name: str | None = None,
) -> None:
# set default name if not provided
self.value = value
if name is None:
name = str(self.value)
super().__init__(name)
@classmethod
def _from_json(cls, snippet: dict):
return cls(snippet["value"], name=snippet["name"])
def __str__(self):
return str(self.value)
@property
def value(self):
"""The value returned by the node when evaluated."""
return self._value
# address numpy 1.25 deprecation warning: array should have ndim=0 before conversion
@value.setter
def value(self, value):
self._value = (
np.float64(value.item())
if isinstance(value, np.ndarray)
else np.float64(value)
)
[docs]
def set_id(self):
"""See :meth:`pybamm.Symbol.set_id()`."""
# We must include the value in the hash, since different scalars can be
# indistinguishable by class and name alone
self._id = hash((self.__class__, str(self.value)))
def _base_evaluate(
self,
t: float | None = None,
y: npt.NDArray[np.float64] | None = None,
y_dot: npt.NDArray[np.float64] | None = None,
inputs: dict | str | None = None,
):
"""See :meth:`pybamm.Symbol._base_evaluate()`."""
return self._value
def _to_casadi(self, t, y, y_dot, inputs, casadi_symbols):
"""See :meth:`pybamm.Symbol._to_casadi()`."""
return casadi.MX(self.evaluate(t, y, y_dot, inputs))
def _jac(self, variable: pybamm.Variable) -> pybamm.Scalar:
"""See :meth:`pybamm.Symbol._jac()`."""
return pybamm.Scalar(0)
[docs]
def create_copy(
self,
new_children=None,
perform_simplifications=True,
):
"""See :meth:`pybamm.Symbol.new_copy()`."""
if new_children is None or len(new_children) == 0:
return Scalar(self.value, self.name)
else:
raise ValueError(
f"Cannot create a copy of a scalar with new children: {new_children}"
)
[docs]
def is_constant(self) -> Literal[True]:
"""See :meth:`pybamm.Symbol.is_constant()`."""
return True
[docs]
def to_equation(self):
"""Returns the value returned by the node when evaluated."""
if self.print_name is not None:
return sympy.Symbol(self.print_name)
else:
return self.value
[docs]
def to_json(self):
"""
Method to serialise a Symbol object into JSON.
"""
json_dict = {"name": self.name, "id": self.id, "value": self.value}
return json_dict
class Constant(Scalar):
"""
A node in the expression tree representing a named constant value. This is a subclass of
:class:`pybamm.Scalar` and is used to represent named constants such as :math:`R`, :math:`F`,
and :math:`k_b`. Counterintuitively, the "is_constant" method is set to False, so that
named constants are not simplified when constructed.
Parameters
----------
value : numeric
the value returned by the node when evaluated
name : str
the name of the node
"""
def __init__(self, value: Numeric, name: str):
super().__init__(value, name)
def is_constant(self) -> Literal[True]:
"""
The value is constant, but setting this to False makes sure we retain named constants
in the expression tree. For example, `pybamm.constants.R + 2` should not be
simplified to `10.314462618` until after the expression is evaluated. See :meth:`pybamm.Symbol.is_constant()`.
"""
return False
def __str__(self):
return str(self.name)