From ae2be71ee4a02c277d65e3f8446a996f99ba8a98 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 28 Aug 2024 19:33:14 +0100 Subject: [PATCH 1/3] draft graded electrodes notebook --- .../notebooks/models/graded-electrodes.ipynb | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 docs/source/examples/notebooks/models/graded-electrodes.ipynb diff --git a/docs/source/examples/notebooks/models/graded-electrodes.ipynb b/docs/source/examples/notebooks/models/graded-electrodes.ipynb new file mode 100644 index 0000000000..a984a1d2aa --- /dev/null +++ b/docs/source/examples/notebooks/models/graded-electrodes.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulating graded electrodes" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Note: you may need to restart the kernel to use updated packages.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + } + ], + "source": [ + "%pip install \"pybamm[plot,cite]\" -q # install PyBaMM if it is not installed\n", + "import pybamm" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "model = pybamm.lithium_ion.DFN()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "parameter_values = pybamm.ParameterValues(\"Chen2020\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "L_n = parameter_values[\"Negative electrode thickness [m]\"]\n", + "\n", + "\n", + "def eps_n(x):\n", + " return 0.2 + 0.1 * (x / L_n)\n", + "\n", + "\n", + "parameter_values[\"Negative electrode porosity\"] = eps_n\n", + "parameter_values[\"Positive electrode porosity\"] = eps_n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "sim = pybamm.Simulation(model, parameter_values=parameter_values)\n", + "sol = sim.solve([0, 3600])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d622f8692d31487ca98b0e1aea3b270e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(FloatSlider(value=0.0, description='t', max=3556.5751296553094, step=35.565751296553096)…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sol.plot()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "05a4a84b560e4e15ad8b9357364a9052", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(FloatSlider(value=0.0, description='t', max=3556.5751296553094, step=35.565751296553096)…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sol.plot(\n", + " output_variables=[\"Negative electrode porosity\", \"Positive electrode porosity\"]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From d0c9ded1efb4acca9cd5f701ed28a5f84b2d9f4e Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Sat, 7 Sep 2024 12:32:48 -0400 Subject: [PATCH 2/3] add graded electrodes example --- .../notebooks/models/graded-electrodes.ipynb | 154 ++++++++++++++---- 1 file changed, 126 insertions(+), 28 deletions(-) diff --git a/docs/source/examples/notebooks/models/graded-electrodes.ipynb b/docs/source/examples/notebooks/models/graded-electrodes.ipynb index a984a1d2aa..adb316ba2d 100644 --- a/docs/source/examples/notebooks/models/graded-electrodes.ipynb +++ b/docs/source/examples/notebooks/models/graded-electrodes.ipynb @@ -4,7 +4,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Simulating graded electrodes" + "# Simulating graded electrodes\n", + "\n", + "In this notebook we explore how to simulate the effect of graded electrodes in the performance of a battery. Graded electrodes have a composition that varies along the thickness of the electrode, typically active material volume fraction and particle size. This variation can be used to improve the performance of the battery, for example, by increasing the power density.\n", + "\n", + "As usual, we start by importing PyBaMM." ] }, { @@ -33,64 +37,108 @@ ] }, { - "cell_type": "code", - "execution_count": 2, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "model = pybamm.lithium_ion.DFN()" + "We use the DFN model for the simulations and the Chen2020 parameter set. Note that we will need to modify the default Chen2020 parameter set to describe graded electrodes." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ + "model = pybamm.lithium_ion.DFN()\n", "parameter_values = pybamm.ParameterValues(\"Chen2020\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will vary the porosity in both electrodes and we will try three different scenarios: constant porosity, one where lower porosity occurs near the separator and one where lower porosity occurs near the current collector. All other parameters are kept constant. The varying porosity is defined to be linear centered around the default value and with a variation of $\\pm$ 10%.\n", + "\n", + "We define the varying porosities and store them in a list so we can loop over when solving the model." + ] + }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "L_n = parameter_values[\"Negative electrode thickness [m]\"]\n", + "L_s = parameter_values[\"Separator thickness [m]\"]\n", + "L_p = parameter_values[\"Positive electrode thickness [m]\"]\n", "\n", + "eps_n_0 = parameter_values[\"Negative electrode porosity\"]\n", + "eps_p_0 = parameter_values[\"Positive electrode porosity\"]\n", "\n", - "def eps_n(x):\n", - " return 0.2 + 0.1 * (x / L_n)\n", + "eps_ns = [\n", + " eps_n_0,\n", + " lambda x: eps_n_0 * (1.1 - 0.2 * (x / L_n)),\n", + " lambda x: eps_n_0 * (0.9 + 0.2 * (x / L_n)),\n", + "]\n", "\n", - "\n", - "parameter_values[\"Negative electrode porosity\"] = eps_n\n", - "parameter_values[\"Positive electrode porosity\"] = eps_n" + "eps_ps = [\n", + " eps_p_0,\n", + " lambda x: eps_p_0 * (0.9 - 0.2 / L_p * (L_n + L_s) + 0.2 * (x / L_p)),\n", + " lambda x: eps_p_0 * (1.1 + 0.2 / L_p * (L_n + L_s) - 0.2 * (x / L_p)),\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the distance through the electrode is computed from the negative electrode, so parameter need to be defined accordingly. Next, we can just solve the models for the various parameter sets. We apply a fairly high C-rate to see the effect of the graded electrodes on the discharge capacity." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "sim = pybamm.Simulation(model, parameter_values=parameter_values)\n", - "sol = sim.solve([0, 3600])" + "solutions = []\n", + "\n", + "experiment = pybamm.Experiment([\"Discharge at 3C until 2.5 V\"])\n", + "\n", + "for eps_n, eps_p in zip(eps_ns, eps_ps):\n", + " parameter_values[\"Negative electrode porosity\"] = eps_n\n", + " parameter_values[\"Positive electrode porosity\"] = eps_p\n", + " sim = pybamm.Simulation(\n", + " model,\n", + " parameter_values=parameter_values,\n", + " experiment=experiment,\n", + " solver=pybamm.IDAKLUSolver(),\n", + " )\n", + " sol = sim.solve()\n", + " solutions.append(sol)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And plot the results:" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d622f8692d31487ca98b0e1aea3b270e", + "model_id": "99f847ca09da40cba550dd02dd8281a2", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "interactive(children=(FloatSlider(value=0.0, description='t', max=3556.5751296553094, step=35.565751296553096)…" + "interactive(children=(FloatSlider(value=0.0, description='t', max=673.9136958613059, step=6.7391369586130585),…" ] }, "metadata": {}, @@ -99,32 +147,48 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "sol.plot()" + "pybamm.dynamic_plot(\n", + " solutions,\n", + " labels=[\n", + " \"Constant porosity\",\n", + " \"Low porosity at separator\",\n", + " \"High porosity at separator\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We observe that, even though the average porosity is the same for the three cases the discharge capacity is much higher with the graded electrode where porosity is higher near the separator. This is because the higher porosity near the separator facilitates the ion transport and the better utilisation of the active material.\n", + "\n", + "As a sanity check we can plot the porosity profiles for the three cases and see they match what we intended." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "05a4a84b560e4e15ad8b9357364a9052", + "model_id": "829b68c6b3e04e0ebe5537daabec2278", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "interactive(children=(FloatSlider(value=0.0, description='t', max=3556.5751296553094, step=35.565751296553096)…" + "interactive(children=(FloatSlider(value=0.0, description='t', max=673.9136958613059, step=6.7391369586130585),…" ] }, "metadata": {}, @@ -133,20 +197,54 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "sol.plot(\n", - " output_variables=[\"Negative electrode porosity\", \"Positive electrode porosity\"]\n", + "pybamm.dynamic_plot(\n", + " solutions,\n", + " output_variables=[\"Negative electrode porosity\", \"Positive electrode porosity\"],\n", + " labels=[\n", + " \"Constant porosity\",\n", + " \"Low porosity at separator\",\n", + " \"High porosity at separator\",\n", + " ],\n", ")" ] }, + { + "cell_type": "code", + "execution_count": 9, + "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] Von DAG Bruggeman. Berechnung verschiedener physikalischer konstanten von heterogenen substanzen. i. dielektrizitätskonstanten und leitfähigkeiten der mischkörper aus isotropen substanzen. Annalen der physik, 416(7):636–664, 1935.\n", + "[3] Chang-Hui Chen, Ferran Brosa Planella, Kieran O'Regan, Dominika Gastol, W. Dhammika Widanage, and Emma Kendrick. Development of Experimental Techniques for Parameterization of Multi-scale Lithium-ion Battery Models. Journal of The Electrochemical Society, 167(8):080534, 2020. doi:10.1149/1945-7111/ab9050.\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] Alan C. Hindmarsh. The PVODE and IDA algorithms. Technical Report, Lawrence Livermore National Lab., CA (US), 2000. doi:10.2172/802599.\n", + "[7] Alan C. Hindmarsh, Peter N. Brown, Keith E. Grant, Steven L. Lee, Radu Serban, Dan E. Shumaker, and Carol S. Woodward. SUNDIALS: Suite of nonlinear and differential/algebraic equation solvers. ACM Transactions on Mathematical Software (TOMS), 31(3):363–396, 2005. doi:10.1145/1089014.1089020.\n", + "[8] 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", + "[9] 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", + "[10] 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", + "[11] 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()" + ] + }, { "cell_type": "code", "execution_count": null, From f28e6873389b1ca6d8fed18b9f8201c15e4f4c0c Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Sat, 7 Sep 2024 12:38:40 -0400 Subject: [PATCH 3/3] add graded electrode notebook to index --- docs/source/examples/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/examples/index.rst b/docs/source/examples/index.rst index a5958b327b..dab8247ddf 100644 --- a/docs/source/examples/index.rst +++ b/docs/source/examples/index.rst @@ -54,6 +54,7 @@ The notebooks are organised into subfolders, and can be viewed in the galleries notebooks/models/DFN-with-particle-size-distributions.ipynb notebooks/models/DFN.ipynb notebooks/models/electrode-state-of-health.ipynb + notebooks/models/graded-electrodes.ipynb notebooks/models/half-cell.ipynb notebooks/models/jelly-roll-model.ipynb notebooks/models/latexify.ipynb