Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v25.1.1 #4781

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push Docker image to Docker Hub
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0
with:
context: .
file: scripts/Dockerfile
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/run_periodic_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo dot -c
sudo apt-get install gfortran gcc graphviz pandoc
sudo apt-get install libopenblas-dev texlive-latex-extra dvipng

- name: Install macOS system dependencies
Expand Down Expand Up @@ -100,6 +100,7 @@ jobs:
- name: Install Linux system dependencies
run: |
sudo apt-get update
sudo apt-get install graphviz pandoc
sudo apt-get install texlive-latex-extra dvipng

- name: Set up Python
Expand Down Expand Up @@ -132,6 +133,7 @@ jobs:
- name: Install Linux system dependencies
run: |
sudo apt-get update
sudo apt-get install gfortran gcc graphviz pandoc
sudo apt-get install libopenblas-dev texlive-latex-extra dvipng

- name: Set up Python 3.12
Expand Down Expand Up @@ -161,6 +163,7 @@ jobs:
- name: Install Linux system dependencies
run: |
sudo apt-get update
sudo apt-get install gfortran gcc graphviz
sudo apt-get install libopenblas-dev texlive-latex-extra dvipng

- name: Set up Python 3.12
Expand Down
39 changes: 0 additions & 39 deletions .github/workflows/update_license.yml

This file was deleted.

4 changes: 1 addition & 3 deletions .github/workflows/validation_benchmarks.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
name: Alert validation repository
on:
workflow_dispatch:
release:
types:
- published
push:
branches:
- develop

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ci:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.9.1"
rev: "v0.9.2"
hooks:
- id: ruff
args: [--fix, --show-fixes]
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# [Unreleased](https://github.com/pybamm-team/PyBaMM/)

# [v25.1.1](https://github.com/pybamm-team/PyBaMM/tree/v25.1.1) - 2025-01-20

## Features
kratman marked this conversation as resolved.
Show resolved Hide resolved
- Added Operators to current and voltage termination events. ([#4770](https://github.com/pybamm-team/PyBaMM/pull/4770))

# [v25.1.0](https://github.com/pybamm-team/PyBaMM/tree/v25.1.0) - 2025-01-14

## Features
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ keywords:
- "expression tree"
- "python"
- "symbolic differentiation"
version: "25.1.0"
version: "25.1.1"
repository-code: "https://github.com/pybamm-team/PyBaMM"
title: "Python Battery Mathematical Modelling (PyBaMM)"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pybamm"
version = "25.1.0"
version = "25.1.1"
license = { file = "LICENSE.txt" }
description = "Python Battery Mathematical Modelling"
authors = [{name = "The PyBaMM Team", email = "[email protected]"}]
Expand Down
2 changes: 1 addition & 1 deletion src/pybamm/experiment/step/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .steps import *
from .base_step import BaseStep, BaseStepExplicit, BaseStepImplicit
from .step_termination import *
from .step_termination import BaseTermination, CurrentTermination, VoltageTermination, CustomTermination, CrateTermination, _read_termination

__all__ = ['base_step', 'step_termination', 'steps']
14 changes: 10 additions & 4 deletions src/pybamm/experiment/step/base_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,14 @@ def __init__(
tags=None,
start_time=None,
description=None,
direction=None,
direction: str | None = None,
):
potential_directions = ["charge", "discharge", "rest", None]
if direction not in potential_directions:
raise ValueError(
f"Invalid direction: {direction}. Must be one of {potential_directions}"
)
self.input_duration = duration
self.input_duration = duration
self.input_value = value
# Check if drive cycle
Expand Down Expand Up @@ -386,11 +392,11 @@ def value_based_charge_or_discharge(self):
init_curr = self.value
sign = np.sign(init_curr)
if sign == 0:
return "Rest"
return "rest"
elif sign > 0:
return "Discharge"
return "discharge"
else:
return "Charge"
return "charge"

def record_tags(
self,
Expand Down
57 changes: 47 additions & 10 deletions src/pybamm/experiment/step/step_termination.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ class BaseTermination:
The value at which the event is triggered
"""

def __init__(self, value):
def __init__(self, value, operator=None):
self.value = value
if operator not in ["<", ">", None]:
raise ValueError(f"Invalid operator: {operator}")
self.operator = operator

def get_event(self, variables, step):
"""
Expand Down Expand Up @@ -67,9 +70,19 @@ def get_event(self, variables, step):
"""
See :meth:`BaseTermination.get_event`
"""
operator = self.operator
if operator == ">":
expr = self.value - variables["Current [A]"]
event_string = f"Current [A] > {self.value} [A] [experiment]"
elif operator == "<":
expr = variables["Current [A]"] - self.value
event_string = f"Current [A] < {self.value} [A] [experiment]"
else:
expr = abs(variables["Current [A]"]) - self.value
event_string = f"abs(Current [A]) < {self.value} [A] [experiment]"
event = pybamm.Event(
"Current cut-off [A] [experiment]",
abs(variables["Current [A]"]) - self.value,
event_string,
expr,
)
return event

Expand All @@ -89,24 +102,48 @@ def get_event(self, variables, step):
# figure out whether the voltage event is greater than the starting
# voltage (charge) or less (discharge) and set the sign of the
# event accordingly
direction = step.direction.capitalize()
if direction == "Charge":
operator = self.operator
if operator is None:
direction = step.direction
if direction == "charge":
operator = ">"
elif direction == "discharge":
operator = "<"
else:
# No event for rest steps
return None

if operator == ">":
sign = -1
elif direction == "Discharge":
else:
# operator can only be "<" or ">"
sign = 1
elif direction == "Rest":
# No event for rest steps
return None

# Event should be positive at initial conditions for both
# charge and discharge
event = pybamm.Event(
f"{direction} voltage cut-off [V] [experiment]",
f"Voltage {operator} {self.value} [V] [experiment]",
sign * (variables["Battery voltage [V]"] - self.value),
)
return event


class Voltage:
def __gt__(self, value):
return VoltageTermination(value, operator=">")

def __lt__(self, value):
return VoltageTermination(value, operator="<")


class Current:
def __gt__(self, value):
return CurrentTermination(value, operator=">")

def __lt__(self, value):
return CurrentTermination(value, operator="<")


class CustomTermination(BaseTermination):
"""
Define a custom termination event using a function. This can be used to create an
Expand Down
1 change: 0 additions & 1 deletion src/pybamm/models/submodels/interface/sei/sei_growth.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ def get_coupled_variables(self, variables):
# j = -F * c_0* k_exp() / (1 + L * k_exp() / D)
# c_ec = c_0 - L * k_exp() / D / (1 + L * k_exp() / D)
# = c_0 / (1 + L * k_exp() / D)
eta_SEI = delta_phi
k_exp = phase_param.k_sei * pybamm.exp(-alpha_SEI * F_RT * eta_SEI)
L_over_D = L_sei / phase_param.D_ec
c_0 = phase_param.c_ec_0
Expand Down
7 changes: 4 additions & 3 deletions src/pybamm/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,6 @@ def solve(
logs["summary variables"] = cycle_sum_vars

# Calculate capacity_start using the first cycle
capacity_stop = None
if cycle_num == 1:
# Note capacity_start could be defined as
# self._parameter_values["Nominal cell capacity [A.h]"] instead
Expand All @@ -907,6 +906,8 @@ def solve(
capacity_stop = value
elif typ == "%":
capacity_stop = value / 100 * capacity_start
else:
capacity_stop = None
logs["stopping conditions"]["capacity"] = capacity_stop

logs["elapsed time"] = timer.time()
Expand Down Expand Up @@ -1022,8 +1023,8 @@ def step(
def _get_esoh_solver(self, calc_esoh):
if (
calc_esoh is False
or isinstance(self._model, pybamm.lead_acid.BaseModel)
or isinstance(self._model, pybamm.equivalent_circuit.Thevenin)
or not isinstance(self._model, pybamm.lithium_ion.BaseModel)
or self._model.options["particle phases"] not in ["1", ("1", "1")]
or self._model.options["working electrode"] != "both"
):
return None
Expand Down
2 changes: 1 addition & 1 deletion src/pybamm/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "25.1.0"
__version__ = "25.1.1"
39 changes: 39 additions & 0 deletions tests/unit/test_experiments/test_experiment_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,42 @@ def custom_step_voltage(variables):

with pytest.raises(ValueError, match="control must be"):
pybamm.step.CustomStepImplicit(custom_step_voltage, control="bla")

def test_bad_direction(self):
with pytest.raises(ValueError, match="Invalid direction"):
pybamm.step.Voltage(4.1, direction="foo")

def test_steps_with_operators(self):
# voltage
step = pybamm.step.voltage(1, duration=3600)
termination_lt_4_1 = pybamm.step.VoltageTermination(4.1, operator="<")
termination_gt_4_1 = pybamm.step.VoltageTermination(4.1, operator=">")
variables = {"Battery voltage [V]": 4.2}
event_lt_4_1 = termination_lt_4_1.get_event(variables, step)
np.testing.assert_allclose(event_lt_4_1.expression, 4.2 - 4.1)
event_gt_4_1 = termination_gt_4_1.get_event(variables, step)
np.testing.assert_allclose(event_gt_4_1.expression, 4.1 - 4.2)

# current
step = pybamm.step.current(1, duration=3600)
termination_lt_0_05 = pybamm.step.CurrentTermination(0.05, operator="<")
termination_gt_0_05 = pybamm.step.CurrentTermination(0.05, operator=">")
variables = {"Current [A]": 0.06}
event_lt_0_05 = termination_lt_0_05.get_event(variables, step)
np.testing.assert_allclose(event_lt_0_05.expression, 0.06 - 0.05)
event_gt_0_05 = termination_gt_0_05.get_event(variables, step)
np.testing.assert_allclose(event_gt_0_05.expression, 0.05 - 0.06)

# error
with pytest.raises(ValueError, match="Invalid operator"):
pybamm.step.CurrentTermination(0.05, operator="=")

# operator overloading
termination_lt_0_05_oo = pybamm.step.step_termination.Current() < 0.05
termination_gt_0_05_oo = pybamm.step.step_termination.Current() > 0.05
assert termination_lt_0_05_oo == termination_gt_0_05
assert termination_gt_0_05_oo == termination_gt_0_05
termination_lt_4_1_oo = pybamm.step.step_termination.Voltage() < 4.1
termination_gt_4_1_oo = pybamm.step.step_termination.Voltage() > 4.1
assert termination_lt_4_1_oo == termination_gt_4_1
assert termination_gt_4_1_oo == termination_gt_4_1
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ def test_set_up(self):
steps[1].basic_repr()
] # CC charge
model_V = sim.experiment_unique_steps_to_model[steps[2].basic_repr()] # CV hold
assert "Current cut-off [A] [experiment]" in [
assert "abs(Current [A]) < 0.05 [A] [experiment]" in [
event.name for event in model_V.events
]
assert "Charge voltage cut-off [V] [experiment]" in [
assert "Voltage > 4.1 [V] [experiment]" in [
event.name for event in model_I.events
]

Expand Down
Loading