Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify model copy #1977

Merged
merged 1 commit into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pybamm/discretisations/discretisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ def process_model(self, model, inplace=True, check_model=True):
# since they point to the same object
model_disc = model
else:
# create an empty copy of the original model
model_disc = model.new_empty_copy()
# create a copy of the original model
model_disc = model.new_copy()

# Keep a record of y_slices in the model
model_disc.y_slices = self.y_slices_explicit
Expand Down
4 changes: 2 additions & 2 deletions pybamm/expression_tree/operations/replace_symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def process_model(self, unprocessed_model, inplace=True):
# since they point to the same object
model = unprocessed_model
else:
# create a blank model of the same class
model = unprocessed_model.new_empty_copy()
# create a copy of the model
model = unprocessed_model.new_copy()

new_rhs = {}
for variable, equation in unprocessed_model.rhs.items():
Expand Down
47 changes: 14 additions & 33 deletions pybamm/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import warnings
from collections import OrderedDict

import copy
import casadi
import numpy as np

Expand Down Expand Up @@ -366,35 +367,21 @@ def __getitem__(self, key):
def default_quick_plot_variables(self):
return None

def new_empty_copy(self):
"""
Create an empty copy of the model with the same name and "parameters"
(convert_to_format, etc), but empty equations and variables.
This is usually then called by :class:`pybamm.ParameterValues`,
:class:`pybamm.Discretisation`, or :class:`pybamm.SymbolReplacer`.
"""
new_model = self.__class__(name=self.name)
new_model.use_jacobian = self.use_jacobian
new_model.convert_to_format = self.convert_to_format
new_model._timescale = self.timescale
new_model._length_scales = self.length_scales

# Variables from discretisation
new_model.is_discretised = self.is_discretised
new_model.y_slices = self.y_slices
new_model.concatenated_rhs = self.concatenated_rhs
new_model.concatenated_algebraic = self.concatenated_algebraic
new_model.concatenated_initial_conditions = self.concatenated_initial_conditions

return new_model

def new_copy(self):
"""
Creates an identical copy of the model, using the functionality of
:class:`pybamm.SymbolReplacer` but without performing any replacements
Creates a copy of the model, explicitly copying all the mutable attributes
to avoid issues with shared objects.
"""
replacer = pybamm.SymbolReplacer({})
return replacer.process_model(self, inplace=False)
new_model = copy.copy(self)
new_model._rhs = self.rhs.copy()
new_model._algebraic = self.algebraic.copy()
new_model._initial_conditions = self.initial_conditions.copy()
new_model._boundary_conditions = self.boundary_conditions.copy()
new_model._variables = self.variables.copy()
new_model._events = self.events.copy()
new_model.external_variables = self.external_variables.copy()
new_model._variables_casadi = self._variables_casadi.copy()
return new_model

def update(self, *submodels):
"""
Expand Down Expand Up @@ -435,13 +422,7 @@ def set_initial_conditions_from(self, solution, inplace=True):
if inplace is True:
model = self
else:
model = self.new_empty_copy()
model.rhs = self.rhs.copy()
model.algebraic = self.algebraic.copy()
model.initial_conditions = self.initial_conditions.copy()
model.boundary_conditions = self.boundary_conditions.copy()
model.variables = self.variables.copy()
model.events = self.events.copy()
model = self.new_copy()

if isinstance(solution, pybamm.Solution):
solution = solution.last_state
Expand Down
9 changes: 0 additions & 9 deletions pybamm/models/full_battery_models/base_battery_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,15 +864,6 @@ def build_model(self):
self._built = True
pybamm.logger.info("Finish building {}".format(self.name))

def new_empty_copy(self):
"""See :meth:`pybamm.BaseModel.new_empty_copy()`"""
new_model = self.__class__(name=self.name, options=self.options)
new_model.use_jacobian = self.use_jacobian
new_model.convert_to_format = self.convert_to_format
new_model._timescale = self.timescale
new_model._length_scales = self.length_scales
return new_model

@property
def summary_variables(self):
return self._summary_variables
Expand Down
3 changes: 0 additions & 3 deletions pybamm/models/full_battery_models/lead_acid/basic_full.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,3 @@ def __init__(self, name="Basic full model"):
pybamm.Event("Maximum voltage", voltage - param.voltage_high_cut),
]
)

def new_empty_copy(self):
return pybamm.BaseModel.new_empty_copy(self)
3 changes: 0 additions & 3 deletions pybamm/models/full_battery_models/lithium_ion/basic_dfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,3 @@ def __init__(self, name="Doyle-Fuller-Newman model"):
pybamm.Event("Minimum voltage", voltage - param.voltage_low_cut),
pybamm.Event("Maximum voltage", voltage - param.voltage_high_cut),
]

def new_empty_copy(self):
return pybamm.BaseModel.new_empty_copy(self)
2 changes: 0 additions & 2 deletions pybamm/models/full_battery_models/lithium_ion/basic_spm.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,3 @@ def __init__(self, name="Single Particle Model"):
pybamm.Event("Maximum voltage", V - param.voltage_high_cut),
]

def new_empty_copy(self):
return pybamm.BaseModel.new_empty_copy(self)
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,3 @@ def __init__(self, working_electrode, name="Electrode-specific SOH model"):
def default_solver(self):
# Use AlgebraicSolver as CasadiAlgebraicSolver gives unnecessary warnings
return pybamm.AlgebraicSolver()

def new_empty_copy(self):
new_model = ElectrodeSOHHalfCell(self.working_electrode, name=self.name)
return new_model
4 changes: 2 additions & 2 deletions pybamm/parameters/parameter_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ def process_model(self, unprocessed_model, inplace=True):
# since they point to the same object
model = unprocessed_model
else:
# create a blank model of the same class
model = unprocessed_model.new_empty_copy()
# create a copy of the model
model = unprocessed_model.new_copy()

if (
len(unprocessed_model.rhs) == 0
Expand Down
6 changes: 3 additions & 3 deletions pybamm/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,11 +515,11 @@ def build_for_experiment(self, check_model=True):
unbuilt_model,
parameter_values,
) in self.op_conds_to_model_and_param.items():
# It's ok to modify the models in-place as they are not accessible
# from outside the simulation
model_with_set_params = parameter_values.process_model(
unbuilt_model, inplace=True
unbuilt_model, inplace=False
)
# It's ok to modify the model with set parameters in place as it's
# not returned anywhere
built_model = self._disc.process_model(
model_with_set_params, inplace=True, check_model=check_model
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ def test_basic_full_lead_acid_well_posed(self):
model = pybamm.lead_acid.BasicFull()
model.check_well_posedness()

copy = model.new_copy()
copy.check_well_posedness()


if __name__ == "__main__":
print("Add -v for more debug output")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,19 @@ def test_dfn_well_posed(self):
model = pybamm.lithium_ion.BasicDFN()
model.check_well_posedness()

copy = model.new_copy()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the point of these tests, originally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just coverage

copy.check_well_posedness()

def test_spm_well_posed(self):
model = pybamm.lithium_ion.BasicSPM()
model.check_well_posedness()

copy = model.new_copy()
copy.check_well_posedness()

def test_dfn_half_cell_well_posed(self):
options = {"working electrode": "positive"}
model = pybamm.lithium_ion.BasicDFNHalfCell(options=options)
model.check_well_posedness()

copy = model.new_copy()
copy.check_well_posedness()

options = {"working electrode": "negative"}
model = pybamm.lithium_ion.BasicDFNHalfCell(options=options)
model.check_well_posedness()

copy = model.new_copy()
copy.check_well_posedness()

def test_dfn_half_cell_simulation_with_experiment_error(self):
options = {"working electrode": "negative"}
model = pybamm.lithium_ion.BasicDFNHalfCell(options=options)
Expand Down