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

MSMR model #3116

Merged
merged 53 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e60ec43
basic MSMR model with fast diffusion
rtimms May 26, 2023
094f2b6
run test simulation
rtimms May 26, 2023
6387858
particle problem in basic SP MSMR
rtimms May 31, 2023
d1b20a7
update example
rtimms Jun 13, 2023
318f6d3
merge develop
rtimms Jun 13, 2023
e0e42d1
MSMR submodels for diffusion and ocp
rtimms Jun 14, 2023
c644be8
MSMR model options + example
rtimms Jun 14, 2023
e7f9c18
fix options test
rtimms Jun 15, 2023
8d92c18
merge develop
rtimms Jun 20, 2023
dbf2018
esoh for msmr mostly working
rtimms Jun 21, 2023
3a7c39f
start cleaning up esoh
rtimms Jun 21, 2023
ac821e8
fix eSOH
rtimms Jun 23, 2023
0c61222
improve esoh
rtimms Jun 23, 2023
f9a92be
Use .diff to get dx/dU
rtimms Jun 23, 2023
86c4184
esoh tests
rtimms Jun 23, 2023
c49e36f
merge develop
rtimms Jul 4, 2023
42c7438
fix diff for broadcasts
rtimms Jul 4, 2023
4c0758d
start msmr notebook
rtimms Jul 6, 2023
c94d842
improve coverage
rtimms Jul 9, 2023
75835b5
update esoh
rtimms Jul 9, 2023
0f7c2ab
clean up notebook
rtimms Jul 10, 2023
51702ca
merge develop
rtimms Jul 10, 2023
ab61213
add helper function for msmr reactions
rtimms Jul 10, 2023
7b12a61
docs and notebook
rtimms Jul 11, 2023
a33c3af
fix initial soc at solve
rtimms Jul 12, 2023
d88dfb8
merge develop
rtimms Jul 12, 2023
8396295
update notebook
rtimms Jul 12, 2023
917a53b
fix test
rtimms Jul 12, 2023
9af984d
merge develop
rtimms Jul 18, 2023
8c95a6d
add individual reaction params
rtimms Jul 18, 2023
085543f
fix setting by reaction index
rtimms Jul 18, 2023
899067f
add MSMR model class
rtimms Jul 18, 2023
e9148ae
add paramaters by reaction index
rtimms Jul 19, 2023
986d171
debugging current density
rtimms Jul 19, 2023
10bec45
fix exchange current parameters
rtimms Jul 20, 2023
e549a4e
fix PSD
rtimms Jul 21, 2023
f7f8741
merge develop
rtimms Jul 21, 2023
78d2776
esoh coverage
rtimms Jul 21, 2023
925a04e
merge develop
rtimms Jul 21, 2023
fc0d71e
update notebook
rtimms Jul 28, 2023
c4953df
merge 'develop' into 'msmr'
rtimms Aug 10, 2023
d73a1eb
style: pre-commit fixes
pre-commit-ci[bot] Aug 10, 2023
32b73e5
fix tests
rtimms Aug 10, 2023
54a06e0
merge conflicts
rtimms Aug 10, 2023
d8dace3
debug half cell
rtimms Aug 11, 2023
9e513bf
merge develop
rtimms Aug 31, 2023
d1cd977
relax option check
rtimms Aug 31, 2023
d3d921d
merge develop
rtimms Sep 11, 2023
c030b88
ferran msmr comments
rtimms Sep 11, 2023
f8a0fbc
update docs
rtimms Sep 11, 2023
c330ffa
fix example notebooks
rtimms Sep 13, 2023
cb36b35
merge develop
rtimms Sep 13, 2023
77a62c1
update bib in docs
rtimms Sep 13, 2023
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
295 changes: 295 additions & 0 deletions docs/source/examples/notebooks/models/MSMR.ipynb
Copy link
Member

Choose a reason for hiding this comment

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

Picky comment, can you delete the empty cells at the end of the notebook?

Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Multi-Species Multi-Reaction model"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Model Equations"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example solving MSMR using PyBaMM"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"#%pip install pybamm -q # install PyBaMM if it is not installed\n",
"import pybamm\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"model = pybamm.lithium_ion.SPM(\n",
" {\n",
" \"open-circuit potential\": \"MSMR\",\n",
" \"particle\": \"MSMR\",\n",
" }\n",
")\n",
"\n",
"parameter_values = pybamm.ParameterValues(\"MSMR_Example\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# x_n\n",
"U_n = model.variables[\"Negative electrode open-circuit potential [V]\"]\n",
"T = model.variables[\"Negative electrode temperature [K]\"]\n",
"f = pybamm.constants.F / (pybamm.constants.R * T)\n",
"for i in range(6):\n",
" U0 = pybamm.Parameter(f\"U0_n_{i}\")\n",
" w = pybamm.Parameter(f\"w_n_{i}\")\n",
" Xj = pybamm.Parameter(f\"Xj_n_{i}\")\n",
"\n",
" x_n = Xj / (1 + pybamm.exp(f * (U_n - U0) / w))\n",
" model.variables[f\"x{i}_n\"] = x_n\n",
" model.variables[f\"X-averaged x{i}_n\"] = pybamm.x_average(x_n)\n",
" \n",
"\n",
"# x_p\n",
"U_p = model.variables[\"Positive electrode open-circuit potential [V]\"]\n",
"T = model.variables[\"Positive electrode temperature [K]\"]\n",
"f = pybamm.constants.F / (pybamm.constants.R * T)\n",
"for i in range(4):\n",
" U0 = pybamm.Parameter(f\"U0_p_{i}\")\n",
" w = pybamm.Parameter(f\"w_p_{i}\")\n",
" Xj = pybamm.Parameter(f\"Xj_p_{i}\")\n",
"\n",
" x_p = Xj / (1 + pybamm.exp(f * (U_p - U0) / w))\n",
" model.variables[f\"x{i}_p\"] = x_p\n",
" model.variables[f\"X-averaged x{i}_p\"] = pybamm.x_average(x_p)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<pybamm.solvers.solution.Solution at 0x14be066a0>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"experiment = pybamm.Experiment(\n",
" [\n",
" (\n",
" \"Discharge at 1C for 1 hour or until 3 V\",\n",
" \"Rest for 1 hour\",\n",
" \"Charge at C/3 until 4 V\",\n",
" \"Hold at 4 V until 10 mA\",\n",
" \"Rest for 1 hour\",\n",
" ),\n",
" ]\n",
")\n",
"sim = pybamm.Simulation(model, parameter_values=parameter_values, experiment=experiment)\n",
"sim.solve()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a2be754ae444465a9b5c413582e703f1",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.0, description='t', max=5.86646556905814, step=0.0586646556905814), …"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<pybamm.plotting.quick_plot.QuickPlot at 0x14fb3bcd0>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sim.plot(\n",
" [\n",
" \"X-averaged negative particle stoichiometry\",\n",
" \"X-averaged positive particle stoichiometry\",\n",
" \"X-averaged negative particle potential [V]\",\n",
" \"X-averaged positive particle potential [V]\",\n",
" [f\"X-averaged x{i}_n\" for i in range(6)],\n",
" [f\"X-averaged x{i}_p\" for i in range(4)],\n",
" \"X-averaged negative electrode open-circuit potential [V]\",\n",
" \"X-averaged positive electrode open-circuit potential [V]\",\n",
" \"Current [A]\",\n",
" \"Voltage [V]\",\n",
" ]\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Comparison with ideal diffusion and \"standard\" OCV model"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 162,
"metadata": {},
"outputs": [],
"source": [
"def U_n(sto):\n",
" u_eq = (\n",
" 0.3635 * pybamm.exp(-439.3 * sto)\n",
" + 0.6908\n",
" + 0.5489 * pybamm.tanh(-30.07 * sto)\n",
" - 0.0344 * pybamm.tanh(25.46 * (sto - 0.1713))\n",
" - 0.0276 * pybamm.tanh(14.27 * (sto - 0.5270))\n",
"\n",
" )\n",
" return u_eq\n",
"\n",
"def U_p(sto):\n",
" u_eq = (\n",
" -0.3415 * sto\n",
" + 4.116\n",
" - 0.2835 * pybamm.tanh(4.181 * (sto - 0.2324))\n",
" - 0.1020 * pybamm.tanh(29.61 * (sto - 1))\n",
" )\n",
" return u_eq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"parameter_values_2 = parameter_values.copy()\n",
"parameter_values_2.update({\n",
" \"Negative electrode OCP [V]\": U_n,\n",
" \"Positive electrode OCP [V]\": U_p,\n",
"})"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## References\n",
"\n",
"The relevant papers for this notebook are:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1] Joel A. E. Andersson, Joris Gillis, Greg Horn, James B. Rawlings, and Moritz Diehl. CasADi – A software framework for nonlinear optimization and optimal control. Mathematical Programming Computation, 11(1):1–36, 2019. doi:10.1007/s12532-018-0139-4.\n",
"[2] Daniel R Baker and Mark W Verbrugge. Multi-species, multi-reaction model for porous intercalation electrodes: part i. model formulation and a perturbation solution for low-scan-rate, linear-sweep voltammetry of a spinel lithium manganese oxide electrode. Journal of The Electrochemical Society, 165(16):A3952, 2018.\n",
"[3] Charles R. Harris, K. Jarrod Millman, Stéfan J. van der Walt, Ralf Gommers, Pauli Virtanen, David Cournapeau, Eric Wieser, Julian Taylor, Sebastian Berg, Nathaniel J. Smith, and others. Array programming with NumPy. Nature, 585(7825):357–362, 2020. doi:10.1038/s41586-020-2649-2.\n",
"[4] Scott G. Marquis, Valentin Sulzer, Robert Timms, Colin P. Please, and S. Jon Chapman. An asymptotic derivation of a single particle model with electrolyte. Journal of The Electrochemical Society, 166(15):A3693–A3706, 2019. doi:10.1149/2.0341915jes.\n",
"[5] Peyman Mohtat, Suhak Lee, Jason B Siegel, and Anna G Stefanopoulou. Towards better estimability of electrode-specific state of health: decoding the cell expansion. Journal of Power Sources, 427:101–111, 2019.\n",
"[6] Valentin Sulzer, Scott G. Marquis, Robert Timms, Martin Robinson, and S. Jon Chapman. Python Battery Mathematical Modelling (PyBaMM). Journal of Open Research Software, 9(1):14, 2021. doi:10.5334/jors.309.\n",
"[7] Pauli Virtanen, Ralf Gommers, Travis E. Oliphant, Matt Haberland, Tyler Reddy, David Cournapeau, Evgeni Burovski, Pearu Peterson, Warren Weckesser, Jonathan Bright, and others. SciPy 1.0: fundamental algorithms for scientific computing in Python. Nature Methods, 17(3):261–272, 2020. doi:10.1038/s41592-019-0686-2.\n",
"[8] Andrew Weng, Jason B Siegel, and Anna Stefanopoulou. Differential voltage analysis for battery manufacturing process control. arXiv preprint arXiv:2303.07088, 2023.\n",
"\n"
]
}
],
"source": [
"pybamm.print_citations()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dev",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
},
"vscode": {
"interpreter": {
"hash": "bca2b99bfac80e18288b793d52fa0653ab9b5fe5d22e7b211c44eb982a41c00c"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
26 changes: 26 additions & 0 deletions examples/scripts/MSMR.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pybamm

pybamm.set_logging_level("DEBUG")
model = pybamm.lithium_ion.SPM(
{
"open-circuit potential": "MSMR",
"particle": "MSMR",
}
)


parameter_values = pybamm.ParameterValues("MSMR_Example")
experiment = pybamm.Experiment(
[
(
"Discharge at 1C for 1 hour or until 3 V",
"Rest for 1 hour",
"Charge at C/3 until 4 V",
"Hold at 4 V until 10 mA",
"Rest for 1 hour",
),
]
)
sim = pybamm.Simulation(model, parameter_values=parameter_values, experiment=experiment)
sim.solve()
sim.plot()
11 changes: 11 additions & 0 deletions pybamm/CITATIONS.bib
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ @article{Andersson2019
doi = {10.1007/s12532-018-0139-4},
}

@article{Baker2018,
title={Multi-species, multi-reaction model for porous intercalation electrodes: Part I. Model formulation and a perturbation solution for low-scan-rate, linear-sweep voltammetry of a spinel lithium manganese oxide electrode},
author={Baker, Daniel R and Verbrugge, Mark W},
journal={Journal of The Electrochemical Society},
volume={165},
number={16},
pages={A3952},
year={2018},
publisher={IOP Publishing}
}

@article{BrosaPlanella2021,
title = {Systematic derivation and validation of a reduced thermal-electrochemical model for lithium-ion batteries using asymptotic methods},
author = {Brosa Planella, Ferran and Sheikh, Muhammad and Widanage, W. Dhammika},
Expand Down
21 changes: 21 additions & 0 deletions pybamm/expression_tree/broadcasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ def _sympy_operator(self, child):
"""Override :meth:`pybamm.UnaryOperator._sympy_operator`"""
return child

def diff(self, variable):
"""
Override :meth:`pybamm.SpatialOperator.diff()` to reinstate behaviour of
:meth:`pybamm.Symbol.diff()`.
"""
Copy link
Member

Choose a reason for hiding this comment

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

probably cleaner to just get rid of the NotImplementedError for spatial operators

if variable == self:
return pybamm.Scalar(1)
elif any(variable == x for x in self.pre_order()):
return self._diff(variable)
elif variable == pybamm.t and self.has_symbol_of_classes(
(pybamm.VariableBase, pybamm.StateVectorBase)
):
return self._diff(variable)
else:
return pybamm.Scalar(0)

def _diff(self, variable):
"""See :meth:`pybamm.Symbol._diff()`."""
# Differentiate the child and broadcast the result in the same way
return self._unary_new_copy(self.child.diff(variable))


class PrimaryBroadcast(Broadcast):
"""
Expand Down
2 changes: 1 addition & 1 deletion pybamm/expression_tree/unary_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def __init__(self, name, child, domains=None):

def diff(self, variable):
"""See :meth:`pybamm.Symbol.diff()`."""
# We shouldn't need this
# We shouldn't need this, except for Broadcasts
raise NotImplementedError


Expand Down
Loading