diff --git a/pybamm/__init__.py b/pybamm/__init__.py index 265697628c..0678523e9f 100644 --- a/pybamm/__init__.py +++ b/pybamm/__init__.py @@ -148,6 +148,7 @@ def version(formatted=False): # from .models.base_model import BaseModel from .models import standard_variables +from .models.event import Event # Battery models from .models.full_battery_models.base_battery_model import BaseBatteryModel diff --git a/pybamm/discretisations/discretisation.py b/pybamm/discretisations/discretisation.py index 9473dcbd06..d996be13e4 100644 --- a/pybamm/discretisations/discretisation.py +++ b/pybamm/discretisations/discretisation.py @@ -198,11 +198,16 @@ def process_model(self, model, inplace=True, check_model=True): model_disc.algebraic, model_disc.concatenated_algebraic = alg, concat_alg # Process events - processed_events = {} + processed_events = [] pybamm.logger.info("Discretise events for {}".format(model.name)) - for event, equation in model.events.items(): + for event in model.events: pybamm.logger.debug("Discretise event '{}'".format(event)) - processed_events[event] = self.process_symbol(equation) + processed_event = pybamm.Event( + event.name, + self.process_symbol(event.expression), + event.event_type + ) + processed_events.append(processed_event) model_disc.events = processed_events # Create mass matrix diff --git a/pybamm/models/base_model.py b/pybamm/models/base_model.py index 360a5510de..ec5326ff90 100644 --- a/pybamm/models/base_model.py +++ b/pybamm/models/base_model.py @@ -46,9 +46,10 @@ class BaseModel(object): variables: dict A dictionary that maps strings to expressions that represent the useful variables - events: list - A list of events that should cause the solver to terminate (e.g. concentration - goes negative) + events: list of pybamm.Event + A list of events. Each event can either cause the solver to terminate + (e.g. concentration goes negative), or be used to inform the solver of the + existance of a discontinuity (e.g. discontinuity in the input current) concatenated_rhs : :class:`pybamm.Concatenation` After discretisation, contains the expressions representing the rhs equations concatenated into a single expression @@ -105,7 +106,7 @@ def __init__(self, name="Unnamed model"): self._initial_conditions = {} self._boundary_conditions = {} self._variables = {} - self._events = {} + self._events = [] self._concatenated_rhs = None self._concatenated_algebraic = None self._concatenated_initial_conditions = None @@ -337,7 +338,7 @@ def update(self, *submodels): self._boundary_conditions, submodel.boundary_conditions ) self.variables.update(submodel.variables) # keys are strings so no check - self._events.update(submodel.events) + self._events += submodel.events def check_and_combine_dict(self, dict1, dict2): # check that the key ids are distinct diff --git a/pybamm/models/event.py b/pybamm/models/event.py new file mode 100644 index 0000000000..e4975ba2b0 --- /dev/null +++ b/pybamm/models/event.py @@ -0,0 +1,52 @@ +import pybamm + +from enum import Enum + + +class EventType(Enum): + """Defines the type of event, see Event""" + TERMINATION = 0 + DISCONTINUITY = 1 + + +class Event: + """ + + Defines an event for use within a pybamm model + + Attributes + ---------- + + name: str + A string giving the name of the event + event_type: EventType + An enum defining the type of event, see EventType + expression: pybamm.Symbol + An expression that defines when the event occurs + + + """ + + def __init__(self, name, expression, event_type=EventType.TERMINATION): + self._name = name + self._expression = expression + self._event_type = event_type + + def __str__(self): + return self._name + + @property + def name(self): + return self._name + + @property + def expression(self): + return self._expression + + @expression.setter + def expression(self, value): + self._expression = value + + @property + def event_type(self): + return event_type diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index d8c17e2416..a8e74f2180 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -767,8 +767,16 @@ def set_voltage_variables(self): # Cut-off voltage voltage = self.variables["Terminal voltage"] - self.events["Minimum voltage"] = voltage - self.param.voltage_low_cut - self.events["Maximum voltage"] = voltage - self.param.voltage_high_cut + self.events.append(pybamm.Event( + "Minimum voltage", + voltage - self.param.voltage_low_cut, + pybamm.EventType.TERMINATION + )) + self.events.append(pybamm.Event( + "Maximum voltage", + voltage - self.param.voltage_high_cut, + pybamm.EventType.TERMINATION + )) # Power I_dim = self.variables["Current [A]"] diff --git a/pybamm/models/submodels/base_submodel.py b/pybamm/models/submodels/base_submodel.py index 99f8568773..335fdb8e9e 100644 --- a/pybamm/models/submodels/base_submodel.py +++ b/pybamm/models/submodels/base_submodel.py @@ -40,10 +40,10 @@ class BaseSubModel: variables: dict A dictionary that maps strings to expressions that represent the useful variables - events: dict - A dictionary of events that should cause the solver to terminate (e.g. - concentration goes negative). The keys are strings and the values are - symbols. + events: list + A list of events. Each event can either cause the solver to terminate + (e.g. concentration goes negative), or be used to inform the solver of the + existance of a discontinuity (e.g. discontinuity in the input current) """ def __init__( @@ -63,7 +63,7 @@ def __init__( self.boundary_conditions = {} self.initial_conditions = {} self.variables = {} - self.events = {} + self.events = [] self.domain = domain self.set_domain_for_broadcast() diff --git a/pybamm/models/submodels/electrolyte/base_electrolyte_diffusion.py b/pybamm/models/submodels/electrolyte/base_electrolyte_diffusion.py index 9f535f0d39..0f4df2a527 100644 --- a/pybamm/models/submodels/electrolyte/base_electrolyte_diffusion.py +++ b/pybamm/models/submodels/electrolyte/base_electrolyte_diffusion.py @@ -105,4 +105,8 @@ def _get_standard_flux_variables(self, N_e): def set_events(self, variables): c_e = variables["Electrolyte concentration"] - self.events["Zero electrolyte concentration cut-off"] = pybamm.min(c_e) - 0.002 + self.events.append(pybamm.Event( + "Zero electrolyte concentration cut-off", + pybamm.min(c_e) - 0.002, + pybamm.EventType.TERMINATION + )) diff --git a/pybamm/models/submodels/particle/base_particle.py b/pybamm/models/submodels/particle/base_particle.py index 5360472aae..dec23cf510 100644 --- a/pybamm/models/submodels/particle/base_particle.py +++ b/pybamm/models/submodels/particle/base_particle.py @@ -91,10 +91,14 @@ def set_events(self, variables): c_s_surf = variables[self.domain + " particle surface concentration"] tol = 0.01 - self.events[ - "Minumum " + self.domain.lower() + " particle surface concentration" - ] = (pybamm.min(c_s_surf) - tol) - - self.events[ - "Maximum " + self.domain.lower() + " particle surface concentration" - ] = (1 - tol) - pybamm.max(c_s_surf) + self.events.append(pybamm.Event( + "Minumum " + self.domain.lower() + " particle surface concentration", + pybamm.min(c_s_surf) - tol, + pybamm.EventType.TERMINATION + )) + + self.events.append(pybamm.Event( + "Maximum " + self.domain.lower() + " particle surface concentration", + (1 - tol) - pybamm.max(c_s_surf), + pybamm.EventType.TERMINATION + )) diff --git a/pybamm/models/submodels/porosity/base_porosity.py b/pybamm/models/submodels/porosity/base_porosity.py index 72a5082fce..1aebacf3df 100644 --- a/pybamm/models/submodels/porosity/base_porosity.py +++ b/pybamm/models/submodels/porosity/base_porosity.py @@ -96,7 +96,25 @@ def _get_standard_porosity_change_variables(self, deps_dt, set_leading_order=Fal def set_events(self, variables): eps_n = variables["Negative electrode porosity"] eps_p = variables["Positive electrode porosity"] - self.events["Zero negative electrode porosity cut-off"] = pybamm.min(eps_n) - self.events["Max negative electrode porosity cut-off"] = pybamm.max(eps_n) - 1 - self.events["Zero positive electrode porosity cut-off"] = pybamm.min(eps_p) - self.events["Max positive electrode porosity cut-off"] = pybamm.max(eps_p) - 1 + self.events.append(pybamm.Event( + "Zero negative electrode porosity cut-off", + pybamm.min(eps_n), + pybamm.EventType.TERMINATION + )) + self.events.append(pybamm.Event( + "Max negative electrode porosity cut-off", + pybamm.max(eps_n) - 1, + pybamm.EventType.TERMINATION + )) + + self.events.append(pybamm.Event( + "Zero positive electrode porosity cut-off", + pybamm.min(eps_p), + pybamm.EventType.TERMINATION + )) + + self.events.append(pybamm.Event( + "Max positive electrode porosity cut-off", + pybamm.max(eps_p) - 1, + pybamm.EventType.TERMINATION + )) diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py index 4f5ecdc250..4cb4cefec2 100644 --- a/pybamm/parameters/parameter_values.py +++ b/pybamm/parameters/parameter_values.py @@ -346,11 +346,11 @@ def process_model(self, unprocessed_model, processing="process", inplace=True): ) ) model.variables[variable] = processing_function(equation) - for event, equation in model.events.items(): + for event in model.events: pybamm.logger.debug( "{} parameters for event '{}''".format(processing.capitalize(), event) ) - model.events[event] = processing_function(equation) + event.expression = processing_function(event.expression) pybamm.logger.info("Finish setting parameters for {}".format(model.name))