Skip to content

Commit

Permalink
Merge pull request #1459 from pybamm-team/experiment-refactor
Browse files Browse the repository at this point in the history
Experiment refactor
  • Loading branch information
valentinsulzer committed May 26, 2021
2 parents 7d8ec5c + ad1590d commit fe6960c
Show file tree
Hide file tree
Showing 71 changed files with 4,183 additions and 3,329 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
- Some features ("loss of active material" and "particle mechanics") can now be specified separately for the negative electrode and positive electrode by passing a 2-tuple ([#1490](https://github.com/pybamm-team/PyBaMM/pull/1490))
- `plot` and `plot2D` now take and return a matplotlib Axis to allow for easier customization ([#1472](https://github.com/pybamm-team/PyBaMM/pull/1472))
- `ParameterValues.evaluate` can now return arrays to allow function parameters to be easily evaluated ([#1472](https://github.com/pybamm-team/PyBaMM/pull/1472))
- Added option to save only specific cycle numbers when simulating an `Experiment` ([#1459](https://github.com/pybamm-team/PyBaMM/pull/1459))
- Added capacity-based termination conditions when simulating an `Experiment` ([#1459](https://github.com/pybamm-team/PyBaMM/pull/1459))
- Added "summary variables" to track degradation over several cycles ([#1459](https://github.com/pybamm-team/PyBaMM/pull/1459))
- Added `ElectrodeSOH` model for calculating capacities and stoichiometric limits ([#1459](https://github.com/pybamm-team/PyBaMM/pull/1459))
- Added Batch Study class ([#1455](https://github.com/pybamm-team/PyBaMM/pull/1455))
- Added `ConcatenationVariable`, which is automatically created when variables are concatenated ([#1453](https://github.com/pybamm-team/PyBaMM/pull/1453))
- Added "fast with events" mode for the CasADi solver, which solves a model and finds events more efficiently than "safe" mode. As of PR #1450 this feature is still being tested and "safe" mode remains the default ([#1450](https://github.com/pybamm-team/PyBaMM/pull/1450))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,9 @@
" 'Current collector current density',\n",
" 'Current collector current density [A.m-2]',\n",
" 'Leading-order current collector current density',\n",
" 'Sei interfacial current density',\n",
" 'Sei interfacial current density [A.m-2]',\n",
" 'Sei interfacial current density per volume [A.m-3]',\n",
" 'SEI interfacial current density',\n",
" 'SEI interfacial current density [A.m-2]',\n",
" 'SEI interfacial current density per volume [A.m-3]',\n",
" 'Negative electrode interfacial current density',\n",
" 'X-averaged negative electrode interfacial current density',\n",
" 'Negative electrode interfacial current density [A.m-2]',\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,20 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
"version": "3.8.8"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
}
},
"nbformat": 4,
Expand Down
338 changes: 0 additions & 338 deletions examples/notebooks/Validating_mechanical_models_Enertech_DFN.ipynb

This file was deleted.

376 changes: 376 additions & 0 deletions examples/notebooks/electrode-state-of-health.ipynb

Large diffs are not rendered by default.

100 changes: 89 additions & 11 deletions examples/notebooks/lithium-plating.ipynb

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions examples/notebooks/models/SPM.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@
"\t- Total lithium in negative electrode [mol]\n",
"\t- Positive particle flux\n",
"\t- X-averaged positive particle flux\n",
"\t- Total lithium in electrolyte [mol]\n",
"\t- Positive electrode volume-averaged concentration\n",
"\t- Positive electrode volume-averaged concentration [mol.m-3]\n",
"\t- Total lithium in positive electrode [mol]\n",
Expand Down Expand Up @@ -729,9 +730,9 @@
"\t- Current collector current density\n",
"\t- Current collector current density [A.m-2]\n",
"\t- Leading-order current collector current density\n",
"\t- Sei interfacial current density\n",
"\t- Sei interfacial current density [A.m-2]\n",
"\t- Sei interfacial current density per volume [A.m-3]\n",
"\t- SEI interfacial current density\n",
"\t- SEI interfacial current density [A.m-2]\n",
"\t- SEI interfacial current density per volume [A.m-3]\n",
"\t- X-averaged negative electrode total interfacial current density\n",
"\t- X-averaged negative electrode total interfacial current density [A.m-2]\n",
"\t- X-averaged negative electrode total interfacial current density per volume [A.m-3]\n",
Expand Down

Large diffs are not rendered by default.

1,964 changes: 1,964 additions & 0 deletions examples/notebooks/simulating-long-experiments.ipynb

Large diffs are not rendered by default.

2,507 changes: 49 additions & 2,458 deletions examples/notebooks/speed-up-solver.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"name": "stdout",
"text": [
"\u001b[33mWARNING: You are using pip version 21.0.1; however, version 21.1.1 is available.\n",
"\u001b[33mWARNING: You are using pip version 21.0.1; however, version 21.1.2 is available.\n",
"You should consider upgrading via the '/Users/vsulzer/Documents/Energy_storage/PyBaMM/.tox/dev/bin/python -m pip install --upgrade pip' command.\u001b[0m\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
Expand Down Expand Up @@ -47,10 +47,11 @@
"metadata": {},
"outputs": [],
"source": [
"# model = pybamm.lithium_ion.SPMe(\n",
"# model = pybamm.lithium_ion.SPM(\n",
"model = pybamm.lithium_ion.DFN(\n",
" options = {\"particle mechanics\": \"swelling and cracking\"}\n",
" options = {\n",
" \"particle\": \"Fickian diffusion\", \n",
" \"particle mechanics\": \"swelling and cracking\", # other options are \"none\", \"swelling only\"\n",
" }\n",
")"
]
},
Expand Down Expand Up @@ -87,18 +88,16 @@
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…",
"application/vnd.jupyter.widget-view+json": {
"model_id": "c3b1f934d8e34942a66d8771c0d09d17",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
]
"version_minor": 0,
"model_id": "653353cedea84635a916a217d9826e3c"
}
},
"metadata": {},
"output_type": "display_data"
"metadata": {}
}
],
"source": [
Expand Down Expand Up @@ -126,18 +125,16 @@
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='t', max=3600.0, step=10.0), Output()), _dom_classes=…",
"application/vnd.jupyter.widget-view+json": {
"model_id": "232ab4b5fb4b49d6832cc709518ad61a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.0, description='t', max=3600.0, step=10.0), Output()), _dom_classes=…"
]
"version_minor": 0,
"model_id": "a5ed452d11ce494d83f30efec6b6abb4"
}
},
"metadata": {},
"output_type": "display_data"
"metadata": {}
}
],
"source": [
Expand Down Expand Up @@ -193,18 +190,16 @@
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…",
"application/vnd.jupyter.widget-view+json": {
"model_id": "f42ca205ce824664917d70d8ff35bebf",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
]
"version_minor": 0,
"model_id": "dbe2842d65ad4cbd9d0efcaf97a50b57"
}
},
"metadata": {},
"output_type": "display_data"
"metadata": {}
}
],
"source": [
Expand Down Expand Up @@ -234,16 +229,10 @@
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"name": "stdout",
"text": [
"[1] Weilong Ai, Ludwig Kraft, Johannes Sturm, Andreas Jossen, and Billy Wu. Electrochemical thermal-mechanical modelling of stress inhomogeneity in lithium-ion pouch cells. Journal of The Electrochemical Society, 167(1):013512, 2019. doi:10.1149/2.0122001JES.\n",
"[2] 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",
"[3] Rutooj Deshpande, Mark Verbrugge, Yang-Tse Cheng, John Wang, and Ping Liu. Battery cycle life prediction with coupled chemical degradation and fatigue mechanics. Journal of the Electrochemical Society, 159(10):A1730, 2012. doi:10.1149/2.049210jes.\n",
"[4] Marc Doyle, Thomas F. Fuller, and John Newman. Modeling of galvanostatic charge and discharge of the lithium/polymer/insertion cell. Journal of the Electrochemical society, 140(6):1526–1533, 1993. doi:10.1149/1.2221597.\n",
"[5] 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",
"[6] Valentin Sulzer, Scott G. Marquis, Robert Timms, Martin Robinson, and S. Jon Chapman. Python Battery Mathematical Modelling (PyBaMM). ECSarXiv. February, 2020. doi:10.1149/osf.io/67ckj.\n",
"\n"
"[1] Weilong Ai, Ludwig Kraft, Johannes Sturm, Andreas Jossen, and Billy Wu. Electrochemical thermal-mechanical modelling of stress inhomogeneity in lithium-ion pouch cells. Journal of The Electrochemical Society, 167(1):013512, 2019. doi:10.1149/2.0122001JES.\n[2] 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[3] Rutooj Deshpande, Mark Verbrugge, Yang-Tse Cheng, John Wang, and Ping Liu. Battery cycle life prediction with coupled chemical degradation and fatigue mechanics. Journal of the Electrochemical Society, 159(10):A1730, 2012. doi:10.1149/2.049210jes.\n[4] Marc Doyle, Thomas F. Fuller, and John Newman. Modeling of galvanostatic charge and discharge of the lithium/polymer/insertion cell. Journal of the Electrochemical society, 140(6):1526–1533, 1993. doi:10.1149/1.2221597.\n[5] 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[6] Valentin Sulzer, Scott G. Marquis, Robert Timms, Martin Robinson, and S. Jon Chapman. Python Battery Mathematical Modelling (PyBaMM). ECSarXiv. February, 2020. doi:10.1149/osf.io/67ckj.\n\n"
]
}
],
Expand Down Expand Up @@ -286,4 +275,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
33 changes: 20 additions & 13 deletions examples/notebooks/submodel_loss_of_active_materials.ipynb

Large diffs are not rendered by default.

11 changes: 2 additions & 9 deletions examples/scripts/calendar_ageing.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,8 @@
"X-averaged total negative electrode SEI thickness",
"X-averaged negative electrode SEI concentration [mol.m-3]",
"Loss of lithium to negative electrode SEI [mol]",
[
"Negative electrode SEI interfacial current density [A.m-2]",
"Negative electrode interfacial current density [A.m-2]",
],
[
"X-averaged negative electrode SEI interfacial current density [A.m-2]",
"X-averaged negative electrode interfacial current density [A.m-2]",
],
"Sum of x-averaged negative electrode interfacial current densities",
"X-averaged electrolyte concentration",
"Loss of lithium inventory [%]",
["Total lithium lost [mol]", "Loss of lithium to negative electrode SEI [mol]"],
],
)
3 changes: 1 addition & 2 deletions examples/scripts/conservation_lithium.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@
solution = sim.solution

t = solution["Time [s]"].entries
Ne = solution["Total concentration in electrolyte [mol]"].entries
Np = solution["Total lithium in positive electrode [mol]"].entries
Nn = solution["Total lithium in negative electrode [mol]"].entries
Ntot = Np + Nn + Ne
Ntot = solution["Total lithium [mol]"].entries

fig, ax = plt.subplots(1, 2, figsize=(12, 5))

Expand Down
32 changes: 19 additions & 13 deletions examples/scripts/cycling_ageing_yang.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import pybamm as pb

# Note: the Yang model is still in active development and results do not
# match with those reported in the paper

pb.set_logging_level("NOTICE")
model = pb.lithium_ion.Yang2017()

Expand Down Expand Up @@ -27,18 +30,18 @@
"Rest for 30 minutes",
"Discharge at 1 C until 2.8 V",
),
# (
# "Charge at 1 C until 4.2 V",
# "Hold at 4.2 V until C/20",
# "Rest for 30 minutes",
# "Discharge at 2 C until 2.8 V",
# ),
# (
# "Charge at 1 C until 4.2 V",
# "Hold at 4.2 V until C/20",
# "Rest for 30 minutes",
# "Discharge at 3 C until 2.8 V",
# ),
(
"Charge at 1 C until 4.2 V",
"Hold at 4.2 V until C/20",
"Rest for 30 minutes",
"Discharge at 2 C until 2.8 V",
),
(
"Charge at 1 C until 4.2 V",
"Hold at 4.2 V until C/20",
"Rest for 30 minutes",
"Discharge at 3 C until 2.8 V",
),
]
)
sim = pb.Simulation(model, experiment=experiment)
Expand All @@ -56,6 +59,9 @@
"X-averaged negative electrode porosity",
"Negative electrode SEI interfacial current density [A.m-2]",
"X-averaged total negative electrode SEI thickness [m]",
"Loss of lithium to negative electrode SEI [mol]",
[
"Total lithium lost [mol]",
"Loss of lithium to negative electrode SEI [mol]",
],
]
)
2 changes: 1 addition & 1 deletion examples/scripts/experimental_protocols/cccv.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
model = pybamm.lithium_ion.DFN()

sim = pybamm.Simulation(
model, experiment=experiment, solver=pybamm.CasadiSolver("safe")
model, experiment=experiment, solver=pybamm.CasadiSolver("fast with events")
)
sim.solve()

Expand Down
10 changes: 10 additions & 0 deletions pybamm/CITATIONS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@
doi = {10.1149/1945-7111/aba5d1},
}

@article{Mohtat2019,
title={Towards better estimability of electrode-specific state of health: Decoding the cell expansion},
author={Mohtat, Peyman and Lee, Suhak and Siegel, Jason B and Stefanopoulou, Anna G},
journal={Journal of Power Sources},
volume={427},
pages={101--111},
year={2019},
publisher={Elsevier}
}

@article{Malengier2018,
year = {2018},
month = {feb},
Expand Down
2 changes: 1 addition & 1 deletion pybamm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def version(formatted=False):
#
# Solver classes
#
from .solvers.solution import Solution
from .solvers.solution import Solution, make_cycle_solution
from .solvers.processed_variable import ProcessedVariable
from .solvers.processed_symbolic_variable import ProcessedSymbolicVariable
from .solvers.base_solver import BaseSolver
Expand Down
49 changes: 45 additions & 4 deletions pybamm/experiments/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class Experiment:
period : string, optional
Period (1/frequency) at which to record outputs. Default is 1 minute. Can be
overwritten by individual operating conditions.
termination : list, optional
List of conditions under which to terminate the experiment. Default is None.
use_simulation_setup_type : str
Whether to use the "new" (default) or "old" simulation set-up type. "new" is
faster at simulating individual steps but has higher set-up overhead
Expand All @@ -61,6 +63,7 @@ def __init__(
operating_conditions,
parameters=None,
period="1 minute",
termination=None,
use_simulation_setup_type="new",
drive_cycles={},
):
Expand Down Expand Up @@ -105,6 +108,7 @@ def __init__(
else:
raise TypeError("experimental parameters should be a dictionary")

self.termination = self.read_termination(termination)
self.use_simulation_setup_type = use_simulation_setup_type

def __str__(self):
Expand Down Expand Up @@ -181,8 +185,9 @@ def read_string(self, cond, drive_cycles):
# e.g. for 3 hours
idx = cond_list.index("for")
end_time = self.convert_time_to_seconds(cond_list[idx + 1 :])
ext_drive_cycle = self.extend_drive_cycle(drive_cycles[cond_list[1]],
end_time)
ext_drive_cycle = self.extend_drive_cycle(
drive_cycles[cond_list[1]], end_time
)
# Drive cycle as numpy array
dc_data = ext_drive_cycle
# Find the type of drive cycle ("A", "V", or "W")
Expand Down Expand Up @@ -244,8 +249,9 @@ def extend_drive_cycle(self, drive_cycle, end_time):
while loop_end_time <= end_time:
# Extend the drive cycle until the drive cycle time
# becomes greater than specified end time
temp_time.append(np.append(temp_time[i - 1],
temp_time[0] + temp_time[i - 1][-1] + 1))
temp_time.append(
np.append(temp_time[i - 1], temp_time[0] + temp_time[i - 1][-1] + 1)
)
loop_end_time = temp_time[i][-1]
i += 1
time = temp_time[-1]
Expand Down Expand Up @@ -363,3 +369,38 @@ def convert_time_to_seconds(self, time_and_units):
)
)
return time_in_seconds

def read_termination(self, termination):
"""
Read the termination reason. If this condition is hit, the experiment will stop.
"""
if termination is None:
return {}
elif isinstance(termination, str):
termination = [termination]

termination_dict = {}
for term in termination:
term_list = term.split()
if term_list[-1] == "capacity":
end_discharge = "".join(term_list[:-1])
if end_discharge.endswith("%"):
end_discharge_percent = end_discharge.split("%")[0]
termination_dict["capacity"] = (float(end_discharge_percent), "%")
elif end_discharge.endswith("Ah"):
end_discharge_Ah = end_discharge.split("Ah")[0]
termination_dict["capacity"] = (float(end_discharge_Ah), "Ah")
elif end_discharge.endswith("A.h"):
end_discharge_Ah = end_discharge.split("A.h")[0]
termination_dict["capacity"] = (float(end_discharge_Ah), "Ah")
else:
raise ValueError(
"Capacity termination must be given in the form "
"'80%', '4Ah', or '4A.h'"
)
else:
raise ValueError(
"Only capacity can be provided as a termination reason, "
"e.g. '80% capacity' or '4 Ah capacity'"
)
return termination_dict
Loading

0 comments on commit fe6960c

Please sign in to comment.