-
Notifications
You must be signed in to change notification settings - Fork 26
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
Allow linked design parameters #533
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #533 +/- ##
========================================
Coverage 99.08% 99.08%
========================================
Files 52 52
Lines 3605 3622 +17
========================================
+ Hits 3572 3589 +17
Misses 33 33 ☔ View full report in Codecov by Sentry. |
This is not the neatest implementation and only works for design problems, but it's functionality that I would like to use! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is such a good idea. I'm not a fan of monkeypatching functions on a method (it can lead to some very confusing debugging later down the line), and its probably going to be confusing for users if they have to replace a function with signature def update_linked_parameters(self, parameter_set: None):
with one that has a different signature def update_linked_parameters(parameter_set: Inputs):
.
In the example given, you are effectivly removing the "Positive electrode porosity" parameter from the model, but not really because this parameter still exists in the underlying pybamm model. If the model is used in a design problem it won't have this parameter because your custom function is overwriting it every time, but if it is used in a fitting problem it will have this parameter. Worse yet, if the user accidiently tries to add "Positive electrode porosity" to the list of fitted parameters in a design problem, pybop will happily accept this, even through the model doesn't have this parameter in it anymore. I think this will lead to all sorts of confusions
These are all good points... Let's find another way to implement this. I would like to be able to run this example and also change/add parameter relations to test different design assumptions. |
I would do something like this to alter the underlying pybamm model: import pybop
import pybamm
# The aim of this script is to show how to systematically update
# design parameters which depend on the optimisation parameters.
# Define parameter set and model
parameter_set = pybop.ParameterSet.pybamm("Chen2020", formation_concentrations=True)
model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)
parameter_to_replace = pybamm.Parameter("Positive electrode porosity")
replacement_symbol = 1 - pybamm.Parameter("Positive electrode active material volume fraction")
def replace_parameter(symbol):
if symbol == parameter_to_replace:
return replacement_symbol
else:
return symbol.create_copy(symbol.children)
def replace_dict(dictionary):
return {key: replace_parameter(value) for key, value in dictionary.items()}
def replace_list(lst):
return [replace_parameter(item) for item in lst]
new_model = model.pybamm_model.new_copy()
new_model.rhs = replace_dict(new_model.rhs)
new_model.algebraic = replace_dict(new_model.algebraic)
new_model.initial_conditions = replace_dict(new_model.initial_conditions)
new_model.boundary_conditions = replace_dict(new_model.boundary_conditions)
new_model.variables = replace_dict(new_model.variables)
new_model.events = replace_list(new_model.events)
model.pybamm_model = new_model
# Fitting parameters
parameters = pybop.Parameters(
pybop.Parameter(
"Positive electrode thickness [m]",
prior=pybop.Gaussian(7.56e-05, 0.1e-05),
bounds=[65e-06, 10e-05],
),
pybop.Parameter(
"Positive electrode active material volume fraction",
prior=pybop.Gaussian(0.6, 0.15),
bounds=[0.1, 0.9],
),
)
# Define test protocol
experiment = pybop.Experiment(
[
"Discharge at 1C until 2.5 V (5 seconds period)",
"Hold at 2.5 V for 30 minutes or until 10 mA (5 seconds period)",
],
)
signal = ["Voltage [V]", "Current [A]"]
# Generate problem
problem = pybop.DesignProblem(
model,
parameters,
experiment,
signal=signal,
initial_state={"Initial SoC": 1.0},
update_capacity=True,
)
# Define the cost
cost = pybop.GravimetricEnergyDensity(problem)
# Run optimisation
optim = pybop.XNES(
cost, verbose=True, allow_infeasible_solutions=False, max_iterations=10
)
x, final_cost = optim.run()
print("Estimated parameters:", x)
print(f"Initial gravimetric energy density: {cost(optim.x0):.2f} Wh.kg-1")
print(f"Optimised gravimetric energy density: {cost(x):.2f} Wh.kg-1")
# Plot the timeseries output
pybop.quick_plot(problem, problem_inputs=x, title="Optimised Comparison")
# Plot the cost landscape with optimisation path
pybop.plot2d(optim, steps=5) |
You could hide all the messing around with the pybamm model in a |
This is very nice, thanks @martinjrobins! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great @NicolaCourtier. I've made a few suggestions to improve the test on evaluate_symbol
Co-authored-by: Martin Robinson <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, nice one!
* Remove unused arguments * Create linked_parameters.py * Update CHANGELOG.md * swap to use expression in parameter set * Update README.md * Update optim result * Update CHANGELOG.md * Update linked_parameters.py * Test evaluate_symbol * Enforce volume fraction check * Update tests/unit/test_parameter_sets.py Co-authored-by: Martin Robinson <[email protected]> * Update test_parameter_sets.py --------- Co-authored-by: martinjrobins <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Description
Enables relations to be enforced between the optimisation parameters and other model parameters for the purpose of design optimisation. Adds an example showing how to link the porosity to the active material volume fraction.
Issue reference
Fixes #532
Review
Before you mark your PR as ready for review, please ensure that you've considered the following:
Type of change
Key checklist:
$ pre-commit run
(or$ nox -s pre-commit
) (see CONTRIBUTING.md for how to set this up to run automatically when committing locally, in just two lines of code)$ nox -s tests
$ nox -s doctest
You can run integration tests, unit tests, and doctests together at once, using
$ nox -s quick
.Further checks:
Thank you for contributing to our project! Your efforts help us to deliver great software.