PyBaMM-GEM 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. pybamm_gem-0.2.2/.github/workflows/ci.yml +63 -0
  2. pybamm_gem-0.2.2/.github/workflows/monthly-report.yml +63 -0
  3. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/.github/workflows/release.yml +3 -3
  4. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/CHANGELOG.md +8 -0
  5. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/PKG-INFO +51 -14
  6. pybamm_gem-0.2.2/README.md +97 -0
  7. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/pyproject.toml +2 -2
  8. pybamm_gem-0.2.2/scripts/health_report.py +135 -0
  9. pybamm_gem-0.2.2/tests/test_zoo_contract.py +30 -0
  10. pybamm_gem-0.2.1/.github/workflows/ci.yml +0 -53
  11. pybamm_gem-0.2.1/README.md +0 -61
  12. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/.gitignore +0 -0
  13. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/LICENSE.txt +0 -0
  14. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/LICENSES-bundled.txt +0 -0
  15. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/examples/higher_dimensional_models.ipynb +0 -0
  16. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/__init__.py +0 -0
  17. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/_registry.py +0 -0
  18. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/CITATION.bib +0 -0
  19. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/README.md +0 -0
  20. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/__init__.py +0 -0
  21. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/examples/run_dfn_2d.py +0 -0
  22. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/model.py +0 -0
  23. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/model.toml +0 -0
  24. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_2d/tests/test_dfn_2d.py +0 -0
  25. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/CITATION.bib +0 -0
  26. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/README.md +0 -0
  27. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/__init__.py +0 -0
  28. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/examples/run_dfn_3d.py +0 -0
  29. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/model.py +0 -0
  30. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/model.toml +0 -0
  31. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/dfn_3d/tests/test_dfn_3d.py +0 -0
  32. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/lithium_ion/__init__.py +0 -0
  33. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/CITATION.bib +0 -0
  34. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/README.md +0 -0
  35. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/__init__.py +0 -0
  36. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/examples/run_spm_2d.py +0 -0
  37. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/model.py +0 -0
  38. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/model.toml +0 -0
  39. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_2d/tests/test_spm_2d.py +0 -0
  40. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/CITATION.bib +0 -0
  41. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/README.md +0 -0
  42. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/__init__.py +0 -0
  43. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/examples/run_spm_3d.py +0 -0
  44. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/model.py +0 -0
  45. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/model.toml +0 -0
  46. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/src/pybamm_gem/spm_3d/tests/test_spm_3d.py +0 -0
  47. {pybamm_gem-0.2.1 → pybamm_gem-0.2.2}/tests/test_registry.py +0 -0
@@ -0,0 +1,63 @@
1
+ # Runs on every push and pull request, and every Monday against the newest PyBaMM and the newest
2
+ # PyBaMM model zoo (pybamm-model-zoo): ruff, GEM's tests and the zoo's contract checks.
3
+ # Weekly runs only: if a check fails, ONE issue is opened (or commented on) and @mohammedasher is
4
+ # mentioned, so GitHub emails him. When the weekly run passes again, the issue is closed.
5
+ # It never changes any code.
6
+ name: CI
7
+
8
+ on:
9
+ push:
10
+ pull_request:
11
+ schedule:
12
+ - cron: "17 6 * * 1"
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+ issues: write
18
+
19
+ jobs:
20
+ test:
21
+ name: Newest PyBaMM and model zoo
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+ - name: Install
29
+ run: |
30
+ pip install --upgrade pip
31
+ pip install --upgrade pybamm pybamm-model-zoo
32
+ pip install -e ".[dev]"
33
+ python -c "import pybamm, pybamm_model_zoo; print('PyBaMM', pybamm.__version__, ' zoo', pybamm_model_zoo.__version__)"
34
+ - name: Lint
35
+ run: ruff check src tests scripts
36
+ - name: Test (GEM's tests and the zoo's contract checks)
37
+ run: pytest
38
+
39
+ report:
40
+ name: Weekly report
41
+ needs: [test]
42
+ if: ${{ always() && github.event_name == 'schedule' }}
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - name: Open, update or close the "Weekly check failed" issue
46
+ env:
47
+ GH_TOKEN: ${{ github.token }}
48
+ REPO: ${{ github.repository }}
49
+ RESULT: ${{ needs.test.result }}
50
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
51
+ run: |
52
+ TITLE="Weekly check failed"
53
+ NUMBER=$(gh issue list --repo "$REPO" --state open --search "$TITLE in:title" --json number --jq '.[0].number')
54
+ if [ "$RESULT" = "success" ]; then
55
+ if [ -n "$NUMBER" ]; then
56
+ gh issue comment "$NUMBER" --repo "$REPO" --body "Passing again with the newest PyBaMM and model zoo: $RUN_URL"
57
+ gh issue close "$NUMBER" --repo "$REPO"
58
+ fi
59
+ elif [ -z "$NUMBER" ]; then
60
+ gh issue create --repo "$REPO" --title "$TITLE" --body "@mohammedasher the weekly check against the newest PyBaMM and model zoo failed: $RUN_URL"
61
+ else
62
+ gh issue comment "$NUMBER" --repo "$REPO" --body "@mohammedasher failed again: $RUN_URL"
63
+ fi
@@ -0,0 +1,63 @@
1
+ # On the 1st of every month: installs PyBaMM-GEM from PyPI (what users get) with the newest
2
+ # PyBaMM and model zoo, runs the tests and scripts/health_report.py, and posts the result as a
3
+ # comment on the pinned "Monthly health report" issue, mentioning the people below so GitHub
4
+ # emails them. It never changes any code.
5
+ name: Monthly health report
6
+
7
+ on:
8
+ schedule:
9
+ - cron: "0 7 1 * *"
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+ issues: write
15
+ actions: read
16
+
17
+ jobs:
18
+ report:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.12"
25
+ - name: Install PyBaMM-GEM from PyPI with the newest PyBaMM and model zoo
26
+ run: |
27
+ pip install --upgrade pip
28
+ pip install --upgrade pybamm-gem pybamm pybamm-model-zoo pytest
29
+ - name: Run the tests and the health report
30
+ run: |
31
+ cd /tmp
32
+ pytest --import-mode=importlib --pyargs pybamm_gem -q > tests.txt 2>&1 || true
33
+ python "$GITHUB_WORKSPACE/scripts/health_report.py" report.md
34
+ - name: Post the report
35
+ env:
36
+ GH_TOKEN: ${{ github.token }}
37
+ REPO: ${{ github.repository }}
38
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
39
+ PEOPLE: "@gjo97 @MonicaMarinescu @mohammedasher"
40
+ run: |
41
+ cd /tmp
42
+ WEEKLY=$(gh run list --repo "$REPO" --workflow ci.yml --event schedule --limit 4 --json conclusion --jq '[.[].conclusion] | join(", ")')
43
+ {
44
+ echo "## PyBaMM-GEM health report, $(date -u +%Y-%m)"
45
+ echo
46
+ echo "$PEOPLE: the monthly check of PyBaMM-GEM (as installed from PyPI) with the newest PyBaMM and PyBaMM model zoo."
47
+ echo
48
+ cat report.md
49
+ echo
50
+ echo "**Model tests:** $(tail -n 1 tests.txt)"
51
+ echo
52
+ echo "**Last weekly checks (newest first):** ${WEEKLY:-none yet}"
53
+ echo
54
+ echo "Details: $RUN_URL"
55
+ } > body.md
56
+ TITLE="Monthly health report"
57
+ NUMBER=$(gh issue list --repo "$REPO" --state open --search "$TITLE in:title" --json number --jq '.[0].number')
58
+ if [ -z "$NUMBER" ]; then
59
+ URL=$(gh issue create --repo "$REPO" --title "$TITLE" --body "A health report of PyBaMM-GEM is added here as a comment on the 1st of every month.")
60
+ NUMBER=${URL##*/}
61
+ gh issue pin "$NUMBER" --repo "$REPO" || true
62
+ fi
63
+ gh issue comment "$NUMBER" --repo "$REPO" --body-file body.md
@@ -76,9 +76,9 @@ jobs:
76
76
  run: |
77
77
  VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
78
78
  pip install "pybamm[cite]>=26.9" pytest
79
- # A new upload can take a few minutes to appear on TestPyPI
80
- for attempt in 1 2 3 4 5 6 7 8 9 10; do
81
- if pip install --no-deps --index-url https://test.pypi.org/simple/ "pybamm-gem==$VERSION"; then
79
+ # A new upload can take up to 15 minutes to appear on TestPyPI
80
+ for attempt in $(seq 1 30); do
81
+ if pip install --no-cache-dir --no-deps --index-url https://test.pypi.org/simple/ "pybamm-gem==$VERSION"; then
82
82
  break
83
83
  fi
84
84
  sleep 30
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.2
4
+
5
+ - README: the models first, then installation and usage, then a description of PyBaMM-GEM.
6
+ - Tests: the PyBaMM model zoo's contract checks run on every GEM model
7
+ (`pybamm-model-zoo` added to the `dev` extra).
8
+ - CI: weekly checks against the newest PyBaMM and PyBaMM model zoo, and a monthly health report.
9
+ - Release workflow: waits up to 15 minutes for TestPyPI to list a new upload.
10
+
3
11
  ## 0.2.1
4
12
 
5
13
  - `pybamm_gem` now has the same commands as the PyBaMM model zoo: `require()` is new, and
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: PyBaMM-GEM
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Spatially resolved (2D and 3D) battery models for PyBaMM
5
5
  Author: Mohammed Asheruddin N
6
6
  License-Expression: BSD-3-Clause
@@ -11,32 +11,40 @@ Requires-Python: >=3.10
11
11
  Requires-Dist: pybamm[cite]>=26.9
12
12
  Requires-Dist: tomli>=2.0.1; python_version < '3.11'
13
13
  Provides-Extra: dev
14
+ Requires-Dist: pybamm-model-zoo; extra == 'dev'
14
15
  Requires-Dist: pytest; extra == 'dev'
15
16
  Requires-Dist: ruff; extra == 'dev'
16
17
  Description-Content-Type: text/markdown
17
18
 
18
19
  # PyBaMM-GEM
19
20
 
20
- Spatially resolved (2D and 3D) battery models built on [PyBaMM](https://pybamm.org), laid out
21
- like the PyBaMM model zoo: one folder per model, each with a `model.toml` manifest, a
22
- `CITATION.bib`, a README, tests and an example.
21
+ An open-source extension package for PyBaMM providing advanced battery models, degradation
22
+ models, and simulation tools.
23
23
 
24
24
  ## Models
25
25
 
26
- | Slug | Class | What it is |
26
+ ```python
27
+ import pybamm_gem as gem
28
+
29
+ print(gem.list_models())
30
+ # ['dfn_2d', 'dfn_3d', 'spm_2d', 'spm_3d']
31
+ ```
32
+
33
+ | Model | Class | What it is |
27
34
  |---|---|---|
28
- | `spm_2d` | `BasicSPM2D` | Single Particle Model with a pair of particles at every height z |
29
- | `spm_3d` | `BasicSPM3D` | The same, over a y-z grid of points |
30
35
  | `dfn_2d` | `DFN2D` | Doyle-Fuller-Newman model resolved in x and z |
31
36
  | `dfn_3d` | `DFN3D` | The same, resolved in x, y and z |
37
+ | `spm_2d` | `BasicSPM2D` | Single Particle Model with a pair of particles at every height z |
38
+ | `spm_3d` | `BasicSPM3D` | The same, over a y-z grid of points |
32
39
 
33
40
  ## Installation
34
41
 
35
42
  ```
36
- pip install git+https://github.com/ImperialCollegeLondon/PyBaMM-GEM
43
+ pip install pybamm-gem
37
44
  ```
38
45
 
39
- PyBaMM 26.9 or newer is needed.
46
+ PyBaMM 26.9 or newer is needed. To get the newest code from GitHub instead:
47
+ `pip install git+https://github.com/ImperialCollegeLondon/PyBaMM-GEM`
40
48
 
41
49
  ## Usage
42
50
 
@@ -63,16 +71,45 @@ listed by `pybamm_model_zoo.list_models()`.
63
71
  The notebook `examples/higher_dimensional_models.ipynb` runs all four models, compares them with
64
72
  the stock PyBaMM models and shows a temperature that changes with height.
65
73
 
66
- ## Licence
74
+ ## About PyBaMM-GEM
67
75
 
68
- BSD 3-Clause, see `LICENSE.txt`. Copyright (c) 2026, Imperial College London.
69
- Some of the model code is adapted from PyBaMM; see `LICENSES-bundled.txt`.
76
+ PyBaMM-GEM is an open, collaborative home for battery models that extend
77
+ [PyBaMM](https://pybamm.org). Many new models are experimental, specialised or still under active
78
+ research, which makes them unsuitable for the core PyBaMM project in their early stages. GEM is
79
+ where they can be developed, validated, compared and shared, while staying close to PyBaMM. Some
80
+ GEM models may later move into PyBaMM; others stay in GEM because they answer specialised
81
+ questions. Both outcomes count as success.
82
+
83
+ **Stay close to PyBaMM. Explore beyond it.** GEM models follow PyBaMM's design, options and user
84
+ experience, so PyBaMM users feel at home. Where a GEM model differs scientifically from a PyBaMM
85
+ model, it is a separate, explicitly named model. Every release states the PyBaMM versions it
86
+ supports.
87
+
88
+ GEM stands for **General Enough Model** and **Good Enough Model**: the fewest physical processes
89
+ needed to explain the behaviour of interest. The name also honours Professor John B. Goodenough.
90
+
91
+ The models are laid out like the PyBaMM model zoo: one folder per model, each with a `model.toml`
92
+ manifest, a `CITATION.bib`, a README, tests and an example.
93
+
94
+ ## Automatic checks
95
+
96
+ - **Every push and pull request, and every Monday:** ruff, GEM's tests and the PyBaMM model zoo's
97
+ contract checks, against the newest PyBaMM and `pybamm-model-zoo`. If the Monday run fails, an
98
+ issue "Weekly check failed" is opened; it is closed when the check passes again.
99
+ - **1st of every month:** a health report of the released package (installed from PyPI) with the
100
+ newest PyBaMM and model zoo, posted on the pinned issue "Monthly health report". It can also be
101
+ run by hand with `python scripts/health_report.py`.
70
102
 
71
103
  ## Releasing a new version
72
104
 
73
- 1. In a pull request, raise `version` in `pyproject.toml` (for example `0.2.1`) and add a
105
+ 1. In a pull request, raise `version` in `pyproject.toml` (for example `0.2.2`) and add a
74
106
  `CHANGELOG.md` entry. Merge it.
75
- 2. On GitHub, go to Releases, then "Draft a new release". Create the tag `v0.2.1` (a "v" and
107
+ 2. On GitHub, go to Releases, then "Draft a new release". Create the tag `v0.2.2` (a "v" and
76
108
  the version), add a title and notes, and publish.
77
109
  3. The Release workflow builds and tests the package, uploads it to TestPyPI and tests it again.
78
110
  It then waits for a maintainer to approve the upload to PyPI (GitHub sends an email).
111
+
112
+ ## Licence
113
+
114
+ BSD 3-Clause, see `LICENSE.txt`. Copyright (c) 2026, Imperial College London.
115
+ Some of the model code is adapted from PyBaMM; see `LICENSES-bundled.txt`.
@@ -0,0 +1,97 @@
1
+ # PyBaMM-GEM
2
+
3
+ An open-source extension package for PyBaMM providing advanced battery models, degradation
4
+ models, and simulation tools.
5
+
6
+ ## Models
7
+
8
+ ```python
9
+ import pybamm_gem as gem
10
+
11
+ print(gem.list_models())
12
+ # ['dfn_2d', 'dfn_3d', 'spm_2d', 'spm_3d']
13
+ ```
14
+
15
+ | Model | Class | What it is |
16
+ |---|---|---|
17
+ | `dfn_2d` | `DFN2D` | Doyle-Fuller-Newman model resolved in x and z |
18
+ | `dfn_3d` | `DFN3D` | The same, resolved in x, y and z |
19
+ | `spm_2d` | `BasicSPM2D` | Single Particle Model with a pair of particles at every height z |
20
+ | `spm_3d` | `BasicSPM3D` | The same, over a y-z grid of points |
21
+
22
+ ## Installation
23
+
24
+ ```
25
+ pip install pybamm-gem
26
+ ```
27
+
28
+ PyBaMM 26.9 or newer is needed. To get the newest code from GitHub instead:
29
+ `pip install git+https://github.com/ImperialCollegeLondon/PyBaMM-GEM`
30
+
31
+ ## Usage
32
+
33
+ ```python
34
+ import pybamm
35
+ import pybamm_gem as gem
36
+
37
+ print(gem.list_models())
38
+ model = gem.load("spm_2d")()
39
+ simulation = pybamm.Simulation(model)
40
+ solution = simulation.solve([0, 3000])
41
+ print(solution["Voltage [V]"](1500))
42
+ ```
43
+
44
+ The classes are also available directly, for example `gem.lithium_ion.BasicSPM2D` or
45
+ `gem.lithium_ion.DFN2D`.
46
+
47
+ The commands are the same as in the PyBaMM model zoo (`pybamm_model_zoo`): `list_models()`,
48
+ `info()`, `load()`, `require()` and `register_citation()`. `info()`, `load()`, `require()` and
49
+ `register_citation()` take either the slug (`"spm_2d"`) or the class name (`"BasicSPM2D"`);
50
+ `list_models()` returns the slugs. With `pybamm-model-zoo` installed, the GEM models are also
51
+ listed by `pybamm_model_zoo.list_models()`.
52
+
53
+ The notebook `examples/higher_dimensional_models.ipynb` runs all four models, compares them with
54
+ the stock PyBaMM models and shows a temperature that changes with height.
55
+
56
+ ## About PyBaMM-GEM
57
+
58
+ PyBaMM-GEM is an open, collaborative home for battery models that extend
59
+ [PyBaMM](https://pybamm.org). Many new models are experimental, specialised or still under active
60
+ research, which makes them unsuitable for the core PyBaMM project in their early stages. GEM is
61
+ where they can be developed, validated, compared and shared, while staying close to PyBaMM. Some
62
+ GEM models may later move into PyBaMM; others stay in GEM because they answer specialised
63
+ questions. Both outcomes count as success.
64
+
65
+ **Stay close to PyBaMM. Explore beyond it.** GEM models follow PyBaMM's design, options and user
66
+ experience, so PyBaMM users feel at home. Where a GEM model differs scientifically from a PyBaMM
67
+ model, it is a separate, explicitly named model. Every release states the PyBaMM versions it
68
+ supports.
69
+
70
+ GEM stands for **General Enough Model** and **Good Enough Model**: the fewest physical processes
71
+ needed to explain the behaviour of interest. The name also honours Professor John B. Goodenough.
72
+
73
+ The models are laid out like the PyBaMM model zoo: one folder per model, each with a `model.toml`
74
+ manifest, a `CITATION.bib`, a README, tests and an example.
75
+
76
+ ## Automatic checks
77
+
78
+ - **Every push and pull request, and every Monday:** ruff, GEM's tests and the PyBaMM model zoo's
79
+ contract checks, against the newest PyBaMM and `pybamm-model-zoo`. If the Monday run fails, an
80
+ issue "Weekly check failed" is opened; it is closed when the check passes again.
81
+ - **1st of every month:** a health report of the released package (installed from PyPI) with the
82
+ newest PyBaMM and model zoo, posted on the pinned issue "Monthly health report". It can also be
83
+ run by hand with `python scripts/health_report.py`.
84
+
85
+ ## Releasing a new version
86
+
87
+ 1. In a pull request, raise `version` in `pyproject.toml` (for example `0.2.2`) and add a
88
+ `CHANGELOG.md` entry. Merge it.
89
+ 2. On GitHub, go to Releases, then "Draft a new release". Create the tag `v0.2.2` (a "v" and
90
+ the version), add a title and notes, and publish.
91
+ 3. The Release workflow builds and tests the package, uploads it to TestPyPI and tests it again.
92
+ It then waits for a maintainer to approve the upload to PyPI (GitHub sends an email).
93
+
94
+ ## Licence
95
+
96
+ BSD 3-Clause, see `LICENSE.txt`. Copyright (c) 2026, Imperial College London.
97
+ Some of the model code is adapted from PyBaMM; see `LICENSES-bundled.txt`.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "PyBaMM-GEM"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  license = "BSD-3-Clause"
9
9
  license-files = ["LICENSE.txt", "LICENSES-bundled.txt"]
10
10
  description = "Spatially resolved (2D and 3D) battery models for PyBaMM"
@@ -18,7 +18,7 @@ dependencies = [
18
18
  ]
19
19
 
20
20
  [project.optional-dependencies]
21
- dev = ["pytest", "ruff"]
21
+ dev = ["pytest", "ruff", "pybamm-model-zoo"]
22
22
 
23
23
  # Lets the PyBaMM model zoo list these models too, if the zoo is installed.
24
24
  [project.entry-points."pybamm_zoo_models"]
@@ -0,0 +1,135 @@
1
+ # Monthly health report for PyBaMM-GEM (simple Python).
2
+ #
3
+ # It starts with the models from gem.list_models(). Then, for every GEM model, it checks:
4
+ # 1. the PyBaMM model zoo finds it and its contract checks pass,
5
+ # 2. it solves a 1C discharge, and how long that takes,
6
+ # 3. how far its voltage is from the matching stock PyBaMM model.
7
+ # It writes the result as Markdown to the file named on the command line (default report.md).
8
+ #
9
+ # How to use it:
10
+ # python scripts/health_report.py report.md
11
+
12
+ import sys
13
+ import time
14
+ import warnings
15
+
16
+ import numpy as np
17
+ import pybamm
18
+ import pybamm_model_zoo as zoo
19
+ from pybamm_model_zoo.testing import contract
20
+
21
+ import pybamm_gem as gem
22
+
23
+ OUTPUT = "report.md"
24
+ if len(sys.argv) > 1:
25
+ OUTPUT = sys.argv[1]
26
+
27
+ END_TIME = 3000 # seconds of a 1C discharge
28
+ POINTS = 3 # cells in each extra direction, kept small so the report runs quickly
29
+ TOLERANCE = 1e-3 # volts, the same as the model tests
30
+
31
+ warnings.simplefilter("ignore")
32
+
33
+
34
+ def stock_model(slug):
35
+ if slug.startswith("spm"):
36
+ return pybamm.lithium_ion.SPM()
37
+ return pybamm.lithium_ion.DFN()
38
+
39
+
40
+ def solve_gem_model(slug):
41
+ model_class = gem.load(slug)
42
+ if slug == "spm_3d":
43
+ model = model_class(points_y=POINTS, points_z=POINTS)
44
+ return pybamm.Simulation(model).solve([0, END_TIME])
45
+ if slug.startswith("spm"):
46
+ return pybamm.Simulation(model_class()).solve([0, END_TIME])
47
+ var_pts = dict(pybamm.lithium_ion.DFN().default_var_pts)
48
+ var_pts["z"] = POINTS
49
+ if slug == "dfn_3d":
50
+ var_pts["y"] = POINTS
51
+ return pybamm.Simulation(model_class(), var_pts=var_pts).solve([0, END_TIME])
52
+
53
+
54
+ lines = []
55
+
56
+ # The models, from gem.list_models() and each model's model.toml
57
+ lines.append("### Models in GEM")
58
+ lines.append("")
59
+ lines.append("`gem.list_models()` = `" + str(gem.list_models()) + "`")
60
+ lines.append("")
61
+ lines.append("| Model | Class | What it is |")
62
+ lines.append("|---|---|---|")
63
+ for slug in gem.list_models():
64
+ manifest = gem.info(slug)
65
+ lines.append("| `" + slug + "` | `" + manifest["name"] + "` | " + manifest["summary"] + " |")
66
+ lines.append("")
67
+
68
+ lines.append("### Health")
69
+ lines.append("")
70
+ lines.append("| | Version |")
71
+ lines.append("|---|---|")
72
+ lines.append("| PyBaMM-GEM | " + gem.__version__ + " |")
73
+ lines.append("| PyBaMM | " + pybamm.__version__ + " |")
74
+ lines.append("| pybamm-model-zoo | " + zoo.__version__ + " |")
75
+ lines.append("| Python | " + sys.version.split()[0] + " |")
76
+ lines.append("")
77
+ lines.append("| Model | Zoo checks | Solves | Solve time [s] | Voltage vs stock PyBaMM [mV] | Health |")
78
+ lines.append("|---|---|---|---|---|---|")
79
+
80
+ all_healthy = True
81
+ check_names = [check.name for check in contract.checks_in_scope(contract.MODEL)]
82
+ times = np.linspace(100, END_TIME - 100, 30)
83
+
84
+ for slug in gem.list_models():
85
+ class_name = gem.info(slug)["name"]
86
+
87
+ # 1. The zoo contract checks
88
+ failed_checks = []
89
+ if class_name not in zoo.list_models():
90
+ failed_checks.append("not found by the zoo")
91
+ else:
92
+ entry = zoo.info(class_name)
93
+ for name in check_names:
94
+ try:
95
+ contract.CHECKS[name].run(entry)
96
+ except Exception: # noqa: BLE001 (any failure is reported in the table)
97
+ failed_checks.append(name)
98
+ if failed_checks:
99
+ zoo_result = "failed: " + ", ".join(failed_checks)
100
+ else:
101
+ zoo_result = str(len(check_names)) + "/" + str(len(check_names)) + " pass"
102
+
103
+ # 2. and 3. Solve and compare with the stock model
104
+ solves = "yes"
105
+ solve_time = "-"
106
+ difference = "-"
107
+ healthy = len(failed_checks) == 0
108
+ try:
109
+ began = time.time()
110
+ solution = solve_gem_model(slug)
111
+ solve_time = str(round(time.time() - began, 1))
112
+ stock_solution = pybamm.Simulation(stock_model(slug)).solve([0, END_TIME])
113
+ largest = np.max(np.abs(solution["Voltage [V]"](times) - stock_solution["Voltage [V]"](times)))
114
+ difference = str(round(1000 * largest, 3))
115
+ if largest > TOLERANCE:
116
+ healthy = False
117
+ except Exception as error: # noqa: BLE001 (any failure is reported in the table)
118
+ solves = "no (" + type(error).__name__ + ")"
119
+ healthy = False
120
+
121
+ if not healthy:
122
+ all_healthy = False
123
+ health = "OK" if healthy else "PROBLEM"
124
+ lines.append("| " + slug + " (" + class_name + ") | " + zoo_result + " | " + solves + " | "
125
+ + solve_time + " | " + difference + " | " + health + " |")
126
+
127
+ lines.append("")
128
+ if all_healthy:
129
+ lines.append("**All models healthy.**")
130
+ else:
131
+ lines.append("**At least one model has a problem; see the table.**")
132
+
133
+ with open(OUTPUT, "w", encoding="utf-8") as file:
134
+ file.write("\n".join(lines) + "\n")
135
+ print("\n".join(lines))
@@ -0,0 +1,30 @@
1
+ """The PyBaMM model zoo's own checks (pybamm_model_zoo.testing.contract) on every GEM model.
2
+
3
+ These are the portable checks the zoo applies to models from other packages: manifest,
4
+ layout, import, citation, well_posed, build and solve. Skipped if pybamm-model-zoo is
5
+ not installed.
6
+ """
7
+
8
+ import pytest
9
+
10
+ pytest.importorskip("pybamm_model_zoo")
11
+
12
+ import pybamm_model_zoo as zoo
13
+ from pybamm_model_zoo.testing import contract
14
+
15
+ import pybamm_gem as gem
16
+
17
+ CHECK_NAMES = [check.name for check in contract.checks_in_scope(contract.MODEL)]
18
+
19
+
20
+ def test_the_zoo_finds_every_gem_model():
21
+ for slug in gem.list_models():
22
+ class_name = gem.info(slug)["name"]
23
+ assert class_name in zoo.list_models()
24
+
25
+
26
+ @pytest.mark.parametrize("slug", gem.list_models())
27
+ @pytest.mark.parametrize("check_name", CHECK_NAMES)
28
+ def test_zoo_contract(slug, check_name):
29
+ entry = zoo.info(gem.info(slug)["name"])
30
+ contract.CHECKS[check_name].run(entry)
@@ -1,53 +0,0 @@
1
- # Runs the tests on every push and pull request, and every Monday, against the latest
2
- # PyBaMM release. A failing scheduled run opens ONE issue (or adds a comment to the open
3
- # one). It never changes any code.
4
- name: CI
5
-
6
- on:
7
- push:
8
- pull_request:
9
- schedule:
10
- - cron: "17 6 * * 1"
11
- workflow_dispatch:
12
-
13
- permissions:
14
- contents: read
15
- issues: write
16
-
17
- jobs:
18
- release:
19
- name: PyBaMM release
20
- runs-on: ubuntu-latest
21
- steps:
22
- - uses: actions/checkout@v4
23
- - uses: actions/setup-python@v5
24
- with:
25
- python-version: "3.12"
26
- - name: Install
27
- run: |
28
- pip install --upgrade pip
29
- pip install -e ".[dev]"
30
- - name: Lint
31
- run: ruff check src tests
32
- - name: Test
33
- run: pytest
34
-
35
- report:
36
- name: Report a failure
37
- needs: [release]
38
- if: ${{ always() && github.event_name == 'schedule' && needs.release.result == 'failure' }}
39
- runs-on: ubuntu-latest
40
- steps:
41
- - name: Open an issue, or comment on the open one
42
- env:
43
- GH_TOKEN: ${{ github.token }}
44
- REPO: ${{ github.repository }}
45
- RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
46
- run: |
47
- TITLE="Weekly check failed"
48
- NUMBER=$(gh issue list --repo "$REPO" --state open --search "$TITLE in:title" --json number --jq '.[0].number')
49
- if [ -z "$NUMBER" ]; then
50
- gh issue create --repo "$REPO" --title "$TITLE" --body "The weekly check failed. See $RUN_URL"
51
- else
52
- gh issue comment "$NUMBER" --repo "$REPO" --body "Failed again. See $RUN_URL"
53
- fi
@@ -1,61 +0,0 @@
1
- # PyBaMM-GEM
2
-
3
- Spatially resolved (2D and 3D) battery models built on [PyBaMM](https://pybamm.org), laid out
4
- like the PyBaMM model zoo: one folder per model, each with a `model.toml` manifest, a
5
- `CITATION.bib`, a README, tests and an example.
6
-
7
- ## Models
8
-
9
- | Slug | Class | What it is |
10
- |---|---|---|
11
- | `spm_2d` | `BasicSPM2D` | Single Particle Model with a pair of particles at every height z |
12
- | `spm_3d` | `BasicSPM3D` | The same, over a y-z grid of points |
13
- | `dfn_2d` | `DFN2D` | Doyle-Fuller-Newman model resolved in x and z |
14
- | `dfn_3d` | `DFN3D` | The same, resolved in x, y and z |
15
-
16
- ## Installation
17
-
18
- ```
19
- pip install git+https://github.com/ImperialCollegeLondon/PyBaMM-GEM
20
- ```
21
-
22
- PyBaMM 26.9 or newer is needed.
23
-
24
- ## Usage
25
-
26
- ```python
27
- import pybamm
28
- import pybamm_gem as gem
29
-
30
- print(gem.list_models())
31
- model = gem.load("spm_2d")()
32
- simulation = pybamm.Simulation(model)
33
- solution = simulation.solve([0, 3000])
34
- print(solution["Voltage [V]"](1500))
35
- ```
36
-
37
- The classes are also available directly, for example `gem.lithium_ion.BasicSPM2D` or
38
- `gem.lithium_ion.DFN2D`.
39
-
40
- The commands are the same as in the PyBaMM model zoo (`pybamm_model_zoo`): `list_models()`,
41
- `info()`, `load()`, `require()` and `register_citation()`. `info()`, `load()`, `require()` and
42
- `register_citation()` take either the slug (`"spm_2d"`) or the class name (`"BasicSPM2D"`);
43
- `list_models()` returns the slugs. With `pybamm-model-zoo` installed, the GEM models are also
44
- listed by `pybamm_model_zoo.list_models()`.
45
-
46
- The notebook `examples/higher_dimensional_models.ipynb` runs all four models, compares them with
47
- the stock PyBaMM models and shows a temperature that changes with height.
48
-
49
- ## Licence
50
-
51
- BSD 3-Clause, see `LICENSE.txt`. Copyright (c) 2026, Imperial College London.
52
- Some of the model code is adapted from PyBaMM; see `LICENSES-bundled.txt`.
53
-
54
- ## Releasing a new version
55
-
56
- 1. In a pull request, raise `version` in `pyproject.toml` (for example `0.2.1`) and add a
57
- `CHANGELOG.md` entry. Merge it.
58
- 2. On GitHub, go to Releases, then "Draft a new release". Create the tag `v0.2.1` (a "v" and
59
- the version), add a title and notes, and publish.
60
- 3. The Release workflow builds and tests the package, uploads it to TestPyPI and tests it again.
61
- It then waits for a maintainer to approve the upload to PyPI (GitHub sends an email).
File without changes
File without changes