Source code for pytes.submodels.base_submodel

#
# Base class for PyTES submodels
#
"""
Base class for submodels.

A submodel is a small :class:`pybamm.BaseModel`: it sets its own variables, equations and
boundary and initial conditions, and refers to the variables of other submodels by name with
:class:`pybamm.CoupledVariable`. The model merges its submodels with
:meth:`pybamm.BaseModel.update` and resolves the coupled variables when it is built.

PyBaMM's ``pybamm.BaseSubModel`` is not used: it assumes a battery (its domains must be
"negative", "separator" or "positive" and its options are battery options).
"""

import pybamm


def parameter_names(symbols):
    """
    Names of the :class:`pybamm.Parameter` and :class:`pybamm.FunctionParameter` objects in
    some symbols, sorted.

    Parameters
    ----------
    symbols : iterable of pybamm.Symbol

    Returns
    -------
    tuple of str
    """
    names = set()
    for symbol in symbols:
        for node in symbol.pre_order():
            if isinstance(node, pybamm.Parameter | pybamm.FunctionParameter):
                names.add(node.name)
    return tuple(sorted(names))


[docs] class BaseSubModel(pybamm.BaseModel): """ A part of a model, with its inputs and outputs readable from the code. Subclasses implement :meth:`build`, which sets ``variables``, ``rhs``, ``algebraic``, ``boundary_conditions``, ``initial_conditions`` and ``events``. A variable set by another submodel is read with :meth:`coupled`, never by reaching into that submodel. Besides the attributes below, the metadata is read from the code (DESIGN D3): :attr:`requires`, :attr:`provides` and :attr:`parameters`. Parameters ---------- param : object The model's parameters. name : str, optional Name of the submodel. Attributes ---------- param : object The model's parameters. coupled_variables : dict The :class:`pybamm.CoupledVariable` objects created by :meth:`coupled`, by name (PyBaMM's own record of the variables a model needs from other models). assumptions : tuple of str Modelling assumptions, in a sentence each (for model cards). """ assumptions = () def __init__(self, param, name=None): super().__init__(name=name or type(self).__name__) self.param = param self.build()
[docs] def build(self): """Set the variables, equations and conditions of the submodel""" raise NotImplementedError
[docs] def coupled(self, name, domain=None): """ A variable set by another submodel, to be resolved when the model is built. Parameters ---------- name : str Name of the variable. domain : str or list of str, optional Its primary domain. The model checks it against the variable that provides it. Returns ------- pybamm.CoupledVariable """ if name not in self.coupled_variables: self.coupled_variables = { **self.coupled_variables, name: pybamm.CoupledVariable(name, domain), } return self.coupled_variables[name]
@property def requires(self): """Names of the variables this submodel needs from other submodels""" return tuple(self.coupled_variables) @property def provides(self): """Names of the variables this submodel sets""" return tuple(self.variables) @property def parameters(self): """ Names of the parameters this submodel uses, read from its equations, conditions, variables and the scales of its states. Domain lengths are not among them: they enter through the model's geometry (see :attr:`pytes.BaseModel.geometry_parameters`). """ symbols = [ *self.rhs.values(), *self.algebraic.values(), *self.initial_conditions.values(), *self.variables.values(), *(event.expression for event in self.events), ] for bcs in self.boundary_conditions.values(): symbols += [value for value, _ in bcs.values()] for state in [*self.rhs, *self.algebraic]: symbols += [ s for s in (state.scale, state.reference) if isinstance(s, pybamm.Symbol) ] return parameter_names(symbols) def __repr__(self): return f"{type(self).__name__}(name={self.name!r})"