Source code for pybamm.experiment.step.step_termination

from warnings import warn

import pybamm


[docs] class BaseTermination: """ Base class for a termination event for an experiment step. To create a custom termination, a class must implement `get_event_expression` to return the symbolic expression for the event. In most cases the class :class:`pybamm.step.CustomTermination` can be used to assist with this. Parameters ---------- value : float The value at which the event is triggered """ def __init__(self, value, operator=None): self.value = value if operator not in ["<", ">", None]: raise ValueError(f"Invalid operator: {operator}") self.operator = operator def get_event_name(self, step): raise NotImplementedError # pragma: no cover
[docs] def get_event_expression(self, variables, step): """ Return the symbolic expression corresponding to the termination event. Parameters ---------- variables : dict Dictionary of model variables, to be used for selecting the variable(s) that determine the event step : :class:`pybamm.step.BaseStep` Step for which this is a termination event, to be used in some cases to determine the sign of the event. """ raise NotImplementedError # pragma: no cover
def get_event(self, variables, step): expression = self.get_event_expression(variables, step) if expression is None: return None return pybamm.Event(self.get_event_name(step), expression) def __repr__(self) -> str: op = "" if self.operator is None else f" {self.operator}" return f"{type(self).__name__}({self.value}{op})" def __eq__(self, other) -> bool: if type(self) is not type(other): return False return self.value == other.value and self.operator == other.operator def __hash__(self) -> int: return hash((type(self).__name__, self.value, self.operator))
[docs] class CRateTermination(BaseTermination): """ Termination based on C-rate, created when a string termination of the C-rate type (e.g. "C/10") is provided """ def get_event_name(self, step): return "C-rate cut-off [experiment]"
[docs] def get_event_expression(self, variables, step): return abs(variables["C-rate"]) - self.value
class CrateTermination(CRateTermination): """ Termination based on C-rate, created when a string termination of the C-rate type (e.g. "C/10") is provided """ def __init__(self, value, operator=None): super().__init__(value, operator) warning = DeprecationWarning( "CrateTermination is deprecated and will be removed in a future release. Use CRateTermination instead." ) warn(warning, stacklevel=2)
[docs] class CurrentTermination(BaseTermination): """ Termination based on current, created when a string termination of the current type (e.g. "1A") is provided """ def get_event_name(self, step): operator = self.operator if operator == ">": return f"Current [A] > {self.value} [A] [experiment]" elif operator == "<": return f"Current [A] < {self.value} [A] [experiment]" else: return f"abs(Current [A]) < {self.value} [A] [experiment]"
[docs] def get_event_expression(self, variables, step): operator = self.operator if operator == ">": return self.value - variables["Current [A]"] elif operator == "<": return variables["Current [A]"] - self.value else: return abs(variables["Current [A]"]) - self.value
[docs] class VoltageTermination(BaseTermination): """ Termination based on voltage, created when a string termination of the voltage type (e.g. "4.2V") is provided """ def _get_operator(self, step): operator = self.operator if operator is None: direction = step.direction if direction == "charge": operator = ">" elif direction == "discharge": operator = "<" else: return None return operator def get_event_name(self, step): operator = self._get_operator(step) if operator is None: return None return f"Voltage {operator} {self.value} [V] [experiment]"
[docs] def get_event_expression(self, variables, step): # The voltage event should be positive at the start of charge/ # discharge. We use the sign of the current or power input to # figure out whether the voltage event is greater than the starting # voltage (charge) or less (discharge) and set the sign of the # event accordingly operator = self._get_operator(step) if operator is None: return None if operator == ">": sign = -1 else: sign = 1 return sign * (variables["Battery voltage [V]"] - self.value)
class Voltage: def __gt__(self, value): return VoltageTermination(value, operator=">") def __lt__(self, value): return VoltageTermination(value, operator="<") class Current: def __gt__(self, value): return CurrentTermination(value, operator=">") def __lt__(self, value): return CurrentTermination(value, operator="<")
[docs] class CustomTermination(BaseTermination): """ Define a custom termination event using a function. This can be used to create an event based on any variable in the model. Parameters ---------- name : str Name of the event event_function : callable A function that takes in a dictionary of variables and evaluates the event value. Must be positive before the event is triggered and zero when the event is triggered. Example ------- Add a cut-off based on negative electrode stoichiometry. The event will trigger when the negative electrode stoichiometry reaches 10%. >>> def neg_stoich_cutoff(variables): ... return variables["Negative electrode stoichiometry"] - 0.1 >>> neg_stoich_termination = pybamm.step.CustomTermination( ... name="Negative stoichiometry cut-off", event_function=neg_stoich_cutoff ... ) """ def __init__(self, name, event_function): if not name.endswith(" [experiment]"): name += " [experiment]" self.name = name self.event_function = event_function def get_event_name(self, step): return self.name
[docs] def get_event_expression(self, variables, step): return self.event_function(variables)
def __repr__(self) -> str: return f"{type(self).__name__}({self.name})" def __eq__(self, other) -> bool: if type(self) is not type(other): return False return self.name == other.name and self.event_function is other.event_function def __hash__(self) -> int: return hash((type(self).__name__, self.name, id(self.event_function)))
def _read_termination(termination, operator=None): if isinstance(termination, tuple): op, typ, value = termination else: return termination termination_class = { "current": CurrentTermination, "voltage": VoltageTermination, "C-rate": CRateTermination, }[typ] return termination_class(value, operator=op)