diff --git a/.github/workflows/lychee_links.yaml b/.github/workflows/lychee_links.yaml
new file mode 100644
index 000000000..a5d181f94
--- /dev/null
+++ b/.github/workflows/lychee_links.yaml
@@ -0,0 +1,58 @@
+# Lychee Link Checking
+
+name: Links
+on:
+ workflow_dispatch:
+ pull_request:
+ push:
+ branches:
+ - main
+ schedule:
+ - cron: '0 6 * * 0' # Run weekly on Sundays at 06:00 UTC
+
+jobs:
+ Lychee:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Restore lychee cache
+ uses: actions/cache@v4
+ with:
+ path: .lycheecache
+ key: cache-lychee-${{ github.sha }}
+ restore-keys: cache-lychee-
+
+ - name: Set up Lychee
+ uses: lycheeverse/lychee-action@v1.10.0
+ with:
+ args: >-
+ --cache
+ --no-progress
+ --max-cache-age 2d
+ --timeout 10
+ --max-retries 5
+ --skip-missing
+ --exclude-loopback
+ --accept 200,429
+ --exclude "https://tiles.stadiamaps.com/*|https://b.tile.openstreetmap.org/*"
+ --exclude "https://cartodb-basemaps-c.global.ssl.fastly.net/*"
+ --exclude "https://events.mapbox.com/*|https://events.mapbox.cn/*|https://api.mapbox.cn/*"
+ --exclude "https://github.com/mikolalysenko/glsl-read-float/*"
+ --exclude "https://fonts.openmaptiles.org/*"
+ --exclude "https://a.tile.openstreetmap.org/*"
+ --exclude "https://cdn.plot.ly/*"
+ --exclude "https://doi.org/*"
+ --exclude-path ./CHANGELOG.md
+ --exclude-path asv.conf.json
+ --exclude-path docs/conf.py
+ './**/*.rst'
+ './**/*.md'
+ './**/*.py'
+ './**/*.ipynb'
+ './**/*.json'
+ './**/*.toml'
+ fail: true
+ jobSummary: true
+ format: markdown
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 47ef467c5..82299a924 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,7 +4,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: "v0.5.0"
+ rev: "v0.5.1"
hooks:
- id: ruff
args: [--fix, --show-fixes]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 108a48dfd..8fcf76005 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
## Features
- [#327](https://github.com/pybop-team/PyBOP/issues/327) - Adds the `WeightedCost` subclass, defines when to evaluate a problem and adds the `spm_weighted_cost` example script.
+- [#403](https://github.com/pybop-team/PyBOP/pull/403/) - Adds lychee link checking action.
## Bug Fixes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 727c5c510..110debbb2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -62,7 +62,7 @@ You now have everything you need to start making changes!
### B. Writing your code
-6. PyBOP is developed in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)), and makes heavy use of [NumPy](https://en.wikipedia.org/wiki/NumPy) (see also [NumPy for MatLab users](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html) and [Python for R users](http://blog.hackerearth.com/how-can-r-users-learn-python-for-data-science)).
+6. PyBOP is developed in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)), and makes heavy use of [NumPy](https://en.wikipedia.org/wiki/NumPy) (see also [NumPy for MatLab users](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html) and [Python for R users](https://rebeccabarter.com/blog/2023-09-11-from_r_to_python)).
7. Make sure to follow our [coding style guidelines](#coding-style-guidelines).
8. Commit your changes to your branch with [useful, descriptive commit messages](https://chris.beams.io/posts/git-commit/): Remember these are publicly visible and should still make sense a few months ahead in time. While developing, you can keep using the GitHub issue you're working on as a place for discussion. [Refer to your commits](https://stackoverflow.com/questions/8910271/how-can-i-reference-a-commit-in-an-issue-comment-on-github) when discussing specific lines of code.
9. If you want to add a dependency on another library, or re-use code you found somewhere else, have a look at [these guidelines](#dependencies-and-reusing-code).
diff --git a/README.md b/README.md
index 99f7a031e..9080dc9b6 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[![Contributors](https://img.shields.io/github/contributors/pybop-team/PyBOP)](https://github.com/pybop-team/PyBOP/graphs/contributors)
[![Last Commit](https://img.shields.io/github/last-commit/pybop-team/PyBOP/develop?color=purple)](https://github.com/pybop-team/PyBOP/commits/develop)
[![Python Versions from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fpybop-team%2FPyBOP%2Fdevelop%2Fpyproject.toml&label=Python)](https://pypi.org/project/pybop/)
- [![Forks](https://img.shields.io/github/forks/pybop-team/PyBOP?style=flat)](https://github.com/pybop-team/PyBOPe/network/members)
+ [![Forks](https://img.shields.io/github/forks/pybop-team/PyBOP?style=flat)](https://github.com/pybop-team/PyBOP/network/members)
[![Stars](https://img.shields.io/github/stars/pybop-team/PyBOP?style=flat&color=gold)](https://github.com/pybop-team/PyBOP/stargazers)
[![Codecov](https://codecov.io/gh/pybop-team/PyBOP/branch/develop/graph/badge.svg)](https://codecov.io/gh/pybop-team/PyBOP)
[![Open Issues](https://img.shields.io/github/issues/pybop-team/PyBOP)](https://github.com/pybop-team/PyBOP/issues/)
@@ -74,7 +74,7 @@ Additional script-based examples can be found in the [examples directory](https:
- [Unscented Kalman filter parameter identification of a SPM](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/spm_UKF.py)
- [Import and export parameters using Faraday's BPX format](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/BPX_spm.py)
- [Maximum a posteriori parameter identification of a SPM](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/BPX_spm.py)
-- [Gradient based parameter identification of a SPM](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/spm_adam.py)
+- [Gradient based parameter identification of a SPM](https://github.com/pybop-team/PyBOP/blob/develop/examples/scripts/spm_AdamW.py)
### Supported Methods
The table below lists the currently supported [models](https://github.com/pybop-team/PyBOP/tree/develop/pybop/models), [optimisers](https://github.com/pybop-team/PyBOP/tree/develop/pybop/optimisers), and [cost functions](https://github.com/pybop-team/PyBOP/tree/develop/pybop/costs) in PyBOP.
diff --git a/benchmarks/benchmark_model.py b/benchmarks/benchmark_model.py
index 843b03bcc..5d496215b 100644
--- a/benchmarks/benchmark_model.py
+++ b/benchmarks/benchmark_model.py
@@ -1,8 +1,7 @@
import numpy as np
import pybop
-
-from .benchmark_utils import set_random_seed
+from benchmarks.benchmark_utils import set_random_seed
class BenchmarkModel:
diff --git a/benchmarks/benchmark_optim_construction.py b/benchmarks/benchmark_optim_construction.py
index fee5f0789..75bb28b3c 100644
--- a/benchmarks/benchmark_optim_construction.py
+++ b/benchmarks/benchmark_optim_construction.py
@@ -1,8 +1,7 @@
import numpy as np
import pybop
-
-from .benchmark_utils import set_random_seed
+from benchmarks.benchmark_utils import set_random_seed
class BenchmarkOptimisationConstruction:
diff --git a/benchmarks/benchmark_parameterisation.py b/benchmarks/benchmark_parameterisation.py
index a64116a48..681502387 100644
--- a/benchmarks/benchmark_parameterisation.py
+++ b/benchmarks/benchmark_parameterisation.py
@@ -1,8 +1,7 @@
import numpy as np
import pybop
-
-from .benchmark_utils import set_random_seed
+from benchmarks.benchmark_utils import set_random_seed
class BenchmarkParameterisation:
diff --git a/benchmarks/benchmark_track_parameterisation.py b/benchmarks/benchmark_track_parameterisation.py
index 9180ffecb..a420dd3b9 100644
--- a/benchmarks/benchmark_track_parameterisation.py
+++ b/benchmarks/benchmark_track_parameterisation.py
@@ -1,8 +1,7 @@
import numpy as np
import pybop
-
-from .benchmark_utils import set_random_seed
+from benchmarks.benchmark_utils import set_random_seed
class BenchmarkTrackParameterisation:
diff --git a/docs/_extension/gallery_directive.py b/docs/_extension/gallery_directive.py
index 3579ffcd8..4ab88d996 100644
--- a/docs/_extension/gallery_directive.py
+++ b/docs/_extension/gallery_directive.py
@@ -12,7 +12,7 @@
"""
from pathlib import Path
-from typing import Any, Dict, List
+from typing import Any
from docutils import nodes
from docutils.parsers.rst import directives
@@ -68,7 +68,7 @@ class GalleryGridDirective(SphinxDirective):
"class-card": directives.unchanged,
}
- def run(self) -> List[nodes.Node]:
+ def run(self) -> list[nodes.Node]:
"""Create the gallery grid."""
if self.arguments:
# If an argument is given, assume it's a path to a YAML file
@@ -129,7 +129,7 @@ def run(self) -> List[nodes.Node]:
return [container.children[0]]
-def setup(app: Sphinx) -> Dict[str, Any]:
+def setup(app: Sphinx) -> dict[str, Any]:
"""Add custom configuration to sphinx app.
Args:
diff --git a/docs/conf.py b/docs/conf.py
index df93a8fa4..d7c54b116 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -7,11 +7,11 @@
from pathlib import Path
sys.path.append(str(Path(".").resolve()))
-from pybop._version import __version__ # noqa: E402
+from pybop._version import __version__
# -- Project information -----------------------------------------------------
project = "PyBOP"
-copyright = "2023, The PyBOP Team"
+copyright = "2023, The PyBOP Team" # noqa A001
author = "The PyBOP Team"
release = f"v{__version__}"
diff --git a/examples/notebooks/LG_M50_ECM/1-single-pulse-circuit-model.ipynb b/examples/notebooks/LG_M50_ECM/1-single-pulse-circuit-model.ipynb
index 9fd084dd6..9030596d8 100644
--- a/examples/notebooks/LG_M50_ECM/1-single-pulse-circuit-model.ipynb
+++ b/examples/notebooks/LG_M50_ECM/1-single-pulse-circuit-model.ipynb
@@ -7,7 +7,7 @@
"source": [
"## LG M50 Single Pulse Parameter Identification\n",
"\n",
- "This example presents an experimental parameter identification method for a two-RC circuit model. The data for this notebook is located within the same directory and was obtained from [[1]](https://github.com/WDWidanage/Simscape-Battery-Library/tree/main/Examples/parameterEstimation_TECMD/Data).\n",
+ "This example presents an experimental parameter identification method for a two-RC circuit model. The data for this notebook is located within the same directory and was obtained from WDWidanage/Simscape-Battery-Library [[1]](https://github.com/WDWidanage/Simscape-Battery-Library/tree/a3842b91b3ccda006bc9be5d59c8bcbd167ceef7/Examples/parameterEstimation_TECMD/Data).\n",
"\n",
"\n",
"### Setting up the Environment\n",
@@ -261,7 +261,7 @@
{
"type": "scatter",
"x": [
- 0.0,
+ 0,
0.01800000004004687,
0.12100000004284084,
0.25100000004749745,
@@ -571,7 +571,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -607,7 +607,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -631,7 +631,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -667,7 +667,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -682,7 +682,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -718,7 +718,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -745,7 +745,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -781,7 +781,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -796,7 +796,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -832,7 +832,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -977,7 +977,7 @@
},
"colorscale": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -1013,7 +1013,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
@@ -1104,7 +1104,7 @@
],
"sequential": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -1140,13 +1140,13 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
],
"sequentialminus": [
[
- 0.0,
+ 0,
"#0d0887"
],
[
@@ -1182,7 +1182,7 @@
"#fdca26"
],
[
- 1.0,
+ 1,
"#f0f921"
]
]
@@ -1888,7 +1888,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.2"
+ "version": "3.11.7"
}
},
"nbformat": 4,
diff --git a/examples/notebooks/pouch_cell_identification.ipynb b/examples/notebooks/pouch_cell_identification.ipynb
index d952e22c7..11c87993c 100644
--- a/examples/notebooks/pouch_cell_identification.ipynb
+++ b/examples/notebooks/pouch_cell_identification.ipynb
@@ -8,7 +8,7 @@
"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 [[1]](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",
+ "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",
@@ -36,58 +36,38 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: pip in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (24.0)\r\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Requirement already satisfied: ipywidgets in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (8.1.2)\r\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Requirement already satisfied: comm>=0.1.3 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (0.2.2)\r\n",
- "Requirement already satisfied: ipython>=6.1.0 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (8.23.0)\r\n",
- "Requirement already satisfied: traitlets>=4.3.1 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (5.14.2)\r\n",
- "Requirement already satisfied: widgetsnbextension~=4.0.10 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (4.0.10)\r\n",
- "Requirement already satisfied: jupyterlab-widgets~=3.0.10 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (3.0.10)\r\n",
- "Requirement already satisfied: decorator in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (5.1.1)\r\n",
- "Requirement already satisfied: jedi>=0.16 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.19.1)\r\n",
- "Requirement already satisfied: matplotlib-inline in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.1.6)\r\n",
- "Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (3.0.43)\r\n",
- "Requirement already satisfied: pygments>=2.4.0 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (2.17.2)\r\n",
- "Requirement already satisfied: stack-data in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.6.3)\r\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Requirement already satisfied: pexpect>4.3 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (4.9.0)\r\n",
- "Requirement already satisfied: parso<0.9.0,>=0.8.3 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets) (0.8.4)\r\n",
- "Requirement already satisfied: ptyprocess>=0.5 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets) (0.7.0)\r\n",
- "Requirement already satisfied: wcwidth in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from prompt-toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets) (0.2.13)\r\n",
- "Requirement already satisfied: executing>=1.2.0 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.0.1)\r\n",
- "Requirement already satisfied: asttokens>=2.1.0 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.4.1)\r\n",
- "Requirement already satisfied: pure-eval in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (0.2.2)\r\n",
- "Requirement already satisfied: six>=1.12.0 in /Users/engs2510/.pyenv/versions/pybop-3.12/lib/python3.12/site-packages (from asttokens>=2.1.0->stack-data->ipython>=6.1.0->ipywidgets) (1.16.0)\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": [
+ "Requirement already satisfied: pip in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (24.1.1)\n",
+ "Collecting pip\n",
+ " Downloading pip-24.1.2-py3-none-any.whl.metadata (3.6 kB)\n",
+ "Requirement already satisfied: ipywidgets in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (8.1.3)\n",
+ "Requirement already satisfied: comm>=0.1.3 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (0.2.2)\n",
+ "Requirement already satisfied: ipython>=6.1.0 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (8.23.0)\n",
+ "Requirement already satisfied: traitlets>=4.3.1 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (5.14.2)\n",
+ "Requirement already satisfied: widgetsnbextension~=4.0.11 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (4.0.11)\n",
+ "Requirement already satisfied: jupyterlab-widgets~=3.0.11 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipywidgets) (3.0.11)\n",
+ "Requirement already satisfied: decorator in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (5.1.1)\n",
+ "Requirement already satisfied: jedi>=0.16 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.19.1)\n",
+ "Requirement already satisfied: matplotlib-inline in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.1.6)\n",
+ "Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (3.0.43)\n",
+ "Requirement already satisfied: pygments>=2.4.0 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (2.17.2)\n",
+ "Requirement already satisfied: stack-data in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (0.6.3)\n",
+ "Requirement already satisfied: pexpect>4.3 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from ipython>=6.1.0->ipywidgets) (4.9.0)\n",
+ "Requirement already satisfied: parso<0.9.0,>=0.8.3 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets) (0.8.4)\n",
+ "Requirement already satisfied: ptyprocess>=0.5 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets) (0.7.0)\n",
+ "Requirement already satisfied: wcwidth in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from prompt-toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets) (0.2.13)\n",
+ "Requirement already satisfied: executing>=1.2.0 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.0.1)\n",
+ "Requirement already satisfied: asttokens>=2.1.0 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (2.4.1)\n",
+ "Requirement already satisfied: pure-eval in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from stack-data->ipython>=6.1.0->ipywidgets) (0.2.2)\n",
+ "Requirement already satisfied: six>=1.12.0 in /Users/engs2510/.pyenv/versions/3.12.2/envs/pybop-3.12/lib/python3.12/site-packages (from asttokens>=2.1.0->stack-data->ipython>=6.1.0->ipywidgets) (1.16.0)\n",
+ "Downloading pip-24.1.2-py3-none-any.whl (1.8 MB)\n",
+ "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m14.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
+ "\u001b[?25hInstalling collected packages: pip\n",
+ " Attempting uninstall: pip\n",
+ " Found existing installation: pip 24.1.1\n",
+ " Uninstalling pip-24.1.1:\n",
+ " Successfully uninstalled pip-24.1.1\n",
+ "Successfully installed pip-24.1.2\n",
+ "Note: you may need to restart the kernel to use updated packages.\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
@@ -454,7 +434,7 @@
{
"data": {
"text/plain": [
- "array([0.47496537, 0.61140011])"
+ "array([0.50112972, 0.60822849])"
]
},
"execution_count": 12,
@@ -509,7 +489,7 @@
{
"data": {
"image/svg+xml": [
- ""
+ ""
]
},
"metadata": {},
@@ -541,35 +521,6 @@
}
},
"outputs": [
- {
- "data": {
- "text/html": [
- " \n",
- " "
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
{
"data": {
"application/vnd.plotly.v1+json": {
@@ -635,39 +586,39 @@
],
"z": [
[
- -0.00022055019400039357,
- -0.000208179915115477,
- -0.00017733967875981405,
- -0.00013382475248593996,
- -0.00009744280975100401
+ -0.00022054368296133442,
+ -0.00020817417477179742,
+ -0.00017733555998179898,
+ -0.0001338224058942881,
+ -0.00009744128489582522
],
[
- -0.00022006829217595638,
- -0.00020771646089835422,
- -0.00017025065441761346,
- -0.00010411185465723509,
- -1.4831730728913642e-30
+ -0.0002200624215295616,
+ -0.00020771124661048325,
+ -0.00017024715510881273,
+ -0.00010411043723798278,
+ 2.0121777293998183e-28
],
[
- -0.00023289339271513726,
- -0.00022148992831206213,
- -0.0001854997008341146,
- -0.00011792954324326614,
- 1.7126139220369943e-29
+ -0.00023288833495346782,
+ -0.0002214855296927363,
+ -0.00018549704922968932,
+ -0.0001179289043801153,
+ 1.0313790127184039e-29
],
[
- -0.00025468769038466233,
- -0.0002482874721993978,
- -0.00022970881918716953,
- -0.00020352723357102716,
- -0.0001826834881022567
+ -0.0002546830904738895,
+ -0.0002482834858238037,
+ -0.00022970648308007864,
+ -0.00020352686864885834,
+ -0.00018268420575956896
],
[
- -0.0002626049278499214,
- -0.00025977998017220894,
- -0.00024814221133557976,
- -0.00023376411978352077,
- -0.00022697336267452442
+ -0.00026260052021642185,
+ -0.00025977603234850937,
+ -0.0002481397380647309,
+ -0.0002337634294784395,
+ -0.00022697371294696725
]
]
}
@@ -1505,34 +1456,7 @@
}
}
}
- },
- "text/html": [
- "
"
- ]
+ }
},
"metadata": {},
"output_type": "display_data"
@@ -1644,39 +1568,39 @@
],
"z": [
[
- 3.7078876177014553,
- 3.7078763478472188,
- 3.707853323934633,
- 3.7078260164047094,
- 3.707808564119712
+ 3.7080242488013124,
+ 3.708012980167902,
+ 3.7079899587671075,
+ 3.707962653872268,
+ 3.7079452026255506
],
[
- 3.7078651244026894,
- 3.7078535908947208,
- 3.7078220221902427,
- 3.7077785523089566,
- 3.7077445721396733
+ 3.7080017566721923,
+ 3.7079902242011094,
+ 3.7079586581556887,
+ 3.707915191282287,
+ 3.7078812123884246
],
[
- 3.7078229486184475,
- 3.707804218479802,
- 3.7077454950451716,
- 3.7076369622920593,
- 3.7074529354653967
+ 3.7079595825355014,
+ 3.7079408535029024,
+ 3.7078821330256533,
+ 3.7077736038127984,
+ 3.7075895787025472
],
[
- 3.7077939368814126,
- 3.707773778768286,
- 3.7077102612800763,
- 3.7075952142136557,
- 3.707407186787348
+ 3.707930571743512,
+ 3.707910414663849,
+ 3.7078468999564493,
+ 3.707731856210595,
+ 3.7075438305495547
],
[
- 3.7077846062570954,
- 3.70776995420107,
- 3.707720253036007,
- 3.707647593021552,
- 3.707589085925729
+ 3.707921241493712,
+ 3.7079065902163797,
+ 3.7078568915338876,
+ 3.707784234516676,
+ 3.707725729161621
]
]
}
@@ -2514,34 +2438,7 @@
}
}
}
- },
- "text/html": [
- ""
- ]
+ }
},
"metadata": {},
"output_type": "display_data"
@@ -2592,7 +2489,7 @@
{
"data": {
"image/svg+xml": [
- ""
+ ""
]
},
"metadata": {},
@@ -2601,7 +2498,7 @@
{
"data": {
"image/svg+xml": [
- ""
+ ""
]
},
"metadata": {},
@@ -2637,7 +2534,7 @@
{
"data": {
"image/svg+xml": [
- ""
+ ""
]
},
"metadata": {},
diff --git a/examples/notebooks/spm_electrode_design.ipynb b/examples/notebooks/spm_electrode_design.ipynb
index e1fd58204..90571c993 100644
--- a/examples/notebooks/spm_electrode_design.ipynb
+++ b/examples/notebooks/spm_electrode_design.ipynb
@@ -10,7 +10,7 @@
"\n",
"NOTE: This is a brittle example, the classes and methods below will be integrated into PyBOP in a future release.\n",
"\n",
- "A design optimisation example loosely based on work by L.D. Couto available at https://doi.org/10.1016/j.energy.2022.125966.\n",
+ "A design optimisation example loosely based on work by L.D. Couto available at [[1]](https://doi.org/10.1016/j.energy.2022.125966).\n",
"\n",
"The target is to maximise the gravimetric energy density over a range of possible design parameter values, including for example:\n",
"\n",
@@ -396,7 +396,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.2"
+ "version": "3.11.7"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
diff --git a/examples/standalone/problem.py b/examples/standalone/problem.py
index d76f9dca5..18bf1f7d4 100644
--- a/examples/standalone/problem.py
+++ b/examples/standalone/problem.py
@@ -24,7 +24,7 @@ def __init__(
self._dataset = dataset.data
# Check that the dataset contains time and current
- for name in ["Time [s]"] + self.signal:
+ for name in ["Time [s]", *self.signal]:
if name not in self._dataset:
raise ValueError(f"expected {name} in list of dataset")
diff --git a/pybop/_dataset.py b/pybop/_dataset.py
index 0da8be4be..66bcb1f10 100644
--- a/pybop/_dataset.py
+++ b/pybop/_dataset.py
@@ -1,6 +1,5 @@
import numpy as np
-from pybamm import Interpolant, solvers
-from pybamm import t as pybamm_t
+from pybamm import solvers
class Dataset:
@@ -77,26 +76,7 @@ def __getitem__(self, key):
return self.data[key]
- def Interpolant(self):
- """
- Create an interpolation function of the dataset based on the independent variable.
-
- Currently, only time-based interpolation is supported. This method modifies
- the instance's Interpolant attribute to be an interpolation function that
- can be evaluated at different points in time.
-
- Raises
- ------
- NotImplementedError
- If the independent variable for interpolation is not supported.
- """
-
- if self.variable == "time":
- self.Interpolant = Interpolant(self.x, self.y, pybamm_t)
- else:
- NotImplementedError("Only time interpolation is supported")
-
- def check(self, signal=["Voltage [V]"]):
+ def check(self, signal=None):
"""
Check the consistency of a PyBOP Dataset against the expected format.
@@ -110,11 +90,13 @@ def check(self, signal=["Voltage [V]"]):
ValueError
If the time series and the data series are not consistent.
"""
+ if signal is None:
+ signal = ["Voltage [V]"]
if isinstance(signal, str):
signal = [signal]
# Check that the dataset contains time and chosen signal
- for name in ["Time [s]"] + signal:
+ for name in ["Time [s]", *signal]:
if name not in self.names:
raise ValueError(f"expected {name} in list of dataset")
diff --git a/pybop/costs/_likelihoods.py b/pybop/costs/_likelihoods.py
index 42fdf40df..d8a66360f 100644
--- a/pybop/costs/_likelihoods.py
+++ b/pybop/costs/_likelihoods.py
@@ -1,4 +1,4 @@
-from typing import List, Tuple, Union
+from typing import Union
import numpy as np
@@ -14,7 +14,7 @@ class BaseLikelihood(BaseCost):
"""
def __init__(self, problem: BaseProblem):
- super(BaseLikelihood, self).__init__(problem)
+ super().__init__(problem)
self.n_time_data = problem.n_time_data
@@ -32,8 +32,8 @@ class GaussianLogLikelihoodKnownSigma(BaseLikelihood):
per dimension.
"""
- def __init__(self, problem: BaseProblem, sigma0: Union[List[float], float]):
- super(GaussianLogLikelihoodKnownSigma, self).__init__(problem)
+ def __init__(self, problem: BaseProblem, sigma0: Union[list[float], float]):
+ super().__init__(problem)
sigma0 = self.check_sigma0(sigma0)
self.sigma2 = sigma0**2.0
self._offset = -0.5 * self.n_time_data * np.log(2 * np.pi * self.sigma2)
@@ -65,7 +65,7 @@ def _evaluate(self, inputs: Inputs, grad: Union[None, np.ndarray] = None) -> flo
return e if self.n_outputs != 1 else e.item()
- def _evaluateS1(self, inputs: Inputs) -> Tuple[float, np.ndarray]:
+ def _evaluateS1(self, inputs: Inputs) -> tuple[float, np.ndarray]:
"""
Calculates the log-likelihood and gradient.
"""
@@ -99,7 +99,7 @@ def check_sigma0(self, sigma0: Union[np.ndarray, float]):
if np.shape(sigma0) not in [(), (1,), (self.n_outputs,)]:
raise ValueError(
"sigma0 must be either a scalar value (one standard deviation for "
- + "all coordinates) or an array with one entry per dimension."
+ "all coordinates) or an array with one entry per dimension."
)
return sigma0
@@ -124,10 +124,10 @@ class GaussianLogLikelihood(BaseLikelihood):
def __init__(
self,
problem: BaseProblem,
- sigma0: Union[float, List[float], List[Parameter]] = 0.002,
+ sigma0: Union[float, list[float], list[Parameter]] = 0.002,
dsigma_scale: float = 1.0,
):
- super(GaussianLogLikelihood, self).__init__(problem)
+ super().__init__(problem)
self._dsigma_scale = dsigma_scale
self._logpi = -0.5 * self.n_time_data * np.log(2 * np.pi)
self._fixed_problem = False # keep problem evaluation within _evaluate
@@ -138,7 +138,7 @@ def __init__(
self._dl = np.ones(self.n_parameters)
def _add_sigma_parameters(self, sigma0):
- sigma0 = [sigma0] if not isinstance(sigma0, List) else sigma0
+ sigma0 = [sigma0] if not isinstance(sigma0, list) else sigma0
sigma0 = self._pad_sigma0(sigma0)
for i, value in enumerate(sigma0):
@@ -229,7 +229,7 @@ def _evaluate(self, inputs: Inputs, grad: Union[None, np.ndarray] = None) -> flo
return e if self.n_outputs != 1 else e.item()
- def _evaluateS1(self, inputs: Inputs) -> Tuple[float, np.ndarray]:
+ def _evaluateS1(self, inputs: Inputs) -> tuple[float, np.ndarray]:
"""
Calculates the log-likelihood and sensitivities.
@@ -290,7 +290,7 @@ class MAP(BaseLikelihood):
"""
def __init__(self, problem, likelihood, sigma0=None, gradient_step=1e-3):
- super(MAP, self).__init__(problem)
+ super().__init__(problem)
self.sigma0 = sigma0
self.gradient_step = gradient_step
if self.sigma0 is None:
@@ -303,7 +303,7 @@ def __init__(self, problem, likelihood, sigma0=None, gradient_step=1e-3):
except Exception as e:
raise ValueError(
f"An error occurred when constructing the Likelihood class: {e}"
- )
+ ) from e
if hasattr(self, "likelihood") and not isinstance(
self.likelihood, BaseLikelihood
@@ -338,7 +338,7 @@ def _evaluate(self, inputs: Inputs, grad=None) -> float:
posterior = log_likelihood + log_prior
return posterior
- def _evaluateS1(self, inputs: Inputs) -> Tuple[float, np.ndarray]:
+ def _evaluateS1(self, inputs: Inputs) -> tuple[float, np.ndarray]:
"""
Compute the maximum a posteriori with respect to the parameters.
The method passes the likelihood gradient to the optimiser without modification.
diff --git a/pybop/costs/base_cost.py b/pybop/costs/base_cost.py
index bd11f8a35..322d082fc 100644
--- a/pybop/costs/base_cost.py
+++ b/pybop/costs/base_cost.py
@@ -79,7 +79,7 @@ def evaluate(self, x, grad=None):
raise e
except Exception as e:
- raise ValueError(f"Error in cost calculation: {e}")
+ raise ValueError(f"Error in cost calculation: {e}") from e
def _evaluate(self, inputs: Inputs, grad=None):
"""
@@ -141,7 +141,7 @@ def evaluateS1(self, x):
raise e
except Exception as e:
- raise ValueError(f"Error in cost calculation: {e}")
+ raise ValueError(f"Error in cost calculation: {e}") from e
def _evaluateS1(self, inputs: Inputs):
"""
diff --git a/pybop/costs/design_costs.py b/pybop/costs/design_costs.py
index 056c348fe..738dfe61e 100644
--- a/pybop/costs/design_costs.py
+++ b/pybop/costs/design_costs.py
@@ -31,7 +31,7 @@ def __init__(self, problem, update_capacity=False):
problem : object
The problem instance containing the model and data.
"""
- super(DesignCost, self).__init__(problem)
+ super().__init__(problem)
self.problem = problem
if update_capacity is True:
nominal_capacity_warning = (
@@ -41,7 +41,7 @@ def __init__(self, problem, update_capacity=False):
nominal_capacity_warning = (
"The nominal capacity is fixed at the initial model value."
)
- warnings.warn(nominal_capacity_warning, UserWarning)
+ warnings.warn(nominal_capacity_warning, UserWarning, stacklevel=2)
self.update_capacity = update_capacity
self.parameter_set = problem.model.parameter_set
self.update_simulation_data(self.parameters.as_dict("initial"))
@@ -97,7 +97,7 @@ class GravimetricEnergyDensity(DesignCost):
"""
def __init__(self, problem, update_capacity=False):
- super(GravimetricEnergyDensity, self).__init__(problem, update_capacity)
+ super().__init__(problem, update_capacity)
self._fixed_problem = False # keep problem evaluation within _evaluate
def _evaluate(self, inputs: Inputs, grad=None):
@@ -154,7 +154,7 @@ class VolumetricEnergyDensity(DesignCost):
"""
def __init__(self, problem, update_capacity=False):
- super(VolumetricEnergyDensity, self).__init__(problem, update_capacity)
+ super().__init__(problem, update_capacity)
self._fixed_problem = False # keep problem evaluation within _evaluate
def _evaluate(self, inputs: Inputs, grad=None):
diff --git a/pybop/costs/fitting_costs.py b/pybop/costs/fitting_costs.py
index da4584242..13673287a 100644
--- a/pybop/costs/fitting_costs.py
+++ b/pybop/costs/fitting_costs.py
@@ -18,7 +18,7 @@ class RootMeanSquaredError(BaseCost):
"""
def __init__(self, problem):
- super(RootMeanSquaredError, self).__init__(problem)
+ super().__init__(problem)
# Default fail gradient
self._de = 1.0
@@ -142,7 +142,7 @@ class SumSquaredError(BaseCost):
"""
def __init__(self, problem):
- super(SumSquaredError, self).__init__(problem)
+ super().__init__(problem)
# Default fail gradient
self._de = 1.0
@@ -172,7 +172,7 @@ def _evaluate(self, inputs: Inputs, grad=None):
e = np.asarray(
[
- np.sum(((self._current_prediction[signal] - self._target[signal]) ** 2))
+ np.sum((self._current_prediction[signal] - self._target[signal]) ** 2)
for signal in self.signal
]
)
diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py
index e9ba3d6c4..461989086 100644
--- a/pybop/models/base_model.py
+++ b/pybop/models/base_model.py
@@ -1,6 +1,6 @@
import copy
from dataclasses import dataclass
-from typing import Any, Dict, Optional, Union
+from typing import Any, Optional, Union
import casadi
import numpy as np
@@ -11,7 +11,7 @@
@dataclass
-class TimeSeriesState(object):
+class TimeSeriesState:
"""
The current state of a time series model that is a pybamm model.
"""
@@ -76,9 +76,9 @@ def __init__(self, name="Base Model", parameter_set=None):
def build(
self,
dataset: Dataset = None,
- parameters: Union[Parameters, Dict] = None,
+ parameters: Union[Parameters, dict] = None,
check_model: bool = True,
- init_soc: float = None,
+ init_soc: Optional[float] = None,
) -> None:
"""
Construct the PyBaMM model if not already built, and set parameters.
@@ -191,10 +191,10 @@ def set_params(self, rebuild=False):
def rebuild(
self,
dataset: Dataset = None,
- parameters: Union[Parameters, Dict] = None,
+ parameters: Union[Parameters, dict] = None,
parameter_set: ParameterSet = None,
check_model: bool = True,
- init_soc: float = None,
+ init_soc: Optional[float] = None,
) -> None:
"""
Rebuild the PyBaMM model for a given parameter set.
@@ -329,7 +329,7 @@ def step(self, state: TimeSeriesState, time: np.ndarray) -> TimeSeriesState:
def simulate(
self, inputs: Inputs, t_eval: np.array
- ) -> Dict[str, np.ndarray[np.float64]]:
+ ) -> dict[str, np.ndarray[np.float64]]:
"""
Execute the forward model simulation and return the result.
@@ -457,8 +457,8 @@ def predict(
t_eval: np.array = None,
parameter_set: ParameterSet = None,
experiment: Experiment = None,
- init_soc: float = None,
- ) -> Dict[str, np.ndarray[np.float64]]:
+ init_soc: Optional[float] = None,
+ ) -> dict[str, np.ndarray[np.float64]]:
"""
Solve the model using PyBaMM's simulation framework and return the solution.
@@ -676,7 +676,7 @@ def submesh_types(self):
return self._submesh_types
@submesh_types.setter
- def submesh_types(self, submesh_types: Optional[Dict[str, Any]]):
+ def submesh_types(self, submesh_types: Optional[dict[str, Any]]):
self._submesh_types = (
submesh_types.copy() if submesh_types is not None else None
)
@@ -690,7 +690,7 @@ def var_pts(self):
return self._var_pts
@var_pts.setter
- def var_pts(self, var_pts: Optional[Dict[str, int]]):
+ def var_pts(self, var_pts: Optional[dict[str, int]]):
self._var_pts = var_pts.copy() if var_pts is not None else None
@property
@@ -698,7 +698,7 @@ def spatial_methods(self):
return self._spatial_methods
@spatial_methods.setter
- def spatial_methods(self, spatial_methods: Optional[Dict[str, Any]]):
+ def spatial_methods(self, spatial_methods: Optional[dict[str, Any]]):
self._spatial_methods = (
spatial_methods.copy() if spatial_methods is not None else None
)
diff --git a/pybop/models/lithium_ion/base_echem.py b/pybop/models/lithium_ion/base_echem.py
index fd4aa2682..f60f500d3 100644
--- a/pybop/models/lithium_ion/base_echem.py
+++ b/pybop/models/lithium_ion/base_echem.py
@@ -136,7 +136,7 @@ def _check_params(
):
if self.param_check_counter <= len(electrode_params):
infeasibility_warning = "Non-physical point encountered - [{material_vol_fraction} + {porosity}] > 1.0!"
- warnings.warn(infeasibility_warning, UserWarning)
+ warnings.warn(infeasibility_warning, UserWarning, stacklevel=2)
self.param_check_counter += 1
return allow_infeasible_solutions
@@ -308,7 +308,7 @@ def approximate_capacity(self, inputs: Inputs):
mean_sto_pos
) - negative_electrode_ocp(mean_sto_neg)
except Exception as e:
- raise ValueError(f"Error in average voltage calculation: {e}")
+ raise ValueError(f"Error in average voltage calculation: {e}") from e
# Calculate and update nominal capacity
theoretical_capacity = theoretical_energy / average_voltage
diff --git a/pybop/models/lithium_ion/echem.py b/pybop/models/lithium_ion/echem.py
index 8bd8ab636..9fdd308e3 100644
--- a/pybop/models/lithium_ion/echem.py
+++ b/pybop/models/lithium_ion/echem.py
@@ -1,8 +1,7 @@
from pybamm import lithium_ion as pybamm_lithium_ion
from pybop.models.lithium_ion.base_echem import EChemBaseModel
-
-from .weppner_huggins import BaseWeppnerHuggins
+from pybop.models.lithium_ion.weppner_huggins import BaseWeppnerHuggins
class SPM(EChemBaseModel):
diff --git a/pybop/models/lithium_ion/weppner_huggins.py b/pybop/models/lithium_ion/weppner_huggins.py
index 5d8d626a4..74c42c70e 100644
--- a/pybop/models/lithium_ion/weppner_huggins.py
+++ b/pybop/models/lithium_ion/weppner_huggins.py
@@ -36,7 +36,7 @@ def __init__(self, name="Weppner & Huggins model", **model_kwargs):
# Model kwargs (build, options) are not implemented, keeping here for consistent interface
if model_kwargs is not dict(build=True):
unused_kwargs_warning = "The input model_kwargs are not currently used by the Weppner & Huggins model."
- warnings.warn(unused_kwargs_warning, UserWarning)
+ warnings.warn(unused_kwargs_warning, UserWarning, stacklevel=2)
super().__init__({}, name)
diff --git a/pybop/observers/observer.py b/pybop/observers/observer.py
index 1c35c25df..f7d6f25f3 100644
--- a/pybop/observers/observer.py
+++ b/pybop/observers/observer.py
@@ -38,10 +38,14 @@ def __init__(
parameters: Parameters,
model: BaseModel,
check_model=True,
- signal=["Voltage [V]"],
- additional_variables=[],
+ signal=None,
+ additional_variables=None,
init_soc=None,
) -> None:
+ if additional_variables is None:
+ additional_variables = []
+ if signal is None:
+ signal = ["Voltage [V]"]
super().__init__(
parameters, model, check_model, signal, additional_variables, init_soc
)
diff --git a/pybop/observers/unscented_kalman.py b/pybop/observers/unscented_kalman.py
index afbc2a010..60f4f0949 100644
--- a/pybop/observers/unscented_kalman.py
+++ b/pybop/observers/unscented_kalman.py
@@ -1,5 +1,5 @@
from dataclasses import dataclass
-from typing import List, Tuple, Union
+from typing import Union
import numpy as np
import scipy.linalg as linalg
@@ -41,17 +41,21 @@ class UnscentedKalmanFilterObserver(Observer):
def __init__(
self,
- parameters: List[Parameter],
+ parameters: list[Parameter],
model: BaseModel,
sigma0: Union[Covariance, float],
process: Union[Covariance, float],
measure: Union[Covariance, float],
dataset=None,
check_model=True,
- signal=["Voltage [V]"],
- additional_variables=[],
+ signal=None,
+ additional_variables=None,
init_soc=None,
) -> None:
+ if additional_variables is None:
+ additional_variables = []
+ if signal is None:
+ signal = ["Voltage [V]"]
super().__init__(
parameters, model, check_model, signal, additional_variables, init_soc
)
@@ -59,7 +63,7 @@ def __init__(
self._dataset = dataset.data
# Check that the dataset contains time and current
- dataset.check(self.signal + ["Current function [A]"])
+ dataset.check([*self.signal, "Current function [A]"])
self._time_data = self._dataset["Time [s]"]
self.n_time_data = len(self._time_data)
@@ -152,7 +156,7 @@ def get_current_covariance(self) -> Covariance:
@dataclass
-class SigmaPoint(object):
+class SigmaPoint:
"""
A sigma point is a point in the state space that is used to estimate the mean and covariance of a random variable.
"""
@@ -162,7 +166,7 @@ class SigmaPoint(object):
w_c: float
-class SquareRootUKF(object):
+class SquareRootUKF:
"""
van der Menve, R., & Wan, E. A. (2001). THE SQUARE-ROOT UNSCENTED KALMAN FILTER FOR STATE AND PARAMETER-ESTIMATION.
https://doi.org/10.1109/ICASSP.2001.940586
@@ -235,7 +239,7 @@ def reset(self, x: np.ndarray, S: np.ndarray) -> None:
@staticmethod
def gen_sigma_points(
x: np.ndarray, S: np.ndarray, alpha: float, beta: float, states: np.ndarray
- ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
Generates 2L+1 sigma points for the unscented transform, where L is the number of states.
@@ -291,7 +295,7 @@ def unscented_transform(
w_c: np.ndarray,
sqrtR: np.ndarray,
states: Union[np.ndarray, None] = None,
- ) -> Tuple[np.ndarray, np.ndarray]:
+ ) -> tuple[np.ndarray, np.ndarray]:
"""
Performs the unscented transform
diff --git a/pybop/optimisers/_adamw.py b/pybop/optimisers/_adamw.py
index 24e5ec982..817d8f290 100644
--- a/pybop/optimisers/_adamw.py
+++ b/pybop/optimisers/_adamw.py
@@ -157,7 +157,7 @@ def tell(self, reply):
# Check ask-tell pattern
if not self._ready_for_tell:
- raise Exception("ask() not called before tell()")
+ raise RuntimeError("ask() not called before tell()")
self._ready_for_tell = False
# Unpack reply
diff --git a/pybop/optimisers/base_optimiser.py b/pybop/optimisers/base_optimiser.py
index 4693468f2..2b00b2345 100644
--- a/pybop/optimisers/base_optimiser.py
+++ b/pybop/optimisers/base_optimiser.py
@@ -1,4 +1,5 @@
import warnings
+from typing import Optional
import numpy as np
@@ -75,8 +76,9 @@ def __init__(
cost_test = cost(self.x0)
warnings.warn(
"The cost is not an instance of pybop.BaseCost, but let's continue "
- + "assuming that it is a callable function to be minimised.",
+ "assuming that it is a callable function to be minimised.",
UserWarning,
+ stacklevel=2,
)
self.cost = cost
for i, value in enumerate(self.x0):
@@ -85,8 +87,10 @@ def __init__(
)
self.minimising = True
- except Exception:
- raise Exception("The cost is not a recognised cost object or function.")
+ except Exception as e:
+ raise Exception(
+ "The cost is not a recognised cost object or function."
+ ) from e
if not np.isscalar(cost_test) or not np.isreal(cost_test):
raise TypeError(
@@ -211,7 +215,7 @@ def check_optimal_parameters(self, x):
else:
warnings.warn(
"Optimised parameters are not physically viable! \nConsider retrying the optimisation"
- + " with a non-gradient-based optimiser and the option allow_infeasible_solutions=False",
+ " with a non-gradient-based optimiser and the option allow_infeasible_solutions=False",
UserWarning,
stacklevel=2,
)
@@ -269,8 +273,8 @@ class Result:
def __init__(
self,
x: np.ndarray = None,
- final_cost: float = None,
- n_iterations: int = None,
+ final_cost: Optional[float] = None,
+ n_iterations: Optional[int] = None,
scipy_result=None,
):
self.x = x
diff --git a/pybop/optimisers/pints_optimisers.py b/pybop/optimisers/pints_optimisers.py
index 64b77b674..83f13aa00 100644
--- a/pybop/optimisers/pints_optimisers.py
+++ b/pybop/optimisers/pints_optimisers.py
@@ -272,7 +272,7 @@ def __init__(self, cost, **optimiser_kwargs):
if len(x0) == 1 or len(cost.parameters) == 1:
raise ValueError(
"CMAES requires optimisation of >= 2 parameters at once. "
- + "Please choose another optimiser."
+ "Please choose another optimiser."
)
super().__init__(cost, PintsCMAES, **optimiser_kwargs)
diff --git a/pybop/optimisers/scipy_optimisers.py b/pybop/optimisers/scipy_optimisers.py
index 544abfc88..30499cdb9 100644
--- a/pybop/optimisers/scipy_optimisers.py
+++ b/pybop/optimisers/scipy_optimisers.py
@@ -161,7 +161,7 @@ def callback(intermediate_result: OptimizeResult):
# Compute the absolute initial cost and resample if required
self._cost0 = np.abs(self.cost(self.x0))
if np.isinf(self._cost0):
- for i in range(1, self.num_resamples):
+ for _i in range(1, self.num_resamples):
self.x0 = self.parameters.rvs(1)[0]
self._cost0 = np.abs(self.cost(self.x0))
if not np.isinf(self._cost0):
diff --git a/pybop/parameters/parameter.py b/pybop/parameters/parameter.py
index 27836fc80..093abaed9 100644
--- a/pybop/parameters/parameter.py
+++ b/pybop/parameters/parameter.py
@@ -1,12 +1,12 @@
import warnings
from collections import OrderedDict
-from typing import Dict, List, Union
+from typing import Union
import numpy as np
from pybop._utils import is_numeric
-Inputs = Dict[str, float]
+Inputs = dict[str, float]
class Parameter:
@@ -219,7 +219,7 @@ def __getitem__(self, key: str) -> Parameter:
def __len__(self) -> int:
return len(self.param)
- def keys(self) -> List:
+ def keys(self) -> list:
"""
A list of parameter names
"""
@@ -245,7 +245,7 @@ def add(self, parameter):
if parameter.name in self.param.keys():
raise ValueError(
f"There is already a parameter with the name {parameter.name} "
- + "in the Parameters object. Please remove the duplicate entry."
+ "in the Parameters object. Please remove the duplicate entry."
)
self.param[parameter.name] = parameter
elif isinstance(parameter, dict):
@@ -255,7 +255,7 @@ def add(self, parameter):
if name in self.param.keys():
raise ValueError(
f"There is already a parameter with the name {name} "
- + "in the Parameters object. Please remove the duplicate entry."
+ "in the Parameters object. Please remove the duplicate entry."
)
self.param[name] = Parameter(**parameter)
else:
@@ -287,7 +287,7 @@ def join(self, parameters=None):
else:
print(f"Discarding duplicate {param.name}.")
- def get_bounds(self) -> Dict:
+ def get_bounds(self) -> dict:
"""
Get bounds, for either all or no parameters.
"""
@@ -317,12 +317,12 @@ def update(self, initial_values=None, values=None, bounds=None):
if values is not None:
param.update(value=values[i])
if bounds is not None:
- if isinstance(bounds, Dict):
+ if isinstance(bounds, dict):
param.set_bounds(bounds=[bounds["lower"][i], bounds["upper"][i]])
else:
param.set_bounds(bounds=bounds[i])
- def rvs(self, n_samples: int) -> List:
+ def rvs(self, n_samples: int) -> list:
"""
Draw random samples from each parameter's prior distribution.
@@ -355,7 +355,7 @@ def rvs(self, n_samples: int) -> List:
return all_samples
- def get_sigma0(self) -> List:
+ def get_sigma0(self) -> list:
"""
Get the standard deviation, for either all or no parameters.
"""
@@ -434,7 +434,7 @@ def get_bounds_for_plotly(self):
return bounds
- def as_dict(self, values=None) -> Dict:
+ def as_dict(self, values=None) -> dict:
"""
Parameters
----------
@@ -465,7 +465,7 @@ def verify(self, inputs: Union[Inputs, None] = None):
----------
inputs : Inputs or numeric
"""
- if inputs is None or isinstance(inputs, Dict):
+ if inputs is None or isinstance(inputs, dict):
return inputs
elif (isinstance(inputs, list) and all(is_numeric(x) for x in inputs)) or all(
is_numeric(x) for x in list(inputs)
diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py
index 43f3e999b..c1b9505b5 100644
--- a/pybop/parameters/parameter_set.py
+++ b/pybop/parameters/parameter_set.py
@@ -1,6 +1,5 @@
import json
import types
-from typing import List
from pybamm import LithiumIonParameters, ParameterValues, parameter_sets
@@ -35,7 +34,7 @@ def __setitem__(self, key, value):
def __getitem__(self, key):
return self.params[key]
- def keys(self) -> List:
+ def keys(self) -> list:
"""
A list of parameter names
"""
@@ -67,7 +66,7 @@ def import_parameters(self, json_path=None):
# Read JSON file
if not self.params and self.json_path:
- with open(self.json_path, "r") as file:
+ with open(self.json_path) as file:
self.params = json.load(file)
else:
raise ValueError(
@@ -139,7 +138,7 @@ def export_parameters(self, output_json_path, fit_params=None):
# Update parameter set
if fit_params is not None:
- for i, param in enumerate(fit_params):
+ for _i, param in enumerate(fit_params):
exportable_params.update({param.name: param.value})
# Replace non-serializable values
diff --git a/pybop/plotting/plot2d.py b/pybop/plotting/plot2d.py
index ee8d70573..781b697ba 100644
--- a/pybop/plotting/plot2d.py
+++ b/pybop/plotting/plot2d.py
@@ -71,8 +71,9 @@ def plot2d(
if len(cost.parameters) > 2:
warnings.warn(
"This cost function requires more than 2 parameters. "
- + "Plotting in 2d with fixed values for the additional parameters.",
+ "Plotting in 2d with fixed values for the additional parameters.",
UserWarning,
+ stacklevel=2,
)
for (
i,
diff --git a/pybop/plotting/plot_dataset.py b/pybop/plotting/plot_dataset.py
index 70573e476..ecc84aa6e 100644
--- a/pybop/plotting/plot_dataset.py
+++ b/pybop/plotting/plot_dataset.py
@@ -3,9 +3,7 @@
from pybop import StandardPlot, plot_trajectories
-def plot_dataset(
- dataset, signal=["Voltage [V]"], trace_names=None, show=True, **layout_kwargs
-):
+def plot_dataset(dataset, signal=None, trace_names=None, show=True, **layout_kwargs):
"""
Quickly plot a PyBOP Dataset using Plotly.
@@ -31,6 +29,8 @@ def plot_dataset(
"""
# Get data dictionary
+ if signal is None:
+ signal = ["Voltage [V]"]
dataset.check(signal)
# Compile ydata and labels or legend
diff --git a/pybop/plotting/plotly_manager.py b/pybop/plotting/plotly_manager.py
index 7b4b079a4..5554a2af5 100644
--- a/pybop/plotting/plotly_manager.py
+++ b/pybop/plotting/plotly_manager.py
@@ -119,7 +119,7 @@ def check_browser_availability(self):
if self.pio and self.pio.renderers.default == "browser":
try:
webbrowser.get()
- except webbrowser.Error:
+ except webbrowser.Error as e:
raise Exception(
"\n **Browser Not Found** \nFor Windows users, in order to view figures in the browser using Plotly, "
"you need to set the environment variable BROWSER equal to the "
@@ -129,4 +129,4 @@ def check_browser_availability(self):
"\n\nThen reactivate your virtual environment. Alternatively, you can use a "
"different Plotly renderer. For more information see: "
"https://plotly.com/python/renderers/#setting-the-default-renderer"
- )
+ ) from e
diff --git a/pybop/plotting/quick_plot.py b/pybop/plotting/quick_plot.py
index 5be353a62..1ef4e3ffe 100644
--- a/pybop/plotting/quick_plot.py
+++ b/pybop/plotting/quick_plot.py
@@ -57,16 +57,16 @@ def __init__(
x,
y,
layout=None,
- layout_options=DEFAULT_LAYOUT_OPTIONS.copy(),
- trace_options=DEFAULT_TRACE_OPTIONS.copy(),
+ layout_options=DEFAULT_LAYOUT_OPTIONS,
+ trace_options=DEFAULT_TRACE_OPTIONS,
trace_names=None,
trace_name_width=40,
):
self.x = x
self.y = y
self.layout = layout
- self.layout_options = layout_options
- self.trace_options = DEFAULT_TRACE_OPTIONS.copy()
+ self.layout_options = layout_options.copy()
+ self.trace_options = trace_options.copy()
if trace_options is not None:
for arg, value in trace_options.items():
self.trace_options[arg] = value
@@ -246,9 +246,9 @@ def __init__(
num_cols=None,
axis_titles=None,
layout=None,
- layout_options=DEFAULT_LAYOUT_OPTIONS.copy(),
- subplot_options=DEFAULT_SUBPLOT_OPTIONS.copy(),
- trace_options=DEFAULT_SUBPLOT_TRACE_OPTIONS.copy(),
+ layout_options=DEFAULT_LAYOUT_OPTIONS,
+ subplot_options=DEFAULT_SUBPLOT_OPTIONS,
+ trace_options=DEFAULT_SUBPLOT_TRACE_OPTIONS,
trace_names=None,
trace_name_width=40,
):
@@ -267,7 +267,7 @@ def __init__(
elif self.num_cols is None:
self.num_cols = int(math.ceil(self.num_traces / self.num_rows))
self.axis_titles = axis_titles
- self.subplot_options = DEFAULT_SUBPLOT_OPTIONS.copy()
+ self.subplot_options = subplot_options.copy()
if subplot_options is not None:
for arg, value in subplot_options.items():
self.subplot_options[arg] = value
diff --git a/pybop/problems/base_problem.py b/pybop/problems/base_problem.py
index 4d9d85194..ee36a6bb4 100644
--- a/pybop/problems/base_problem.py
+++ b/pybop/problems/base_problem.py
@@ -27,11 +27,15 @@ def __init__(
parameters,
model=None,
check_model=True,
- signal=["Voltage [V]"],
- additional_variables=[],
+ signal=None,
+ additional_variables=None,
init_soc=None,
):
# Check if parameters is a list of pybop.Parameter objects
+ if additional_variables is None:
+ additional_variables = []
+ if signal is None:
+ signal = ["Voltage [V]"]
if isinstance(parameters, list):
if all(isinstance(param, Parameter) for param in parameters):
parameters = Parameters(*parameters)
diff --git a/pybop/problems/design_problem.py b/pybop/problems/design_problem.py
index a1efa22fd..30e2d9c3a 100644
--- a/pybop/problems/design_problem.py
+++ b/pybop/problems/design_problem.py
@@ -34,11 +34,15 @@ def __init__(
parameters,
experiment,
check_model=True,
- signal=["Voltage [V]"],
- additional_variables=[],
+ signal=None,
+ additional_variables=None,
init_soc=None,
):
# Add time and current and remove duplicates
+ if additional_variables is None:
+ additional_variables = []
+ if signal is None:
+ signal = ["Voltage [V]"]
additional_variables.extend(["Time [s]", "Current [A]"])
additional_variables = list(set(additional_variables))
diff --git a/pybop/problems/fitting_problem.py b/pybop/problems/fitting_problem.py
index b27955479..58d59e9ee 100644
--- a/pybop/problems/fitting_problem.py
+++ b/pybop/problems/fitting_problem.py
@@ -32,11 +32,15 @@ def __init__(
parameters,
dataset,
check_model=True,
- signal=["Voltage [V]"],
- additional_variables=[],
+ signal=None,
+ additional_variables=None,
init_soc=None,
):
# Add time and remove duplicates
+ if additional_variables is None:
+ additional_variables = []
+ if signal is None:
+ signal = ["Voltage [V]"]
additional_variables.extend(["Time [s]"])
additional_variables = list(set(additional_variables))
@@ -47,7 +51,7 @@ def __init__(
self.parameters.initial_value()
# Check that the dataset contains time and current
- dataset.check(self.signal + ["Current function [A]"])
+ dataset.check([*self.signal, "Current function [A]"])
# Unpack time and target data
self._time_data = self._dataset["Time [s]"]
diff --git a/pyproject.toml b/pyproject.toml
index 99067e24e..0ec781e58 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -73,7 +73,7 @@ Homepage = "https://github.com/pybop-team/PyBOP"
Documentation = "https://pybop-docs.readthedocs.io"
Repository = "https://github.com/pybop-team/PyBOP"
Releases = "https://github.com/pybop-team/PyBOP/releases"
-Changelog = "https://github.com/pybop-team/PyBOP/CHANGELOG.md"
+Changelog = "https://github.com/pybop-team/PyBOP/blob/develop/CHANGELOG.md"
[tool.pytest.ini_options]
addopts = "--showlocals -v -n auto"
@@ -81,10 +81,23 @@ addopts = "--showlocals -v -n auto"
[tool.ruff]
extend-include = ["*.ipynb"]
extend-exclude = ["__init__.py"]
+fix = true
[tool.ruff.lint]
-extend-select = ["I"]
+select = [
+ "A", # flake8-builtins: Check for Python builtins being used as variables or parameters
+ "B", # flake8-bugbear: Find likely bugs and design problems
+ "E", # pycodestyle errors
+ "W", # pycodestyle warnings
+ "F", # pyflakes: Detect various errors by parsing the source file
+ "I", # isort: Check and enforce import ordering
+ "ISC", # flake8-implicit-str-concat: Check for implicit string concatenation
+ "TID", # flake8-tidy-imports: Validate import hygiene
+ "UP", # pyupgrade: Automatically upgrade syntax for newer versions of Python
+]
+
ignore = ["E501","E741"]
+per-file-ignores = {"**.ipynb" = ["E402", "E703"]}
-[tool.ruff.lint.per-file-ignores]
-"**.ipynb" = ["E402", "E703"]
+[tool.ruff.lint.flake8-tidy-imports]
+ban-relative-imports = "all"
diff --git a/tests/examples/test_examples.py b/tests/examples/test_examples.py
index 1c45be840..2bebc6fc6 100644
--- a/tests/examples/test_examples.py
+++ b/tests/examples/test_examples.py
@@ -12,14 +12,14 @@ class TestExamples:
"""
def list_of_examples():
- list = []
+ examples_list = []
path_to_example_scripts = os.path.join(
pybop.script_path, "..", "examples", "scripts"
)
for example in os.listdir(path_to_example_scripts):
if example.endswith(".py"):
- list.append(os.path.join(path_to_example_scripts, example))
- return list
+ examples_list.append(os.path.join(path_to_example_scripts, example))
+ return examples_list
@pytest.mark.parametrize("example", list_of_examples())
@pytest.mark.examples
diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py
index 9c4eac13d..618b8ad53 100644
--- a/tests/unit/test_dataset.py
+++ b/tests/unit/test_dataset.py
@@ -20,7 +20,7 @@ def test_dataset(self):
data_dictionary = {
"Time [s]": solution["Time [s]"].data,
"Current [A]": solution["Current [A]"].data,
- "Terminal voltage [V]": solution["Terminal voltage [V]"].data,
+ "Voltage [V]": solution["Voltage [V]"].data,
}
dataset = pybop.Dataset(data_dictionary)
@@ -55,4 +55,4 @@ def test_dataset(self):
dataset["Time"]
# Test conversion of single signal to list
- assert dataset.check(signal="Terminal voltage [V]")
+ assert dataset.check()
diff --git a/tests/unit/test_observer_unscented_kalman.py b/tests/unit/test_observer_unscented_kalman.py
index ce60abbc0..0b5d3067b 100644
--- a/tests/unit/test_observer_unscented_kalman.py
+++ b/tests/unit/test_observer_unscented_kalman.py
@@ -156,3 +156,22 @@ def test_wrong_input_shapes(self, model, parameters):
pybop.UnscentedKalmanFilterObserver(
parameters, model, sigma0, process, measure, signal=signal
)
+
+ @pytest.mark.unit
+ def test_without_signal(self):
+ model = pybop.lithium_ion.SPM()
+ parameters = pybop.Parameters(
+ pybop.Parameter(
+ "Negative electrode active material volume fraction",
+ prior=pybop.Gaussian(0.5, 0.05),
+ )
+ )
+ model.build(parameters=parameters)
+ n = model.n_states
+ sigma0 = np.diag([1e-4] * n)
+ process = np.diag([1e-4] * n)
+ measure = np.diag([1e-4])
+ observer = pybop.UnscentedKalmanFilterObserver(
+ parameters, model, sigma0, process, measure
+ )
+ assert observer.signal == ["Voltage [V]"]
diff --git a/tests/unit/test_optimisation.py b/tests/unit/test_optimisation.py
index 8444159b9..c61d2fae2 100644
--- a/tests/unit/test_optimisation.py
+++ b/tests/unit/test_optimisation.py
@@ -236,7 +236,7 @@ def test_optimiser_kwargs(self, cost, optimiser):
assert optim.pints_optimiser._lambda == 0.1
# Incorrect values
- for i, match in (("Value", -1),):
+ for i, _match in (("Value", -1),):
with pytest.raises(
Exception, match="must be a numeric value between 0 and 1."
):
@@ -253,7 +253,7 @@ def test_optimiser_kwargs(self, cost, optimiser):
# Check defaults
assert optim.pints_optimiser.n_hyper_parameters() == 5
assert optim.pints_optimiser.x_guessed() == optim.pints_optimiser._x0
- with pytest.raises(Exception):
+ with pytest.raises(RuntimeError):
optim.pints_optimiser.tell([0.1])
else:
@@ -326,12 +326,8 @@ def test_default_optimiser(self, cost):
optim = pybop.Optimisation(cost=cost)
assert optim.name() == "Exponential Natural Evolution Strategy (xNES)"
- # Test incorrect setting attribute
- with pytest.raises(
- AttributeError,
- match="'Optimisation' object has no attribute 'not_a_valid_attribute'",
- ):
- optim.not_a_valid_attribute
+ # Test getting incorrect attribute
+ assert not hasattr(optim, "not_a_valid_attribute")
@pytest.mark.unit
def test_incorrect_optimiser_class(self, cost):
diff --git a/tests/unit/test_parameters.py b/tests/unit/test_parameters.py
index ebfccea12..90c43622c 100644
--- a/tests/unit/test_parameters.py
+++ b/tests/unit/test_parameters.py
@@ -130,8 +130,8 @@ def test_parameters_construction(self, parameter):
with pytest.raises(
ValueError,
match="There is already a parameter with the name "
- + "Negative electrode active material volume fraction"
- + " in the Parameters object. Please remove the duplicate entry.",
+ "Negative electrode active material volume fraction"
+ " in the Parameters object. Please remove the duplicate entry.",
):
params.add(parameter)
@@ -158,8 +158,8 @@ def test_parameters_construction(self, parameter):
with pytest.raises(
ValueError,
match="There is already a parameter with the name "
- + "Negative electrode active material volume fraction"
- + " in the Parameters object. Please remove the duplicate entry.",
+ "Negative electrode active material volume fraction"
+ " in the Parameters object. Please remove the duplicate entry.",
):
params.add(
dict(
diff --git a/tests/unit/test_plots.py b/tests/unit/test_plots.py
index 4c7e14d42..79015c006 100644
--- a/tests/unit/test_plots.py
+++ b/tests/unit/test_plots.py
@@ -66,7 +66,7 @@ def test_dataset_plots(self, dataset):
dataset["Voltage [V]"],
trace_names=["Time [s]", "Voltage [V]"],
)
- pybop.plot_dataset(dataset, signal=["Voltage [V]"])
+ pybop.plot_dataset(dataset)
@pytest.fixture
def fitting_problem(self, model, parameters, dataset):