Skip to content

Commit

Permalink
#692 changed to pass in external option
Browse files Browse the repository at this point in the history
  • Loading branch information
Scottmar93 committed Nov 8, 2019
1 parent eb0685e commit faf0a59
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 123 deletions.
14 changes: 12 additions & 2 deletions pybamm/discretisations/discretisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ def process_model(self, model, inplace=True):

# Prepare discretisation
# set variables (we require the full variable not just id)
variables = list(model.rhs.keys()) + list(model.algebraic.keys())
variables = (
list(model.rhs.keys())
+ list(model.algebraic.keys())
+ model.external_variables
)

# Set the y split for variables
pybamm.logger.info("Set variable slices for {}".format(model.name))
Expand Down Expand Up @@ -132,6 +136,8 @@ def process_model(self, model, inplace=True):

model_disc.bcs = self.bcs

self.external_variables = model.external_variables

# Process initial condtions
pybamm.logger.info("Discretise initial conditions for {}".format(model.name))
ics, concat_ics = self.process_initial_conditions(model)
Expand Down Expand Up @@ -795,7 +801,11 @@ def _concatenate_in_order(self, var_eqn_dict, check_complete=False, sparse=False
if check_complete:
# Check keys from the given var_eqn_dict against self.y_slices
ids = {v.id for v in unpacked_variables}
if ids != self.y_slices.keys():
external_id = {v.id for v in self.external_variables}
y_slices_with_external_removed = set(self.y_slices.keys()).difference(
external_id
)
if ids != y_slices_with_external_removed:
given_variable_names = [v.name for v in var_eqn_dict.keys()]
raise pybamm.ModelError(
"Initial conditions are insufficient. Only "
Expand Down
7 changes: 6 additions & 1 deletion pybamm/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,12 @@ def check_well_determined(self, post_discretisation):
# If any variables in the equations don't appear in the keys then the model is
# underdetermined
vars_in_keys = vars_in_rhs_keys.union(vars_in_algebraic_keys)
extra_variables = vars_in_eqns.difference(vars_in_keys)
extra_variables_in_equations = vars_in_eqns.difference(vars_in_keys)

# get ids of external variables
external_ids = {var.id for var in self.external_variables}
extra_variables = extra_variables_in_equations.difference(external_ids)

if extra_variables:
raise pybamm.ModelError("model is underdetermined (too many variables)")

Expand Down
98 changes: 60 additions & 38 deletions pybamm/models/full_battery_models/base_battery_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ class BaseBatteryModel(pybamm.BaseModel):
only takes effect if "dimensionality" is 0. If "dimensionality"
is 1 or 2 current collector effects are always included. Must be 'False'
for lead-acid models.
* "external submodels" : list
A list of the submodels that you would like to supply an external
variable for instead of solving in PyBaMM. The entries of the lists
are strings that correspond to the submodel names in the keys
of `self.submodels`.
**Extends:** :class:`pybamm.BaseModel`
Expand All @@ -68,6 +73,7 @@ def __init__(self, options=None, name="Unnamed battery model"):
self.set_standard_output_variables()
self.submodels = {}
self._built = False
self._built_fundamental_and_external = False

@property
def default_parameter_values(self):
Expand Down Expand Up @@ -157,6 +163,7 @@ def options(self, extra_options):
"particle": "Fickian diffusion",
"thermal": "isothermal",
"thermal current collector": False,
"external submodels": []
}
options = default_options
# any extra options overwrite the default options
Expand Down Expand Up @@ -396,17 +403,7 @@ def set_standard_output_variables(self):
{"y": var.y, "y [m]": var.y * L_y, "z": var.z, "z [m]": var.z * L_z}
)

def build_model(self):

# Check if already built
if self._built:
raise pybamm.ModelError(
"""Model already built. If you are adding a new submodel, try using
`model.update` instead."""
)

pybamm.logger.info("Building {}".format(self.name))

def build_fundamental_and_external(self):
# Get the fundamental variables
for submodel_name, submodel in self.submodels.items():
pybamm.logger.debug(
Expand All @@ -416,20 +413,25 @@ def build_model(self):
)
self.variables.update(submodel.get_fundamental_variables())

# Get any external variables
# set the submodels that are external
for sub in self.options["external submodels"]:
self.submodels[sub].external = True

# Set any external variables
self.external_variables = []
for submodel_name, submodel in self.submodels.items():
pybamm.logger.debug(
"Getting external variables for {} submodel ({})".format(
submodel_name, self.name
)
)
variables, external_variables = submodel.get_external_variables()
external_variables = submodel.get_external_variables()

self.variables.update(variables)
self.external_variables += external_variables

# Get coupled variables
self._built_fundamental_and_external = True

def build_coupled_variables(self):
# Note: pybamm will try to get the coupled variables for the submodels in the
# order they are set by the user. If this fails for a particular submodel,
# return to it later and try again. If setting coupled variables fails and
Expand Down Expand Up @@ -462,36 +464,56 @@ def build_model(self):
# try setting coupled variables on next loop through
pass

def build_model_equations(self):
# Set model equations
for submodel_name, submodel in self.submodels.items():
pybamm.logger.debug(
"Setting rhs for {} submodel ({})".format(submodel_name, self.name)
)
if submodel.external is False:
pybamm.logger.debug(
"Setting rhs for {} submodel ({})".format(submodel_name, self.name)
)

submodel.set_rhs(self.variables)
pybamm.logger.debug(
"Setting algebraic for {} submodel ({})".format(
submodel_name, self.name
submodel.set_rhs(self.variables)
pybamm.logger.debug(
"Setting algebraic for {} submodel ({})".format(
submodel_name, self.name
)
)
)
submodel.set_algebraic(self.variables)
pybamm.logger.debug(
"Setting boundary conditions for {} submodel ({})".format(
submodel_name, self.name
submodel.set_algebraic(self.variables)
pybamm.logger.debug(
"Setting boundary conditions for {} submodel ({})".format(
submodel_name, self.name
)
)
)
submodel.set_boundary_conditions(self.variables)
pybamm.logger.debug(
"Setting initial conditions for {} submodel ({})".format(
submodel_name, self.name
submodel.set_boundary_conditions(self.variables)
pybamm.logger.debug(
"Setting initial conditions for {} submodel ({})".format(
submodel_name, self.name
)
)
submodel.set_initial_conditions(self.variables)
submodel.set_events(self.variables)
pybamm.logger.debug(
"Updating {} submodel ({})".format(submodel_name, self.name)
)
self.update(submodel)

def build_model(self):

# Check if already built
if self._built:
raise pybamm.ModelError(
"""Model already built. If you are adding a new submodel, try using
`model.update` instead."""
)
submodel.set_initial_conditions(self.variables)
submodel.set_events(self.variables)
pybamm.logger.debug(
"Updating {} submodel ({})".format(submodel_name, self.name)
)
self.update(submodel)

pybamm.logger.info("Building {}".format(self.name))

if self._built_fundamental_and_external is False:
self.build_fundamental_and_external()

self.build_coupled_variables()

self.build_model_equations()

pybamm.logger.debug("Setting voltage variables")
self.set_voltage_variables()
Expand Down
38 changes: 30 additions & 8 deletions pybamm/models/submodels/base_submodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class BaseSubModel:
symbols.
"""

def __init__(self, param, domain=None, reactions=None):
def __init__(self, param, domain=None, reactions=None, external=False):
super().__init__()
self.param = param
# Initialise empty variables (to avoid overwriting with 'None')
Expand All @@ -62,6 +62,8 @@ def __init__(self, param, domain=None, reactions=None):
self.set_domain_for_broadcast()
self.reactions = reactions

self.external = external

@property
def domain(self):
return self._domain
Expand Down Expand Up @@ -101,20 +103,40 @@ def get_fundamental_variables(self):
"""
return {}

def set_external_variables(self):
def get_external_variables(self):
"""
A public method that creates and returns the variables in a submodel which are
suppled external to the model.
A public method that returns the variables in a submodel which are
supplied by an external source.
Returns
-------
dict :
The variables created by the submodel which are independent of variables in
other submodels.
list :
A list of the external variables in the model.
"""
return {}, []

external_variables = []
list_of_vars = []

if self.external is True:
# look through all the variables in the submodel and get the
# variables which are state vectors
submodel_variables = self.get_fundamental_variables()
for var in submodel_variables.values():
if isinstance(var, pybamm.Variable):
list_of_vars += [var]
elif isinstance(var, pybamm.Concatenation):
for child in var.children:
if isinstance(child, pybamm.Variable):
list_of_vars += [child]

# remove duplicates
unique_ids = []
for var in list_of_vars:
if var.id not in unique_ids:
external_variables += [var]
unique_ids += [var.id]

return external_variables

def get_coupled_variables(self, variables):
"""
Expand Down
Empty file.
32 changes: 0 additions & 32 deletions pybamm/models/submodels/thermal/external/full.py

This file was deleted.

39 changes: 0 additions & 39 deletions pybamm/models/submodels/thermal/external/lumped.py

This file was deleted.

7 changes: 4 additions & 3 deletions pybamm/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(
self._solver = solver or self._model.default_solver
self._quick_plot_vars = quick_plot_vars

self.reset()
self.reset(update_model=False)

def set_defaults(self):
"""
Expand All @@ -48,11 +48,12 @@ def set_defaults(self):
self._solver = self._model.default_solver
self._quick_plot_vars = None

def reset(self):
def reset(self, update_model=True):
"""
A method to reset a simulation back to its unprocessed state.
"""
self.model = self._model_class(self._model_options)
if update_model:
self.model = self._model_class(self._model_options)
self.geometry = copy.deepcopy(self._unprocessed_geometry)
self._model_with_set_params = None
self._built_model = None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# Tests for external submodels
#
import pybamm
import unittest


# only works for statevector inputs
class TestExternalSubmodel(unittest.TestCase):
def test_external_temperature(self):

model_options = {"thermal": "x-full", "external submodels": ["thermal"]}
model = pybamm.lithium_ion.SPMe(model_options)

sim = pybamm.Simulation(model)
sim.build()


if __name__ == "__main__":
print("Add -v for more debug output")
import sys

if "-v" in sys.argv:
debug = True
unittest.main()
Loading

0 comments on commit faf0a59

Please sign in to comment.