{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "expmkveO04pw" }, "source": [ "## Pouch Cell Model Parameter Identification\n", "\n", "In this notebook, we present the single particle model with a two dimensional current collector. This is achieved via the potential-pair models introduced in Marquis et al. [[1]](https://doi.org/10.1149/1945-7111/abbce4) as implemented in PyBaMM. At a high-level this is accomplished as a potential-pair model which is resolved across the discretised spatial locations.\n", "\n", "### Setting up the Environment\n", "\n", "Before we begin, we need to ensure that we have all the necessary tools. We will install PyBOP and upgrade dependencies:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "X87NUGPW04py", "outputId": "0d785b07-7cff-4aeb-e60a-4ff5a669afbf" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/Users/engs2510/Documents/Git/Second_PyBOP/.nox/notebooks-overwrite/bin/python3: No module named pip\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "/Users/engs2510/Documents/Git/Second_PyBOP/.nox/notebooks-overwrite/bin/python3: No module named pip\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages." ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "%pip install --upgrade pip ipywidgets -q\n", "%pip install pybop -q" ] }, { "cell_type": "markdown", "metadata": { "id": "jAvD5fk104p0" }, "source": [ "### Importing Libraries\n", "\n", "With the environment set up, we can now import PyBOP alongside other libraries we will need:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "SQdt4brD04p1" }, "outputs": [], "source": [ "import numpy as np\n", "\n", "import pybop\n", "\n", "go = pybop.plot.PlotlyManager().go\n", "pybop.plot.PlotlyManager().pio.renderers.default = \"notebook_connected\"" ] }, { "cell_type": "markdown", "metadata": { "id": "5XU-dMtU04p2" }, "source": [ "## Generating Synthetic Data\n", "\n", "To demonstrate parameter estimation, we first need some data. We will generate synthetic data using a forward model, which requires defining a parameter set and the model itself.\n", "\n", "### Defining Parameters and Model\n", "\n", "We start by creating an example parameter set and then instantiate the single-particle model (SPM):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "parameter_set = pybop.ParameterSet.pybamm(\"Marquis2019\")\n", "parameter_set.update(\n", " {\n", " \"Negative electrode active material volume fraction\": 0.495,\n", " \"Positive electrode active material volume fraction\": 0.612,\n", " }\n", ")\n", "model = pybop.lithium_ion.SPM(\n", " parameter_set=parameter_set,\n", " options={\"current collector\": \"potential pair\", \"dimensionality\": 2},\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Updating the Spatial Grid\n", "\n", "Next, we update the number of spatial locations to solve the potential-pair model," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model.var_pts[\"y\"] = 5\n", "model.var_pts[\"z\"] = 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulating the Forward Model\n", "\n", "We can then simulate the model using the `predict` method, with a default constant current to generate voltage data." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "sBasxv8U04p3" }, "outputs": [], "source": [ "t_eval = np.arange(0, 900, 3)\n", "values = model.predict(t_eval=t_eval)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding Noise to Voltage Data\n", "\n", "To make the parameter estimation more realistic, we add Gaussian noise to the data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sigma = 0.001\n", "corrupt_values = values[\"Voltage [V]\"].data + np.random.normal(0, sigma, len(t_eval))" ] }, { "cell_type": "markdown", "metadata": { "id": "X8-tubYY04p_" }, "source": [ "## Identifying the Parameters" ] }, { "cell_type": "markdown", "metadata": { "id": "PQqhvSZN04p_" }, "source": [ "We will now set up the parameter estimation process by defining the datasets for optimisation and selecting the model parameters we wish to estimate." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating a Dataset\n", "\n", "The dataset for optimisation is composed of time, current, and the noisy voltage data:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "zuvGHWID04p_" }, "outputs": [], "source": [ "dataset = pybop.Dataset(\n", " {\n", " \"Time [s]\": t_eval,\n", " \"Current function [A]\": values[\"Current [A]\"].data,\n", " \"Voltage [V]\": corrupt_values,\n", " }\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "ffS3CF_704qA" }, "source": [ "### Defining Parameters to Estimate\n", "\n", "We select the parameters for estimation and set up their prior distributions and bounds:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WPCybXIJ04qA" }, "outputs": [], "source": [ "parameters = pybop.Parameters(\n", " pybop.Parameter(\n", " \"Negative electrode active material volume fraction\",\n", " prior=pybop.Gaussian(0.7, 0.05),\n", " bounds=[0.45, 0.9],\n", " ),\n", " pybop.Parameter(\n", " \"Positive electrode active material volume fraction\",\n", " prior=pybop.Gaussian(0.58, 0.05),\n", " bounds=[0.5, 0.8],\n", " ),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For plotting purposes, we want additional variables to be stored in the problem class. These are defined as," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "additional_variables = [\n", " \"Negative current collector potential [V]\",\n", " \"Positive current collector potential [V]\",\n", "]" ] }, { "cell_type": "markdown", "metadata": { "id": "n4OHa-aF04qA" }, "source": [ "### Setting up the Optimisation Problem\n", "\n", "With the datasets and parameters defined, we can set up the optimisation problem, its cost function, and the optimiser." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "etMzRtx404qA" }, "outputs": [], "source": [ "problem = pybop.FittingProblem(\n", " model, parameters, dataset, additional_variables=additional_variables\n", ")\n", "cost = pybop.SumSquaredError(problem)\n", "optim = pybop.CMAES(cost, max_iterations=30)" ] }, { "cell_type": "markdown", "metadata": { "id": "caprp-bV04qB" }, "source": [ "### Running the Optimisation\n", "\n", "We proceed to run the CMA-ES optimisation algorithm to estimate the parameters:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-9OVt0EQ04qB" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Halt: Maximum number of iterations (30) reached.\n", "OptimisationResult:\n", " Initial parameters: [0.65919975 0.65030567]\n", " Optimised parameters: [0.49949096 0.60907043]\n", " Final cost: 0.0002845276080247215\n", " Optimisation time: 36.19517993927002 seconds\n", " Number of iterations: 30\n", " SciPy result available: No\n" ] } ], "source": [ "results = optim.run()" ] }, { "cell_type": "markdown", "metadata": { "id": "-4pZsDmS04qC" }, "source": [ "### Viewing the Estimated Parameters\n", "\n", "After the optimisation, we can examine the estimated parameter values:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Hgz8SV4i04qC", "outputId": "e1e42ae7-5075-4c47-dd68-1b22ecc170f6" }, "outputs": [ { "data": { "text/plain": [ "array([0.49949096, 0.60907043])" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results.x" ] }, { "cell_type": "markdown", "metadata": { "id": "KxKURtH704qC" }, "source": [ "## Plotting and Visualisation\n", "\n", "PyBOP provides various plotting utilities to visualise the results of the optimisation." ] }, { "cell_type": "markdown", "metadata": { "id": "-cWCOiqR04qC" }, "source": [ "### Comparing System Response\n", "\n", "We can quickly plot the system's response using the estimated parameters compared to the target:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 467 }, "id": "tJUJ80Ve04qD", "outputId": "855fbaa2-1e09-4935-eb1a-8caf7f99eb75" }, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "