Skip to content

Commit

Permalink
Update BPX version and make PyBaMM compatible with Pydantic V2 (#4701)
Browse files Browse the repository at this point in the history
* Force version second attempt

* Fix typo

* Fixing some tests

* Rename some parameters

* Fix typo

* Remove strings with typos

* Fix another bug

* Revert file

* Fix attribute parsing

* Force version

* Fix pin

* Update changelog
  • Loading branch information
kratman authored Dec 27, 2024
1 parent a1f73b6 commit a362f92
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 45 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

## Breaking changes

- Updated BPX to v0.5.0 and made changes for the switch to Pydantic V2 ([#4701](https://github.com/pybamm-team/PyBaMM/pull/4701))
- Summary variables now calculated only when called, accessed via a class in the same manner as other variables rather than a dictionary. ([#4621](https://github.com/pybamm-team/PyBaMM/pull/4621))
- The conda distribution (`pybamm`) now installs all optional dependencies available on conda-forge. Use the new `pybamm-base` conda
package to install PyBaMM with only the required dependencies. ([conda-forge/pybamm-feedstock#70](https://github.com/conda-forge/pybamm-feedstock/pull/70))
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ cite = [
]
# Battery Parameter eXchange format
bpx = [
"bpx==0.4.0",
"bpx>=0.5.0,<0.6.0",
]
# Low-overhead progress bars
tqdm = [
Expand Down
15 changes: 7 additions & 8 deletions src/pybamm/parameters/bpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,7 @@ def _conductivity(c_e, T, Ea, sigma_ref, constant=False):
# Add user-defined parameters, if any
user_defined = bpx.parameterisation.user_defined
if user_defined:
for name in user_defined.__dict__.keys():
value = getattr(user_defined, name)
for name, value in user_defined:
value = process_float_function_table(value, name)
if callable(value):
pybamm_dict[name] = partial(_callable_func, fun=value)
Expand Down Expand Up @@ -447,7 +446,7 @@ def _bpx_to_domain_param_dict(instance: BPX, pybamm_dict: dict, domain: Domain)
Turns a BPX instance in to a dictionary of parameters for PyBaMM for a given domain
"""
# Loop over fields in BPX instance and add to pybamm dictionary
for name, field in instance.__fields__.items():
for name, field in instance.model_fields.items():
value = getattr(instance, name)
# Handle blended electrodes, where the field is now an instance of
# ElectrodeBlended or ElectrodeBlendedSPM
Expand All @@ -460,16 +459,16 @@ def _bpx_to_domain_param_dict(instance: BPX, pybamm_dict: dict, domain: Domain)
for i, phase_name in enumerate(particle_instance.keys()):
phase_instance = particle_instance[phase_name]
# Loop over fields in phase instance and add to pybamm dictionary
for name, field in phase_instance.__fields__.items():
value = getattr(phase_instance, name)
for name_to_add, field_to_add in phase_instance.model_fields.items():
value = getattr(phase_instance, name_to_add)
pybamm_name = PHASE_NAMES[i] + _get_pybamm_name(
field.field_info.alias, domain
field_to_add.alias, domain
)
value = process_float_function_table(value, name)
value = process_float_function_table(value, name_to_add)
pybamm_dict[pybamm_name] = value
# Handle other fields, which correspond directly to parameters
else:
pybamm_name = _get_pybamm_name(field.field_info.alias, domain)
pybamm_name = _get_pybamm_name(field.alias, domain)
value = process_float_function_table(value, name)
pybamm_dict[pybamm_name] = value
return pybamm_dict
52 changes: 16 additions & 36 deletions tests/unit/test_parameters/test_bpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import copy
import numpy as np
import pytest
from typing import Any


class TestBPX:
def setup_method(self):
self.base = {
self.base: dict[str, Any] = {
"Header": {
"BPX": 1.0,
"Title": "Parametrisation example",
Expand Down Expand Up @@ -116,7 +117,7 @@ def test_bpx(self):
},
},
},
copy.copy(self.base),
copy.deepcopy(self.base),
]

model = pybamm.lithium_ion.DFN()
Expand All @@ -132,9 +133,6 @@ def test_bpx(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a temporary file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(obj, tmp)
tmp.flush()

Expand All @@ -153,13 +151,13 @@ def test_no_already_exists_in_BPX(self):
with tempfile.NamedTemporaryFile(
suffix="test.json", delete=False, mode="w"
) as test_file:
json.dump(copy.copy(self.base), test_file)
json.dump(copy.deepcopy(self.base), test_file)
test_file.flush()
params = pybamm.ParameterValues.create_from_bpx(test_file.name)
assert "check_already_exists" not in params.keys()

def test_constant_functions(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
bpx_obj["Parameterisation"]["Electrolyte"].update(
{
"Conductivity [S.m-1]": 1,
Expand All @@ -183,9 +181,6 @@ def test_constant_functions(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a tempory file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

Expand All @@ -210,7 +205,7 @@ def check_constant_output(func):
check_constant_output(De)

def test_table_data(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
data = {"x": [0, 1], "y": [0, 1]}
bpx_obj["Parameterisation"]["Electrolyte"].update(
{
Expand All @@ -237,9 +232,6 @@ def test_table_data(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a temporary file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

Expand All @@ -263,20 +255,17 @@ def test_table_data(self):
assert isinstance(dUdT, pybamm.Interpolant)

def test_bpx_soc_error(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
with pytest.raises(ValueError, match="Target SOC"):
pybamm.ParameterValues.create_from_bpx_obj(bpx_obj, target_soc=10)

def test_bpx_arrhenius(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)

filename = "tmp.json"
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a tempory file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

Expand Down Expand Up @@ -327,7 +316,7 @@ def arrhenius_assertion(pv, param_key, Ea_key):
arrhenius_assertion(pv, param_key, Ea_key)

def test_bpx_blended(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
bpx_obj["Parameterisation"]["Positive electrode"] = {
"Thickness [m]": 5.23e-05,
"Conductivity [S.m-1]": 0.789,
Expand Down Expand Up @@ -367,9 +356,6 @@ def test_bpx_blended(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a tempory file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

Expand All @@ -393,7 +379,7 @@ def test_bpx_blended(self):
sim.solve(calc_esoh=False)

def test_bpx_blended_error(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
bpx_obj["Parameterisation"]["Positive electrode"] = {
"Thickness [m]": 5.23e-05,
"Conductivity [S.m-1]": 0.789,
Expand Down Expand Up @@ -446,17 +432,14 @@ def test_bpx_blended_error(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a tempory file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

with pytest.raises(NotImplementedError, match="PyBaMM does not support"):
pybamm.ParameterValues.create_from_bpx(tmp.name)

def test_bpx_user_defined(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
data = {"x": [0, 1], "y": [0, 1]}
bpx_obj["Parameterisation"]["User-defined"] = {
"User-defined scalar parameter": 1.0,
Expand All @@ -468,9 +451,6 @@ def test_bpx_user_defined(self):
with tempfile.NamedTemporaryFile(
suffix=filename, delete=False, mode="w"
) as tmp:
# write to a tempory file so we can
# get the source later on using inspect.getsource
# (as long as the file still exists)
json.dump(bpx_obj, tmp)
tmp.flush()

Expand All @@ -488,21 +468,21 @@ def test_bpx_user_defined(self):
)

def test_bpx_activation_energy_default(self):
bpx_obj = copy.copy(self.base)
bpx_obj["Parameterisation"]["Negative electrode"][
bpx_obj = copy.deepcopy(self.base)
del bpx_obj["Parameterisation"]["Negative electrode"][
"Diffusivity activation energy [J.mol-1]"
] = None
]
with tempfile.NamedTemporaryFile(
suffix="test.json", delete=False, mode="w"
) as test_file:
json.dump(copy.copy(bpx_obj), test_file)
json.dump(copy.deepcopy(bpx_obj), test_file)
test_file.flush()
param = pybamm.ParameterValues.create_from_bpx(test_file.name)
assert param[
"Negative electrode diffusivity activation energy [J.mol-1]"
] == pytest.approx(0.0, rel=1e-12)

def test_bpx_from_obj(self):
bpx_obj = copy.copy(self.base)
bpx_obj = copy.deepcopy(self.base)
param = pybamm.ParameterValues.create_from_bpx_obj(bpx_obj)
assert isinstance(param, pybamm.ParameterValues)

0 comments on commit a362f92

Please sign in to comment.