From 4a47032e732673bc0d41e3aa3134cc325abc65dc Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Mon, 15 Aug 2022 16:01:36 +0100 Subject: [PATCH 01/10] Added lipf6_OKane2022 electrolyte parameters --- .../models/coupled-degradation.ipynb | 504 ++++++++++++++++++ .../electrolytes/lipf6_OKane2022/README.md | 7 + .../electrolytes/lipf6_OKane2022/__init__.py | 0 .../electrolyte_conductivity_Nyman2008.py | 38 ++ .../electrolyte_diffusivity_Nyman2008.py | 36 ++ .../lipf6_OKane2022/parameters.csv | 10 + .../graphite_OKane2022/README.md | 2 +- pybamm/parameters/parameter_sets.py | 2 +- 8 files changed, 597 insertions(+), 2 deletions(-) create mode 100644 examples/notebooks/models/coupled-degradation.ipynb create mode 100644 pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/README.md create mode 100644 pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/__init__.py create mode 100644 pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py create mode 100644 pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py create mode 100644 pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv diff --git a/examples/notebooks/models/coupled-degradation.ipynb b/examples/notebooks/models/coupled-degradation.ipynb new file mode 100644 index 0000000000..d498d9b0a8 --- /dev/null +++ b/examples/notebooks/models/coupled-degradation.ipynb @@ -0,0 +1,504 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "regional-bedroom", + "metadata": {}, + "source": [ + "# Coupled degradation in PyBaMM" + ] + }, + { + "cell_type": "markdown", + "id": "quantitative-radar", + "metadata": {}, + "source": [ + "This notebook is a guide for how to run many degradation mechanisms at once, implementing the degradation of model of O'Kane et al. (2022)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "novel-spectacular", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install pybamm -q # install PyBaMM if it is not installed\n", + "import pybamm\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "mounted-seven", + "metadata": {}, + "source": [ + "## Simulating long experiments" + ] + }, + { + "cell_type": "markdown", + "id": "chronic-consensus", + "metadata": {}, + "source": [ + "In the interest of simplicity and running time, we consider a SPM with SEI effects leading to linear degradation, with parameter values chosen so that the capacity fades by 20% in just a few cycles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "limiting-making", + "metadata": {}, + "outputs": [], + "source": [ + "parameter_values = pybamm.ParameterValues(\"Mohtat2020\")\n", + "parameter_values.update({\"SEI kinetic rate constant [m.s-1]\": 1e-14})\n", + "spm = pybamm.lithium_ion.SPM({\"SEI\": \"ec reaction limited\"})" + ] + }, + { + "cell_type": "markdown", + "id": "compact-teddy", + "metadata": {}, + "source": [ + "Using the \"Electrode SOH\" (eSOH) model, we initialize the concentration in each electrode at 100% State of Charge" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "photographic-sussex", + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate stoichiometries at 100% SOC\n", + "\n", + "param = spm.param\n", + "esoh_solver = pybamm.lithium_ion.ElectrodeSOHSolver(parameter_values, param)\n", + "\n", + "Vmin = 3.0\n", + "Vmax = 4.2\n", + "Cn = parameter_values.evaluate(param.n.cap_init)\n", + "Cp = parameter_values.evaluate(param.p.cap_init)\n", + "n_Li_init = parameter_values.evaluate(param.n_Li_particles_init)\n", + "\n", + "inputs={ \"V_min\": Vmin, \"V_max\": Vmax, \"C_n\": Cn, \"C_p\": Cp, \"n_Li\": n_Li_init}\n", + "esoh_sol = esoh_solver.solve(inputs)\n", + "\n", + "print(f\"Initial negative electrode SOC: {esoh_sol['x_100'].data[0]:.3f}\")\n", + "print(f\"Initial positive electrode SOC: {esoh_sol['y_100'].data[0]:.3f}\")\n", + "\n", + "# Update parameter values with initial conditions\n", + "c_n_max = parameter_values.evaluate(param.n.c_max)\n", + "c_p_max = parameter_values.evaluate(param.p.c_max)\n", + "parameter_values.update(\n", + " {\n", + " \"Initial concentration in negative electrode [mol.m-3]\": esoh_sol[\"x_100\"].data[0] * c_n_max,\n", + " \"Initial concentration in positive electrode [mol.m-3]\": esoh_sol[\"y_100\"].data[0] * c_p_max,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "focused-substitute", + "metadata": {}, + "source": [ + "We can now simulate a single CCCV cycle using the `Experiment` class (see [this notebook](https://github.com/pybamm-team/PyBaMM/blob/develop/examples/notebooks/Getting%20Started/Tutorial%205%20-%20Run%20experiments.ipynb) for more details)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "religious-primary", + "metadata": {}, + "outputs": [], + "source": [ + "pybamm.set_logging_level(\"NOTICE\")\n", + "\n", + "experiment = pybamm.Experiment([\n", + " (f\"Discharge at 1C until {Vmin}V\",\n", + " \"Rest for 1 hour\",\n", + " f\"Charge at 1C until {Vmax}V\", \n", + " f\"Hold at {Vmax}V until C/50\"\n", + " )\n", + "])\n", + "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", + "sol = sim.solve()" + ] + }, + { + "cell_type": "markdown", + "id": "heavy-crisis", + "metadata": {}, + "source": [ + "Alternatively, we can simulate many CCCV cycles. Here we simulate either 100 cycles or until the capacity is 80% of the initial capacity, whichever is first. The capacity is calculated by the eSOH model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "stupid-abortion", + "metadata": { + "tags": [ + "outputPrepend" + ] + }, + "outputs": [], + "source": [ + "experiment = pybamm.Experiment([\n", + " (f\"Discharge at 1C until {Vmin}V\",\n", + " \"Rest for 1 hour\",\n", + " f\"Charge at 1C until {Vmax}V\", \n", + " f\"Hold at {Vmax}V until C/50\")\n", + "] * 500,\n", + "termination=\"80% capacity\"\n", + ")\n", + "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", + "sol = sim.solve()" + ] + }, + { + "cell_type": "markdown", + "id": "cloudy-lover", + "metadata": {}, + "source": [ + "### Summary variables" + ] + }, + { + "cell_type": "markdown", + "id": "shared-practitioner", + "metadata": {}, + "source": [ + "We can plot standard variables like the current and voltage, but it isn't very instructive on these timescales" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "personalized-oracle", + "metadata": {}, + "outputs": [], + "source": [ + "sol.plot([\"Current [A]\", \"Terminal voltage [V]\"])" + ] + }, + { + "cell_type": "markdown", + "id": "intense-princeton", + "metadata": {}, + "source": [ + "Instead, we plot \"summary variables\", which show how the battery degrades over time by various metrics. Some of the variables also have \"Change in ...\", which is how much that variable changes over each cycle. This can be achieved by using `plot_summary_variables` method of pybamm, which can also be used to compare \"summary variables\" extracted from 2 or more solutions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "right-skiing", + "metadata": {}, + "outputs": [], + "source": [ + "sorted(sol.summary_variables.keys())" + ] + }, + { + "cell_type": "markdown", + "id": "approximate-error", + "metadata": {}, + "source": [ + "The \"summary variables\" associated with a particular model can also be accessed as a list (which can then be edited) -" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "romance-roulette", + "metadata": {}, + "outputs": [], + "source": [ + "spm.summary_variables" + ] + }, + { + "cell_type": "markdown", + "id": "given-telephone", + "metadata": {}, + "source": [ + "Here the only degradation mechanism is one that causes loss of lithium, so we don't see loss of active material" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "postal-butter", + "metadata": {}, + "outputs": [], + "source": [ + "pybamm.plot_summary_variables(sol)" + ] + }, + { + "cell_type": "markdown", + "id": "french-substance", + "metadata": {}, + "source": [ + "To suggest additional summary variables, open an issue!" + ] + }, + { + "cell_type": "markdown", + "id": "accepting-canada", + "metadata": {}, + "source": [ + "## Choosing which cycles to save" + ] + }, + { + "cell_type": "markdown", + "id": "employed-plate", + "metadata": {}, + "source": [ + "If the simulation contains thousands of cycles, saving each cycle in RAM might not be possible. To get around this, we can use `save_at_cycles`. If this is an integer `n`, every nth cycle is saved. If this is a list, all the cycles in the list are saved.\n", + "The first cycle is always saved." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "polished-trout", + "metadata": { + "tags": [ + "outputPrepend" + ] + }, + "outputs": [], + "source": [ + "# With integer\n", + "sol_int = sim.solve(save_at_cycles=5)\n", + "# With list\n", + "sol_list = sim.solve(save_at_cycles=[30,45,55])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "severe-yorkshire", + "metadata": {}, + "outputs": [], + "source": [ + "sol_int.cycles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "unavailable-fetish", + "metadata": {}, + "outputs": [], + "source": [ + "sol_list.cycles" + ] + }, + { + "cell_type": "markdown", + "id": "guilty-nylon", + "metadata": {}, + "source": [ + "For the cycles that are saved, you can plot as usual (note off-by-1 indexing)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "architectural-signal", + "metadata": {}, + "outputs": [], + "source": [ + "sol_list.cycles[44].plot([\"Current [A]\",\"Terminal voltage [V]\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "played-hundred", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1,2,figsize=(10,5))\n", + "for cycle in sol_int.cycles:\n", + " if cycle is not None:\n", + " t = cycle[\"Time [h]\"].data - cycle[\"Time [h]\"].data[0]\n", + " ax[0].plot(t, cycle[\"Current [A]\"].data)\n", + " ax[0].set_xlabel(\"Time [h]\")\n", + " ax[0].set_title(\"Current [A]\")\n", + " ax[1].plot(t, cycle[\"Terminal voltage [V]\"].data)\n", + " ax[1].set_xlabel(\"Time [h]\")\n", + " ax[1].set_title(\"Terminal voltage [V]\")" + ] + }, + { + "cell_type": "markdown", + "id": "considered-rescue", + "metadata": {}, + "source": [ + "All summary variables are always available for every cycle, since these are much less memory-intensive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "multiple-culture", + "metadata": {}, + "outputs": [], + "source": [ + "pybamm.plot_summary_variables(sol_list)" + ] + }, + { + "cell_type": "markdown", + "id": "convinced-winter", + "metadata": {}, + "source": [ + "## Starting solution" + ] + }, + { + "cell_type": "markdown", + "id": "unauthorized-fundamental", + "metadata": {}, + "source": [ + "A simulation can be performed iteratively by using the `starting_solution` feature. For example, we first solve for 10 cycles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "posted-plastic", + "metadata": {}, + "outputs": [], + "source": [ + "experiment = pybamm.Experiment([\n", + " (f\"Discharge at 1C until {Vmin}V\",\n", + " \"Rest for 1 hour\",\n", + " f\"Charge at 1C until {Vmax}V\", \n", + " f\"Hold at {Vmax}V until C/50\")\n", + "] * 10,\n", + "termination=\"80% capacity\"\n", + ")\n", + "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", + "sol = sim.solve()" + ] + }, + { + "cell_type": "markdown", + "id": "weird-darkness", + "metadata": {}, + "source": [ + "If we give `sol` as the starting solution this will then solve for the next 10 cycles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "moderate-pipeline", + "metadata": {}, + "outputs": [], + "source": [ + "sol2 = sim.solve(starting_solution=sol)" + ] + }, + { + "cell_type": "markdown", + "id": "leading-passport", + "metadata": {}, + "source": [ + "We have now simulated 20 cycles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "higher-covering", + "metadata": {}, + "outputs": [], + "source": [ + "len(sol2.cycles)" + ] + }, + { + "cell_type": "markdown", + "id": "plastic-framework", + "metadata": {}, + "source": [ + "## References" + ] + }, + { + "cell_type": "markdown", + "id": "drawn-fifty", + "metadata": {}, + "source": [ + "The relevant papers for this notebook are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "driven-sensitivity", + "metadata": {}, + "outputs": [], + "source": [ + "pybamm.print_citations()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.10" + }, + "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 + }, + "vscode": { + "interpreter": { + "hash": "612adcc456652826e82b485a1edaef831aa6d5abc680d008e93d513dd8724f14" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/README.md b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/README.md new file mode 100644 index 0000000000..afbce52778 --- /dev/null +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/README.md @@ -0,0 +1,7 @@ +# LiPF6 electrolyte parameters + +Parameters for a LiPF6 electrolyte, from the paper + +> Simon O'Kane, Weilong Ai, Ganesh Madabattula, Diego Alonso-Alvarez, Robert Timms, Valentin Sulzer, Jacqueline Edge, Billy Wu, Gregory Offer, and Monica Marinescu. ["Lithium-ion battery degradation: how to model it."](https://pubs.rsc.org/en/content/articlelanding/2022/cp/d2cp00417h) Physical Chemistry: Chemical Physics 24 (2022): 7909-7922 + +and references therein. diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/__init__.py b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py new file mode 100644 index 0000000000..7de27501ba --- /dev/null +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py @@ -0,0 +1,38 @@ +from pybamm import exp, constants + + +def electrolyte_conductivity_Nyman2008(c_e, T): + """ + Conductivity of LiPF6 in EC:EMC (3:7) as a function of ion concentration. The data + comes from [1]. + + References + ---------- + .. [1] A. Nyman, M. Behm, and G. Lindbergh, "Electrochemical characterisation and + modelling of the mass transport phenomena in LiPF6-EC-EMC electrolyte," + Electrochim. Acta, vol. 53, no. 22, pp. 6356–6365, 2008. + + Parameters + ---------- + c_e: :class:`pybamm.Symbol` + Dimensional electrolyte concentration + T: :class:`pybamm.Symbol` + Dimensional temperature + + Returns + ------- + :class:`pybamm.Symbol` + Solid diffusivity + """ + + sigma_e = ( + 0.1297 * (c_e / 1000) ** 3 - 2.51 * (c_e / 1000) ** 1.5 + 3.329 * (c_e / 1000) + ) + + # Nyman et al. (2008) does not provide temperature dependence + # So use temperature dependence from Ecker et al. (2015) instead + + E_sigma_e = 17000 + arrhenius = exp(E_sigma_e / constants.R * (1 / 298.15 - 1 / T)) + + return sigma_e * arrhenius diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py new file mode 100644 index 0000000000..eb57d2450a --- /dev/null +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py @@ -0,0 +1,36 @@ +from pybamm import exp, constants + + +def electrolyte_diffusivity_Nyman2008(c_e, T): + """ + Diffusivity of LiPF6 in EC:EMC (3:7) as a function of ion concentration. The data + comes from [1] + + References + ---------- + .. [1] A. Nyman, M. Behm, and G. Lindbergh, "Electrochemical characterisation and + modelling of the mass transport phenomena in LiPF6-EC-EMC electrolyte," + Electrochim. Acta, vol. 53, no. 22, pp. 6356–6365, 2008. + + Parameters + ---------- + c_e: :class:`pybamm.Symbol` + Dimensional electrolyte concentration + T: :class:`pybamm.Symbol` + Dimensional temperature + + Returns + ------- + :class:`pybamm.Symbol` + Solid diffusivity + """ + + D_c_e = 8.794e-11 * (c_e / 1000) ** 2 - 3.972e-10 * (c_e / 1000) + 4.862e-10 + + # Nyman et al. (2008) does not provide temperature dependence + # So use temperature dependence from Ecker et al. (2015) instead + + E_D_c_e = 17000 + arrhenius = exp(E_D_c_e / constants.R * (1 / 298.15 - 1 / T)) + + return D_c_e * arrhenius diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv new file mode 100644 index 0000000000..2d177004a3 --- /dev/null +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv @@ -0,0 +1,10 @@ +Name [units],Value,Reference,Notes +# Empty rows and rows starting with ‘#’ will be ignored,,, +,,, +# Electrolyte properties,,, +Typical electrolyte concentration [mol.m-3],1000,Chen 2020, +Initial concentration in electrolyte [mol.m-3],1000,Chen 2020, +Cation transference number,0.2594,Chen 2020, +1 + dlnf/dlnc,1,, +Electrolyte diffusivity [m2.s-1],[function]electrolyte_diffusivity_Nyman2008,Nyman 2008, +Electrolyte conductivity [S.m-1],[function]electrolyte_conductivity_Nyman2008,Nyman 2008, diff --git a/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md b/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md index d8f6b21220..6f5c3deb66 100644 --- a/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md +++ b/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md @@ -1,6 +1,6 @@ # LG M50 Graphite anode parameters -Parameters for a LG M50 graphite anode, from the paper +Parameters for a LG M50 graphite negative electrode, from the paper > Simon O'Kane, Weilong Ai, Ganesh Madabattula, Diego Alonso-Alvarez, Robert Timms, Valentin Sulzer, Jacqueline Edge, Billy Wu, Gregory Offer, and Monica Marinescu. ["Lithium-ion battery degradation: how to model it."](https://pubs.rsc.org/en/content/articlelanding/2022/cp/d2cp00417h) Physical Chemistry: Chemical Physics 24 (2022): 7909-7922 diff --git a/pybamm/parameters/parameter_sets.py b/pybamm/parameters/parameter_sets.py index 1bfb5d353b..f880ad7b64 100644 --- a/pybamm/parameters/parameter_sets.py +++ b/pybamm/parameters/parameter_sets.py @@ -239,7 +239,7 @@ "negative electrode": "graphite_OKane2022", "separator": "separator_Chen2020", "positive electrode": "nmc_OKane2022", - "electrolyte": "lipf6_Nyman2008", + "electrolyte": "lipf6_OKane2022", "experiment": "1C_discharge_from_full_Chen2020", "sei": "OKane2022", "lithium plating": "okane2022_Li_plating", From 7a84067f5ad69500eb3435f7f5f419568600fe1a Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Wed, 17 Aug 2022 17:49:27 +0100 Subject: [PATCH 02/10] Define new cumulative variables throughput capacity [A.h] and throughput energy [W.h] --- pybamm/models/standard_variables.py | 4 +++ .../external_circuit/base_external_circuit.py | 34 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pybamm/models/standard_variables.py b/pybamm/models/standard_variables.py index 00ba41e8f9..389002710b 100644 --- a/pybamm/models/standard_variables.py +++ b/pybamm/models/standard_variables.py @@ -11,6 +11,10 @@ def __init__(self): self.Q_Ah = pybamm.Variable("Discharge capacity [A.h]") self.Q_Wh = pybamm.Variable("Discharge energy [W.h]") + # Throughput capacity and energy (cumulative) + self.Qt_Ah = pybamm.Variable("Throughput capacity [A.h]") + self.Qt_Wh = pybamm.Variable("Throughput energy [W.h]") + # Electrolyte concentration self.c_e_n = pybamm.Variable( "Negative electrolyte concentration", diff --git a/pybamm/models/submodels/external_circuit/base_external_circuit.py b/pybamm/models/submodels/external_circuit/base_external_circuit.py index e3fe43f0f9..86769e192c 100644 --- a/pybamm/models/submodels/external_circuit/base_external_circuit.py +++ b/pybamm/models/submodels/external_circuit/base_external_circuit.py @@ -12,29 +12,45 @@ def __init__(self, param, options): def get_fundamental_variables(self): Q_Ah = pybamm.standard_variables.Q_Ah - variables = {"Discharge capacity [A.h]": Q_Ah} + Qt_Ah = pybamm.standard_variables.Qt_Ah + variables = { + "Discharge capacity [A.h]": Q_Ah, + "Throughput capacity [A.h]": Qt_Ah, + } if self.options["calculate discharge energy"] == "true": Q_Wh = pybamm.standard_variables.Q_Wh - variables.update({"Discharge energy [W.h]": Q_Wh}) + Qt_Wh = pybamm.standard_variables.Qt_Wh + variables.update({ + "Discharge energy [W.h]": Q_Wh, + "Throughput energy [W.h]": Qt_Wh, + }) return variables def set_initial_conditions(self, variables): Q_Ah = variables["Discharge capacity [A.h]"] + Qt_Ah = variables["Throughput capacity [A.h]"] self.initial_conditions[Q_Ah] = pybamm.Scalar(0) + self.initial_conditions[Qt_Ah] = pybamm.Scalar(0) if self.options["calculate discharge energy"] == "true": Q_Wh = variables["Discharge energy [W.h]"] + Qt_Wh = variables["Throughput energy [W.h]"] self.initial_conditions[Q_Wh] = pybamm.Scalar(0) + self.initial_conditions[Qt_Wh] = pybamm.Scalar(0) def set_rhs(self, variables): - # ODE for discharge capacity + # ODEs for discharge capacity and throughput capacity Q_Ah = variables["Discharge capacity [A.h]"] + Qt_Ah = variables["Throughput capacity [A.h]"] I = variables["Current [A]"] self.rhs[Q_Ah] = I * self.param.timescale / 3600 + self.rhs[Qt_Ah] = abs(I) * self.param.timescale / 3600 if self.options["calculate discharge energy"] == "true": Q_Wh = variables["Discharge energy [W.h]"] + Qt_Wh = variables["Throughput energy [W.h]"] V = variables["Terminal voltage [V]"] self.rhs[Q_Wh] = I * V * self.param.timescale / 3600 + self.rhs[Qt_Wh] = abs(I * V) * self.param.timescale / 3600 class LeadingOrderBaseModel(BaseModel): @@ -45,8 +61,16 @@ def __init__(self, param, options): def get_fundamental_variables(self): Q_Ah = pybamm.Variable("Leading-order discharge capacity [A.h]") - variables = {"Discharge capacity [A.h]": Q_Ah} + Qt_Ah = pybamm.Variable("Leading-order throughput capacity [A.h]") + variables = { + "Discharge capacity [A.h]": Q_Ah, + "Throughput capacity [A.h]": Qt_Ah, + } if self.options["calculate discharge energy"] == "true": Q_Wh = pybamm.Variable("Leading-order discharge energy [W.h]") - variables.update({"Discharge energy [W.h]": Q_Wh}) + Qt_Wh = pybamm.Variable("Leading-order throughput energy [W.h]") + variables.update({ + "Discharge energy [W.h]": Q_Wh, + "Throughput energy [W.h]": Qt_Wh, + }) return variables From b2838d1904e88dbdea059958b746340d0f163ec5 Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Thu, 18 Aug 2022 14:19:12 +0100 Subject: [PATCH 03/10] New cumulative variables added to list of summary variables --- .../full_battery_models/lithium_ion/base_lithium_ion_model.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py b/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py index bb6b97a8e6..b624465df0 100644 --- a/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py +++ b/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py @@ -185,6 +185,10 @@ def set_summary_variables(self): Sets the default summary variables. """ summary_variables = [ + "Time [s]", + "Time [h]", + "Throughput capacity [A.h]", + "Throughput energy [A.h]", "Positive electrode capacity [A.h]", # LAM, LLI "Loss of active material in positive electrode [%]", From 9f898e15fa79b59af3734f6fb3c83f5c1bdba6d1 Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Thu, 18 Aug 2022 15:04:11 +0100 Subject: [PATCH 04/10] Defined discharge energy and throughput energy to be zero if 'calculate discharge energy' is false --- .../lithium_ion/base_lithium_ion_model.py | 2 +- .../submodels/external_circuit/base_external_circuit.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py b/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py index b624465df0..225e20ce3c 100644 --- a/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py +++ b/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py @@ -188,7 +188,7 @@ def set_summary_variables(self): "Time [s]", "Time [h]", "Throughput capacity [A.h]", - "Throughput energy [A.h]", + "Throughput energy [W.h]", "Positive electrode capacity [A.h]", # LAM, LLI "Loss of active material in positive electrode [%]", diff --git a/pybamm/models/submodels/external_circuit/base_external_circuit.py b/pybamm/models/submodels/external_circuit/base_external_circuit.py index 86769e192c..d8921f5e94 100644 --- a/pybamm/models/submodels/external_circuit/base_external_circuit.py +++ b/pybamm/models/submodels/external_circuit/base_external_circuit.py @@ -24,6 +24,11 @@ def get_fundamental_variables(self): "Discharge energy [W.h]": Q_Wh, "Throughput energy [W.h]": Qt_Wh, }) + else: + variables.update({ + "Discharge energy [W.h]": pybamm.Scalar(0), + "Throughput energy [W.h]": pybamm.Scalar(0), + }) return variables def set_initial_conditions(self, variables): From 7aac18d61124732dce4db99a0da3bd81e149af35 Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Thu, 18 Aug 2022 15:16:56 +0100 Subject: [PATCH 05/10] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd1cd08704..9c195dd63c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # [Unreleased](https://github.com/pybamm-team/PyBaMM/) +## Features + +- Addew new cumulative variables `Throughput capacity [A.h]` and `Throughput energy [W.h]` to standard variables and summary variables, to assist with degradation studies. `Time [s]` and `Time [h]` also added to summary variables. ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) + ## Bug fixes - Added new parameter `Ratio of lithium moles to SEI moles` (short name z_sei) to fix a bug where this number was incorrectly hardcoded to 1. ([#2222](https://github.com/pybamm-team/PyBaMM/pull/2222)) From 0bb60c3c265ac35da8dc63c22eb2ddbc6693e6d8 Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Thu, 18 Aug 2022 16:07:36 +0100 Subject: [PATCH 06/10] Removed coupled_degradation.py due to bugs; corrected provenance for OKane2022 parameters --- .../models/coupled-degradation.ipynb | 504 ------------------ ...olyte_conductivity_Nyman2008_arrhenius.py} | 7 +- ...rolyte_diffusivity_Nyman2008_arrhenius.py} | 7 +- .../lipf6_OKane2022/parameters.csv | 4 +- .../okane2022_Li_plating/README.md | 4 +- .../graphite_OKane2022/README.md | 2 +- .../lithium_ion/seis/OKane2022/README.md | 13 +- 7 files changed, 21 insertions(+), 520 deletions(-) delete mode 100644 examples/notebooks/models/coupled-degradation.ipynb rename pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/{electrolyte_conductivity_Nyman2008.py => electrolyte_conductivity_Nyman2008_arrhenius.py} (74%) rename pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/{electrolyte_diffusivity_Nyman2008.py => electrolyte_diffusivity_Nyman2008_arrhenius.py} (73%) diff --git a/examples/notebooks/models/coupled-degradation.ipynb b/examples/notebooks/models/coupled-degradation.ipynb deleted file mode 100644 index d498d9b0a8..0000000000 --- a/examples/notebooks/models/coupled-degradation.ipynb +++ /dev/null @@ -1,504 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "regional-bedroom", - "metadata": {}, - "source": [ - "# Coupled degradation in PyBaMM" - ] - }, - { - "cell_type": "markdown", - "id": "quantitative-radar", - "metadata": {}, - "source": [ - "This notebook is a guide for how to run many degradation mechanisms at once, implementing the degradation of model of O'Kane et al. (2022)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "novel-spectacular", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install pybamm -q # install PyBaMM if it is not installed\n", - "import pybamm\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "markdown", - "id": "mounted-seven", - "metadata": {}, - "source": [ - "## Simulating long experiments" - ] - }, - { - "cell_type": "markdown", - "id": "chronic-consensus", - "metadata": {}, - "source": [ - "In the interest of simplicity and running time, we consider a SPM with SEI effects leading to linear degradation, with parameter values chosen so that the capacity fades by 20% in just a few cycles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "limiting-making", - "metadata": {}, - "outputs": [], - "source": [ - "parameter_values = pybamm.ParameterValues(\"Mohtat2020\")\n", - "parameter_values.update({\"SEI kinetic rate constant [m.s-1]\": 1e-14})\n", - "spm = pybamm.lithium_ion.SPM({\"SEI\": \"ec reaction limited\"})" - ] - }, - { - "cell_type": "markdown", - "id": "compact-teddy", - "metadata": {}, - "source": [ - "Using the \"Electrode SOH\" (eSOH) model, we initialize the concentration in each electrode at 100% State of Charge" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "photographic-sussex", - "metadata": {}, - "outputs": [], - "source": [ - "# Calculate stoichiometries at 100% SOC\n", - "\n", - "param = spm.param\n", - "esoh_solver = pybamm.lithium_ion.ElectrodeSOHSolver(parameter_values, param)\n", - "\n", - "Vmin = 3.0\n", - "Vmax = 4.2\n", - "Cn = parameter_values.evaluate(param.n.cap_init)\n", - "Cp = parameter_values.evaluate(param.p.cap_init)\n", - "n_Li_init = parameter_values.evaluate(param.n_Li_particles_init)\n", - "\n", - "inputs={ \"V_min\": Vmin, \"V_max\": Vmax, \"C_n\": Cn, \"C_p\": Cp, \"n_Li\": n_Li_init}\n", - "esoh_sol = esoh_solver.solve(inputs)\n", - "\n", - "print(f\"Initial negative electrode SOC: {esoh_sol['x_100'].data[0]:.3f}\")\n", - "print(f\"Initial positive electrode SOC: {esoh_sol['y_100'].data[0]:.3f}\")\n", - "\n", - "# Update parameter values with initial conditions\n", - "c_n_max = parameter_values.evaluate(param.n.c_max)\n", - "c_p_max = parameter_values.evaluate(param.p.c_max)\n", - "parameter_values.update(\n", - " {\n", - " \"Initial concentration in negative electrode [mol.m-3]\": esoh_sol[\"x_100\"].data[0] * c_n_max,\n", - " \"Initial concentration in positive electrode [mol.m-3]\": esoh_sol[\"y_100\"].data[0] * c_p_max,\n", - " }\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "focused-substitute", - "metadata": {}, - "source": [ - "We can now simulate a single CCCV cycle using the `Experiment` class (see [this notebook](https://github.com/pybamm-team/PyBaMM/blob/develop/examples/notebooks/Getting%20Started/Tutorial%205%20-%20Run%20experiments.ipynb) for more details)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "religious-primary", - "metadata": {}, - "outputs": [], - "source": [ - "pybamm.set_logging_level(\"NOTICE\")\n", - "\n", - "experiment = pybamm.Experiment([\n", - " (f\"Discharge at 1C until {Vmin}V\",\n", - " \"Rest for 1 hour\",\n", - " f\"Charge at 1C until {Vmax}V\", \n", - " f\"Hold at {Vmax}V until C/50\"\n", - " )\n", - "])\n", - "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", - "sol = sim.solve()" - ] - }, - { - "cell_type": "markdown", - "id": "heavy-crisis", - "metadata": {}, - "source": [ - "Alternatively, we can simulate many CCCV cycles. Here we simulate either 100 cycles or until the capacity is 80% of the initial capacity, whichever is first. The capacity is calculated by the eSOH model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "stupid-abortion", - "metadata": { - "tags": [ - "outputPrepend" - ] - }, - "outputs": [], - "source": [ - "experiment = pybamm.Experiment([\n", - " (f\"Discharge at 1C until {Vmin}V\",\n", - " \"Rest for 1 hour\",\n", - " f\"Charge at 1C until {Vmax}V\", \n", - " f\"Hold at {Vmax}V until C/50\")\n", - "] * 500,\n", - "termination=\"80% capacity\"\n", - ")\n", - "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", - "sol = sim.solve()" - ] - }, - { - "cell_type": "markdown", - "id": "cloudy-lover", - "metadata": {}, - "source": [ - "### Summary variables" - ] - }, - { - "cell_type": "markdown", - "id": "shared-practitioner", - "metadata": {}, - "source": [ - "We can plot standard variables like the current and voltage, but it isn't very instructive on these timescales" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "personalized-oracle", - "metadata": {}, - "outputs": [], - "source": [ - "sol.plot([\"Current [A]\", \"Terminal voltage [V]\"])" - ] - }, - { - "cell_type": "markdown", - "id": "intense-princeton", - "metadata": {}, - "source": [ - "Instead, we plot \"summary variables\", which show how the battery degrades over time by various metrics. Some of the variables also have \"Change in ...\", which is how much that variable changes over each cycle. This can be achieved by using `plot_summary_variables` method of pybamm, which can also be used to compare \"summary variables\" extracted from 2 or more solutions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "right-skiing", - "metadata": {}, - "outputs": [], - "source": [ - "sorted(sol.summary_variables.keys())" - ] - }, - { - "cell_type": "markdown", - "id": "approximate-error", - "metadata": {}, - "source": [ - "The \"summary variables\" associated with a particular model can also be accessed as a list (which can then be edited) -" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "romance-roulette", - "metadata": {}, - "outputs": [], - "source": [ - "spm.summary_variables" - ] - }, - { - "cell_type": "markdown", - "id": "given-telephone", - "metadata": {}, - "source": [ - "Here the only degradation mechanism is one that causes loss of lithium, so we don't see loss of active material" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "postal-butter", - "metadata": {}, - "outputs": [], - "source": [ - "pybamm.plot_summary_variables(sol)" - ] - }, - { - "cell_type": "markdown", - "id": "french-substance", - "metadata": {}, - "source": [ - "To suggest additional summary variables, open an issue!" - ] - }, - { - "cell_type": "markdown", - "id": "accepting-canada", - "metadata": {}, - "source": [ - "## Choosing which cycles to save" - ] - }, - { - "cell_type": "markdown", - "id": "employed-plate", - "metadata": {}, - "source": [ - "If the simulation contains thousands of cycles, saving each cycle in RAM might not be possible. To get around this, we can use `save_at_cycles`. If this is an integer `n`, every nth cycle is saved. If this is a list, all the cycles in the list are saved.\n", - "The first cycle is always saved." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "polished-trout", - "metadata": { - "tags": [ - "outputPrepend" - ] - }, - "outputs": [], - "source": [ - "# With integer\n", - "sol_int = sim.solve(save_at_cycles=5)\n", - "# With list\n", - "sol_list = sim.solve(save_at_cycles=[30,45,55])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "severe-yorkshire", - "metadata": {}, - "outputs": [], - "source": [ - "sol_int.cycles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "unavailable-fetish", - "metadata": {}, - "outputs": [], - "source": [ - "sol_list.cycles" - ] - }, - { - "cell_type": "markdown", - "id": "guilty-nylon", - "metadata": {}, - "source": [ - "For the cycles that are saved, you can plot as usual (note off-by-1 indexing)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "architectural-signal", - "metadata": {}, - "outputs": [], - "source": [ - "sol_list.cycles[44].plot([\"Current [A]\",\"Terminal voltage [V]\"])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "played-hundred", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(1,2,figsize=(10,5))\n", - "for cycle in sol_int.cycles:\n", - " if cycle is not None:\n", - " t = cycle[\"Time [h]\"].data - cycle[\"Time [h]\"].data[0]\n", - " ax[0].plot(t, cycle[\"Current [A]\"].data)\n", - " ax[0].set_xlabel(\"Time [h]\")\n", - " ax[0].set_title(\"Current [A]\")\n", - " ax[1].plot(t, cycle[\"Terminal voltage [V]\"].data)\n", - " ax[1].set_xlabel(\"Time [h]\")\n", - " ax[1].set_title(\"Terminal voltage [V]\")" - ] - }, - { - "cell_type": "markdown", - "id": "considered-rescue", - "metadata": {}, - "source": [ - "All summary variables are always available for every cycle, since these are much less memory-intensive" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "multiple-culture", - "metadata": {}, - "outputs": [], - "source": [ - "pybamm.plot_summary_variables(sol_list)" - ] - }, - { - "cell_type": "markdown", - "id": "convinced-winter", - "metadata": {}, - "source": [ - "## Starting solution" - ] - }, - { - "cell_type": "markdown", - "id": "unauthorized-fundamental", - "metadata": {}, - "source": [ - "A simulation can be performed iteratively by using the `starting_solution` feature. For example, we first solve for 10 cycles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "posted-plastic", - "metadata": {}, - "outputs": [], - "source": [ - "experiment = pybamm.Experiment([\n", - " (f\"Discharge at 1C until {Vmin}V\",\n", - " \"Rest for 1 hour\",\n", - " f\"Charge at 1C until {Vmax}V\", \n", - " f\"Hold at {Vmax}V until C/50\")\n", - "] * 10,\n", - "termination=\"80% capacity\"\n", - ")\n", - "sim = pybamm.Simulation(spm, experiment=experiment, parameter_values=parameter_values)\n", - "sol = sim.solve()" - ] - }, - { - "cell_type": "markdown", - "id": "weird-darkness", - "metadata": {}, - "source": [ - "If we give `sol` as the starting solution this will then solve for the next 10 cycles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "moderate-pipeline", - "metadata": {}, - "outputs": [], - "source": [ - "sol2 = sim.solve(starting_solution=sol)" - ] - }, - { - "cell_type": "markdown", - "id": "leading-passport", - "metadata": {}, - "source": [ - "We have now simulated 20 cycles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "higher-covering", - "metadata": {}, - "outputs": [], - "source": [ - "len(sol2.cycles)" - ] - }, - { - "cell_type": "markdown", - "id": "plastic-framework", - "metadata": {}, - "source": [ - "## References" - ] - }, - { - "cell_type": "markdown", - "id": "drawn-fifty", - "metadata": {}, - "source": [ - "The relevant papers for this notebook are:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "driven-sensitivity", - "metadata": {}, - "outputs": [], - "source": [ - "pybamm.print_citations()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.8.10" - }, - "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 - }, - "vscode": { - "interpreter": { - "hash": "612adcc456652826e82b485a1edaef831aa6d5abc680d008e93d513dd8724f14" - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008_arrhenius.py similarity index 74% rename from pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py rename to pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008_arrhenius.py index 7de27501ba..69d14debea 100644 --- a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008.py +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_conductivity_Nyman2008_arrhenius.py @@ -1,16 +1,19 @@ from pybamm import exp, constants -def electrolyte_conductivity_Nyman2008(c_e, T): +def electrolyte_conductivity_Nyman2008_arrhenius(c_e, T): """ Conductivity of LiPF6 in EC:EMC (3:7) as a function of ion concentration. The data - comes from [1]. + comes from [1], with Arrhenius temperature dependence added from [2]. References ---------- .. [1] A. Nyman, M. Behm, and G. Lindbergh, "Electrochemical characterisation and modelling of the mass transport phenomena in LiPF6-EC-EMC electrolyte," Electrochim. Acta, vol. 53, no. 22, pp. 6356–6365, 2008. + .. [2] Ecker, Madeleine, et al. "Parameterization of a physico-chemical model of + a lithium-ion battery i. determination of parameters." Journal of the + Electrochemical Society 162.9 (2015): A1836-A1848. Parameters ---------- diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008_arrhenius.py similarity index 73% rename from pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py rename to pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008_arrhenius.py index eb57d2450a..c01bc66320 100644 --- a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008.py +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/electrolyte_diffusivity_Nyman2008_arrhenius.py @@ -1,16 +1,19 @@ from pybamm import exp, constants -def electrolyte_diffusivity_Nyman2008(c_e, T): +def electrolyte_diffusivity_Nyman2008_arrhenius(c_e, T): """ Diffusivity of LiPF6 in EC:EMC (3:7) as a function of ion concentration. The data - comes from [1] + comes from [1], with Arrhenius temperature dependence added from [2]. References ---------- .. [1] A. Nyman, M. Behm, and G. Lindbergh, "Electrochemical characterisation and modelling of the mass transport phenomena in LiPF6-EC-EMC electrolyte," Electrochim. Acta, vol. 53, no. 22, pp. 6356–6365, 2008. + .. [2] Ecker, Madeleine, et al. "Parameterization of a physico-chemical model of + a lithium-ion battery i. determination of parameters." Journal of the + Electrochemical Society 162.9 (2015): A1836-A1848. Parameters ---------- diff --git a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv index 2d177004a3..97a438f793 100644 --- a/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv +++ b/pybamm/input/parameters/lithium_ion/electrolytes/lipf6_OKane2022/parameters.csv @@ -6,5 +6,5 @@ Typical electrolyte concentration [mol.m-3],1000,Chen 2020, Initial concentration in electrolyte [mol.m-3],1000,Chen 2020, Cation transference number,0.2594,Chen 2020, 1 + dlnf/dlnc,1,, -Electrolyte diffusivity [m2.s-1],[function]electrolyte_diffusivity_Nyman2008,Nyman 2008, -Electrolyte conductivity [S.m-1],[function]electrolyte_conductivity_Nyman2008,Nyman 2008, +Electrolyte diffusivity [m2.s-1],[function]electrolyte_diffusivity_Nyman2008_arrhenius,OKane 2022, +Electrolyte conductivity [S.m-1],[function]electrolyte_conductivity_Nyman2008_arrhenius,OKane 2022, diff --git a/pybamm/input/parameters/lithium_ion/lithium_platings/okane2022_Li_plating/README.md b/pybamm/input/parameters/lithium_ion/lithium_platings/okane2022_Li_plating/README.md index b167223ec7..82095310dc 100644 --- a/pybamm/input/parameters/lithium_ion/lithium_platings/okane2022_Li_plating/README.md +++ b/pybamm/input/parameters/lithium_ion/lithium_platings/okane2022_Li_plating/README.md @@ -2,6 +2,8 @@ Some example parameters for lithium plating from the paper: -> O’Kane, S. E. J., Ai, W., Madabattula, G., Alonso-Alvarez, D., Timms, R, Sulzer, V., Edge, J. S., Wu, B., Offer, G. J., & Marinescu, M. (2022) Lithium-ion battery degradation: how to model it. Physical Chemistry: Chemical Physics, accepted. +> Simon O'Kane, Weilong Ai, Ganesh Madabattula, Diego Alonso-Alvarez, Robert Timms, Valentin Sulzer, Jacqueline Edge, Billy Wu, Gregory Offer, and Monica Marinescu. ["Lithium-ion battery degradation: how to model it."](https://pubs.rsc.org/en/content/articlelanding/2022/cp/d2cp00417h) Physical Chemistry: Chemical Physics 24 (2022): 7909-7922 + +and references therein. Note: this parameter set does not claim to be representative of the true parameter values. These are merely the parameter values that were used in the referenced papers. diff --git a/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md b/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md index 6f5c3deb66..96ef76cc35 100644 --- a/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md +++ b/pybamm/input/parameters/lithium_ion/negative_electrodes/graphite_OKane2022/README.md @@ -1,6 +1,6 @@ # LG M50 Graphite anode parameters -Parameters for a LG M50 graphite negative electrode, from the paper +Parameters for an LG M50 graphite negative electrode, from the paper > Simon O'Kane, Weilong Ai, Ganesh Madabattula, Diego Alonso-Alvarez, Robert Timms, Valentin Sulzer, Jacqueline Edge, Billy Wu, Gregory Offer, and Monica Marinescu. ["Lithium-ion battery degradation: how to model it."](https://pubs.rsc.org/en/content/articlelanding/2022/cp/d2cp00417h) Physical Chemistry: Chemical Physics 24 (2022): 7909-7922 diff --git a/pybamm/input/parameters/lithium_ion/seis/OKane2022/README.md b/pybamm/input/parameters/lithium_ion/seis/OKane2022/README.md index 7e4df9e041..8ea18c45d7 100644 --- a/pybamm/input/parameters/lithium_ion/seis/OKane2022/README.md +++ b/pybamm/input/parameters/lithium_ion/seis/OKane2022/README.md @@ -1,12 +1,9 @@ # SEI parameters -Some example parameters for SEI growth from the papers: +Parameters for SEI growth from the paper -> Ramadass, P., Haran, B., Gomadam, P. M., White, R., & Popov, B. N. (2004). Development of first principles capacity fade model for Li-ion cells. Journal of the Electrochemical Society, 151(2), A196-A203. -> Ploehn, H. J., Ramadass, P., & White, R. E. (2004). Solvent diffusion model for aging of lithium-ion battery cells. Journal of The Electrochemical Society, 151(3), A456-A462. -> Single, F., Latz, A., & Horstmann, B. (2018). Identifying the mechanism of continued growth of the solid–electrolyte interphase. ChemSusChem, 11(12), 1950-1955. -> Safari, M., Morcrette, M., Teyssot, A., & Delacour, C. (2009). Multimodal Physics-Based Aging Model for Life Prediction of Li-Ion Batteries. Journal of The Electrochemical Society, 156(3), -> Yang, X., Leng, Y., Zhang, G., Ge, S., Wang, C. (2017). Modeling of lithium plating induced aging of lithium-ion batteries: Transition from linear to nonlinear aging. Journal of Power Sources, 360, 28-40. -> Waldmann, T., Wilka, M., Kasper, M., Fleischammer M., Wohlfahrt-Mehrens M. (2014). Temperature dependent ageing mechanisms in Lithium-ion batteris: A Post-Mortem study. Journal of Power Sources, 262, 129-135. +> Simon O'Kane, Weilong Ai, Ganesh Madabattula, Diego Alonso-Alvarez, Robert Timms, Valentin Sulzer, Jacqueline Edge, Billy Wu, Gregory Offer, and Monica Marinescu. ["Lithium-ion battery degradation: how to model it."](https://pubs.rsc.org/en/content/articlelanding/2022/cp/d2cp00417h) Physical Chemistry: Chemical Physics 24 (2022): 7909-7922 -Note: this parameter set does not claim to be representative of the true parameter values. Instead these are parameter values that were used to fit SEI models to observed experimental data in the referenced papers. +and references therein. + +Note: this parameter set does not claim to be representative of the true parameter values. These are merely the parameter values that were used in the referenced papers. From 6e9d0e697b8b6f1ee47753d25fa8c9bafe83d93b Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Thu, 18 Aug 2022 16:09:33 +0100 Subject: [PATCH 07/10] changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c195dd63c..e1b4ffe71e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## Features -- Addew new cumulative variables `Throughput capacity [A.h]` and `Throughput energy [W.h]` to standard variables and summary variables, to assist with degradation studies. `Time [s]` and `Time [h]` also added to summary variables. ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) +- Added new cumulative variables `Throughput capacity [A.h]` and `Throughput energy [W.h]` to standard variables and summary variables, to assist with degradation studies. `Time [s]` and `Time [h]` also added to summary variables. ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) +- Added `lipf6_OKane2022` electrolyte to `OKane2022` parameter set ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) ## Bug fixes From 779957d93d2871dca1acdd2a9f229c7aea1eed9e Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Fri, 19 Aug 2022 12:44:37 +0100 Subject: [PATCH 08/10] Included discharge capacity in list of variables for basic SPM --- pybamm/models/full_battery_models/lithium_ion/basic_spm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pybamm/models/full_battery_models/lithium_ion/basic_spm.py b/pybamm/models/full_battery_models/lithium_ion/basic_spm.py index 727c7e2da2..1758306474 100644 --- a/pybamm/models/full_battery_models/lithium_ion/basic_spm.py +++ b/pybamm/models/full_battery_models/lithium_ion/basic_spm.py @@ -40,6 +40,7 @@ def __init__(self, name="Single Particle Model"): ###################### # Variables that depend on time only are created without a domain Q = pybamm.Variable("Discharge capacity [A.h]") + Qt = pybamm.Variable("Throughput capacity [A.h]") # Variables that vary spatially are created with a domain c_s_n = pybamm.Variable( "X-averaged negative particle concentration", domain="negative particle" @@ -67,8 +68,10 @@ def __init__(self, name="Single Particle Model"): # The `rhs` dictionary contains differential equations, with the key being the # variable in the d/dt self.rhs[Q] = I * param.timescale / 3600 + self.rhs[Qt] = abs(I) * param.timescale / 3600 # Initial conditions must be provided for the ODEs self.initial_conditions[Q] = pybamm.Scalar(0) + self.initial_conditions[Qt] = pybamm.Scalar(0) ###################### # Particles @@ -159,6 +162,7 @@ def __init__(self, name="Single Particle Model"): # into a vector of the right shape, for multiplying with other vectors self.variables = { "Discharge capacity [A.h]": Q, + "Throughput capacity [A.h]": Qt, "Negative particle surface concentration": pybamm.PrimaryBroadcast( c_s_surf_n, "negative electrode" ), From 7cb756e5a5d1043c7993a2c5ab669b7fbfa3532f Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Fri, 19 Aug 2022 15:41:30 +0100 Subject: [PATCH 09/10] Throughput variables only calculated if 'calculate discharge energy' is set to true --- CHANGELOG.md | 2 +- .../full_battery_models/base_battery_model.py | 5 ++-- .../lithium_ion/basic_spm.py | 4 --- .../external_circuit/base_external_circuit.py | 26 +++++++++---------- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1b4ffe71e..8a0ab89a7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Features -- Added new cumulative variables `Throughput capacity [A.h]` and `Throughput energy [W.h]` to standard variables and summary variables, to assist with degradation studies. `Time [s]` and `Time [h]` also added to summary variables. ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) +- Added new cumulative variables `Throughput capacity [A.h]` and `Throughput energy [W.h]` to standard variables and summary variables, to assist with degradation studies. Throughput variables are only calculated if `calculate discharge energy` is set to `true`. `Time [s]` and `Time [h]` also added to summary variables. ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) - Added `lipf6_OKane2022` electrolyte to `OKane2022` parameter set ([#2249](https://github.com/pybamm-team/PyBaMM/pull/2249)) ## Bug fixes diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index ab32932132..66bc9429c7 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -21,8 +21,9 @@ class BatteryModelOptions(pybamm.FuzzyDict): option for the negative and positive electrodes. * "calculate discharge energy": str - Whether to calculate the discharge energy. Must be one of "true" or - "false". "false" is the default, since calculating the discharge + Whether to calculate the discharge energy, throughput energy and + throughput capacity in addition to discharge capacity. Must be one of + "true" or "false". "false" is the default, since calculating discharge energy can be computationally expensive for simple models like SPM. * "cell geometry" : str Sets the geometry of the cell. Can be "pouch" (default) or diff --git a/pybamm/models/full_battery_models/lithium_ion/basic_spm.py b/pybamm/models/full_battery_models/lithium_ion/basic_spm.py index 1758306474..727c7e2da2 100644 --- a/pybamm/models/full_battery_models/lithium_ion/basic_spm.py +++ b/pybamm/models/full_battery_models/lithium_ion/basic_spm.py @@ -40,7 +40,6 @@ def __init__(self, name="Single Particle Model"): ###################### # Variables that depend on time only are created without a domain Q = pybamm.Variable("Discharge capacity [A.h]") - Qt = pybamm.Variable("Throughput capacity [A.h]") # Variables that vary spatially are created with a domain c_s_n = pybamm.Variable( "X-averaged negative particle concentration", domain="negative particle" @@ -68,10 +67,8 @@ def __init__(self, name="Single Particle Model"): # The `rhs` dictionary contains differential equations, with the key being the # variable in the d/dt self.rhs[Q] = I * param.timescale / 3600 - self.rhs[Qt] = abs(I) * param.timescale / 3600 # Initial conditions must be provided for the ODEs self.initial_conditions[Q] = pybamm.Scalar(0) - self.initial_conditions[Qt] = pybamm.Scalar(0) ###################### # Particles @@ -162,7 +159,6 @@ def __init__(self, name="Single Particle Model"): # into a vector of the right shape, for multiplying with other vectors self.variables = { "Discharge capacity [A.h]": Q, - "Throughput capacity [A.h]": Qt, "Negative particle surface concentration": pybamm.PrimaryBroadcast( c_s_surf_n, "negative electrode" ), diff --git a/pybamm/models/submodels/external_circuit/base_external_circuit.py b/pybamm/models/submodels/external_circuit/base_external_circuit.py index d8921f5e94..c757d3dbce 100644 --- a/pybamm/models/submodels/external_circuit/base_external_circuit.py +++ b/pybamm/models/submodels/external_circuit/base_external_circuit.py @@ -12,50 +12,50 @@ def __init__(self, param, options): def get_fundamental_variables(self): Q_Ah = pybamm.standard_variables.Q_Ah - Qt_Ah = pybamm.standard_variables.Qt_Ah - variables = { - "Discharge capacity [A.h]": Q_Ah, - "Throughput capacity [A.h]": Qt_Ah, - } + + variables = {"Discharge capacity [A.h]": Q_Ah} if self.options["calculate discharge energy"] == "true": Q_Wh = pybamm.standard_variables.Q_Wh Qt_Wh = pybamm.standard_variables.Qt_Wh + Qt_Ah = pybamm.standard_variables.Qt_Ah variables.update({ "Discharge energy [W.h]": Q_Wh, "Throughput energy [W.h]": Qt_Wh, + "Throughput capacity [A.h]": Qt_Ah, }) else: variables.update({ "Discharge energy [W.h]": pybamm.Scalar(0), "Throughput energy [W.h]": pybamm.Scalar(0), + "Throughput capacity [A.h]": pybamm.Scalar(0), }) return variables def set_initial_conditions(self, variables): Q_Ah = variables["Discharge capacity [A.h]"] - Qt_Ah = variables["Throughput capacity [A.h]"] self.initial_conditions[Q_Ah] = pybamm.Scalar(0) - self.initial_conditions[Qt_Ah] = pybamm.Scalar(0) if self.options["calculate discharge energy"] == "true": Q_Wh = variables["Discharge energy [W.h]"] Qt_Wh = variables["Throughput energy [W.h]"] + Qt_Ah = variables["Throughput capacity [A.h]"] self.initial_conditions[Q_Wh] = pybamm.Scalar(0) self.initial_conditions[Qt_Wh] = pybamm.Scalar(0) + self.initial_conditions[Qt_Ah] = pybamm.Scalar(0) def set_rhs(self, variables): # ODEs for discharge capacity and throughput capacity Q_Ah = variables["Discharge capacity [A.h]"] - Qt_Ah = variables["Throughput capacity [A.h]"] I = variables["Current [A]"] self.rhs[Q_Ah] = I * self.param.timescale / 3600 - self.rhs[Qt_Ah] = abs(I) * self.param.timescale / 3600 if self.options["calculate discharge energy"] == "true": Q_Wh = variables["Discharge energy [W.h]"] Qt_Wh = variables["Throughput energy [W.h]"] + Qt_Ah = variables["Throughput capacity [A.h]"] V = variables["Terminal voltage [V]"] self.rhs[Q_Wh] = I * V * self.param.timescale / 3600 self.rhs[Qt_Wh] = abs(I * V) * self.param.timescale / 3600 + self.rhs[Qt_Ah] = abs(I) * self.param.timescale / 3600 class LeadingOrderBaseModel(BaseModel): @@ -66,16 +66,14 @@ def __init__(self, param, options): def get_fundamental_variables(self): Q_Ah = pybamm.Variable("Leading-order discharge capacity [A.h]") - Qt_Ah = pybamm.Variable("Leading-order throughput capacity [A.h]") - variables = { - "Discharge capacity [A.h]": Q_Ah, - "Throughput capacity [A.h]": Qt_Ah, - } + variables = {"Discharge capacity [A.h]": Q_Ah} if self.options["calculate discharge energy"] == "true": Q_Wh = pybamm.Variable("Leading-order discharge energy [W.h]") Qt_Wh = pybamm.Variable("Leading-order throughput energy [W.h]") + Qt_Ah = pybamm.Variable("Leading-order throughput capacity [A.h]") variables.update({ "Discharge energy [W.h]": Q_Wh, "Throughput energy [W.h]": Qt_Wh, + "Throughput capacity [A.h]": Qt_Ah, }) return variables From 7a1f46b39679fcf83881bd8bd296c0bf4ddc2002 Mon Sep 17 00:00:00 2001 From: DrSOKane Date: Fri, 19 Aug 2022 15:56:40 +0100 Subject: [PATCH 10/10] flake8 --- .../models/submodels/external_circuit/base_external_circuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybamm/models/submodels/external_circuit/base_external_circuit.py b/pybamm/models/submodels/external_circuit/base_external_circuit.py index c757d3dbce..a4ee78d11a 100644 --- a/pybamm/models/submodels/external_circuit/base_external_circuit.py +++ b/pybamm/models/submodels/external_circuit/base_external_circuit.py @@ -12,7 +12,7 @@ def __init__(self, param, options): def get_fundamental_variables(self): Q_Ah = pybamm.standard_variables.Q_Ah - + variables = {"Discharge capacity [A.h]": Q_Ah} if self.options["calculate discharge energy"] == "true": Q_Wh = pybamm.standard_variables.Q_Wh