diff --git a/.gitignore b/.gitignore index 3c3bb708d..2bafcca63 100644 --- a/.gitignore +++ b/.gitignore @@ -314,3 +314,6 @@ $RECYCLE.BIN/ # Airspeed Velocity *.asv/ results/ + +# Pycharm +*.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a92d6d92..51d43e025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#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. - [#393](https://github.com/pybop-team/PyBOP/pull/383) - Adds Minkowski and SumofPower cost classes, with an example and corresponding tests. - [#403](https://github.com/pybop-team/PyBOP/pull/403/) - Adds lychee link checking action. +- [#313](https://github.com/pybop-team/PyBOP/pull/313/) - Fixes for PyBaMM v24.5, drops support for PyBaMM v23.9, v24.1 ## Bug Fixes diff --git a/examples/scripts/gitt.py b/examples/scripts/gitt.py index 6d3b4a94b..4b8c1561b 100644 --- a/examples/scripts/gitt.py +++ b/examples/scripts/gitt.py @@ -36,10 +36,10 @@ model = pybop.lithium_ion.WeppnerHuggins(parameter_set=parameter_set) parameters = pybop.Parameter( - "Positive electrode diffusivity [m2.s-1]", + "Positive particle diffusivity [m2.s-1]", prior=pybop.Gaussian(5e-14, 1e-13), bounds=[1e-16, 1e-11], - true_value=parameter_set["Positive electrode diffusivity [m2.s-1]"], + true_value=parameter_set["Positive particle diffusivity [m2.s-1]"], ) problem = pybop.FittingProblem( diff --git a/examples/scripts/parameters/example_BPX.json b/examples/scripts/parameters/example_BPX.json index 43bbcf905..1e1efaadb 100644 --- a/examples/scripts/parameters/example_BPX.json +++ b/examples/scripts/parameters/example_BPX.json @@ -1,7 +1,7 @@ { "Header": { - "BPX": 0.1, - "Title": "Parameterisation example of an LFP|graphite 2 Ah cylindrical 18650 cell.", + "BPX": 0.4, + "Title": "Parameterisation example of an LFP|graphite 2 Ah cylindrical 18650 cell. File downloaded on 19/3/24 from https://github.com/FaradayInstitution/BPX/blob/main/examples/lfp_18650_cell_BPX.json", "Description": "LFP|graphite 2 Ah cylindrical 18650 cell. Parameterisation by About:Energy Limited (aboutenergy.io), December 2022, based on cell cycling data, and electrode data gathered after cell teardown. Electrolyte properties from Nyman et al. 2008 (doi:10.1016/j.electacta.2008.04.023). Negative electrode entropic coefficient data are from O'Regan et al. 2022 (doi:10.1016/j.electacta.2022.140700). Positive electrode entropic coefficient data are from Gerver and Meyers 2011 (doi:10.1149/1.3591799). Other thermal properties are estimated.", "Model": "DFN" }, @@ -70,9 +70,6 @@ "Thickness [m]": 2e-05, "Porosity": 0.47, "Transport efficiency": 0.3222 - }, - "User-defined": { - "Source:": "An example BPX json file downloaded on 19/3/24 from https://github.com/FaradayInstitution/BPX/blob/main/examples/lfp_18650_cell_BPX.json" } } } diff --git a/examples/scripts/spm_UKF.py b/examples/scripts/spm_UKF.py index e528c715e..c69883b23 100644 --- a/examples/scripts/spm_UKF.py +++ b/examples/scripts/spm_UKF.py @@ -22,7 +22,7 @@ # Make a prediction with measurement noise sigma = 0.001 -t_eval = np.arange(0, 300, 2) +t_eval = np.arange(0, 900, 0.5) values = model.predict(t_eval=t_eval) corrupt_values = values["Voltage [V]"].data + np.random.normal(0, sigma, len(t_eval)) @@ -42,8 +42,8 @@ signal = ["Voltage [V]"] n_states = model.n_states n_signals = len(signal) -covariance = np.diag([0] * 19 + [sigma**2] + [0] * 19 + [sigma**2]) -process_noise = np.diag([0] * 19 + [1e-6] + [0] * 19 + [1e-6]) +covariance = np.diag([0] * 20 + [sigma**2] + [0] * 20 + [sigma**2]) +process_noise = np.diag([0] * 20 + [1e-6] + [0] * 20 + [1e-6]) measurement_noise = np.diag([sigma**2]) observer = pybop.UnscentedKalmanFilterObserver( parameters, diff --git a/pybop/_experiment.py b/pybop/_experiment.py index 1c4953849..a651dffc2 100644 --- a/pybop/_experiment.py +++ b/pybop/_experiment.py @@ -49,6 +49,4 @@ def __init__( period, temperature, termination, - drive_cycles, - cccv_handling, ) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 461989086..a706923cb 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -119,9 +119,13 @@ def build( self.set_params() self._mesh = pybamm.Mesh(self.geometry, self.submesh_types, self.var_pts) - self._disc = pybamm.Discretisation(self.mesh, self.spatial_methods) + self._disc = pybamm.Discretisation( + mesh=self.mesh, + spatial_methods=self.spatial_methods, + check_model=check_model, + ) self._built_model = self._disc.process_model( - self._model_with_set_params, inplace=False, check_model=check_model + self._model_with_set_params, inplace=False ) # Clear solver and setup model @@ -230,9 +234,13 @@ def rebuild( self.set_params(rebuild=True) self._mesh = pybamm.Mesh(self.geometry, self.submesh_types, self.var_pts) - self._disc = pybamm.Discretisation(self.mesh, self.spatial_methods) + self._disc = pybamm.Discretisation( + mesh=self.mesh, + spatial_methods=self.spatial_methods, + check_model=check_model, + ) self._built_model = self._disc.process_model( - self._model_with_set_params, inplace=False, check_model=check_model + self._model_with_set_params, inplace=False ) # Clear solver and setup model diff --git a/pybop/models/lithium_ion/weppner_huggins.py b/pybop/models/lithium_ion/weppner_huggins.py index 74c42c70e..b8707cca9 100644 --- a/pybop/models/lithium_ion/weppner_huggins.py +++ b/pybop/models/lithium_ion/weppner_huggins.py @@ -65,7 +65,7 @@ def __init__(self, name="Weppner & Huggins model", **model_kwargs): # Parameters ###################### - d_s = Parameter("Positive electrode diffusivity [m2.s-1]") + d_s = Parameter("Positive particle diffusivity [m2.s-1]") c_s_max = Parameter("Maximum concentration in positive electrode [mol.m-3]") diff --git a/pyproject.toml b/pyproject.toml index 0ec781e58..eacb65f7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ ] requires-python = ">=3.9, <3.13" dependencies = [ - "pybamm>=23.9", + "pybamm>=24.5rc2", "numpy>=1.16, <2.0", "scipy>=1.3", "pints>=0.5", diff --git a/scripts/ci/build_matrix.sh b/scripts/ci/build_matrix.sh index 9dfe32249..88d5b9b38 100755 --- a/scripts/ci/build_matrix.sh +++ b/scripts/ci/build_matrix.sh @@ -11,8 +11,11 @@ python_version=("3.9" "3.10" "3.11" "3.12") os=("ubuntu-latest" "windows-latest" "macos-13" "macos-14") -# This command fetches the last two PyBaMM versions excluding release candidates from PyPI -pybamm_version=($(curl -s https://pypi.org/pypi/pybamm/json | jq -r '.releases | keys[]' | grep -v rc | tail -n 2 | paste -sd " " -)) +# This command fetches the last PyBaMM version excluding release candidates from PyPI +#pybamm_version=($(curl -s https://pypi.org/pypi/pybamm/json | jq -r '.releases | keys[]' | grep -v rc | tail -n 1 | paste -sd " " -)) + +# This command fetches the last PyBaMM versions including release candidates from PyPI +pybamm_version=($(curl -s https://pypi.org/pypi/pybamm/json | jq -r '.releases | keys[]' | tail -n 1 | paste -sd " " -)) # open dict json='{ @@ -40,7 +43,7 @@ json+=' ] }' -# Filter out incompatible combinations -json=$(echo "$json" | jq -c 'del(.include[] | select(.pybamm_version == "23.9" and .python_version == "3.12"))') +# Example for filtering out incompatible combinations +#json=$(echo "$json" | jq -c 'del(.include[] | select(.pybamm_version == "23.9" and .python_version == "3.12"))') echo "$json" | jq -c . diff --git a/tests/integration/test_model_experiment_changes.py b/tests/integration/test_model_experiment_changes.py index 64d27132a..7bcc33ddb 100644 --- a/tests/integration/test_model_experiment_changes.py +++ b/tests/integration/test_model_experiment_changes.py @@ -22,7 +22,7 @@ class TestModelAndExperimentChanges: ), pybop.Parameters( pybop.Parameter( # non-geometric parameter - "Positive electrode diffusivity [m2.s-1]", + "Positive particle diffusivity [m2.s-1]", prior=pybop.Gaussian(3.43e-15, 1e-15), bounds=[1e-15, 5e-15], true_value=4e-15, diff --git a/tests/unit/test_cost.py b/tests/unit/test_cost.py index 802accf19..b50c0f101 100644 --- a/tests/unit/test_cost.py +++ b/tests/unit/test_cost.py @@ -296,7 +296,7 @@ def test_design_costs(self, cost_class, design_problem): # Compute after updating nominal capacity cost = cost_class(design_problem, update_capacity=True) - cost([0.4]) + assert np.isfinite(cost([0.4])) @pytest.mark.unit def test_weighted_fitting_cost(self, problem): diff --git a/tests/unit/test_experiment.py b/tests/unit/test_experiment.py index 6d18ef509..71355ff84 100644 --- a/tests/unit/test_experiment.py +++ b/tests/unit/test_experiment.py @@ -18,9 +18,9 @@ def test_experiment(self): pybop_experiment = pybop.Experiment(protocol) pybamm_experiment = pybamm.Experiment(protocol) - assert [ - step.to_dict() for step in pybop_experiment.operating_conditions_steps - ] == [step.to_dict() for step in pybamm_experiment.operating_conditions_steps] + assert [step.to_dict() for step in pybop_experiment.steps] == [ + step.to_dict() for step in pybamm_experiment.steps + ] assert pybop_experiment.cycle_lengths == pybamm_experiment.cycle_lengths diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index b50a14bfc..b12b3639e 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -358,11 +358,13 @@ def test_non_converged_solution(self): "Voltage [V]": np.zeros(100), } ) - problem = pybop.FittingProblem(model, parameters=parameters, dataset=dataset) - res = problem.evaluate([-0.2, -0.2]) - _, res_grad = problem.evaluateS1([-0.2, -0.2]) + + # Simulate the DFN with active material values of 0. + # The solution elements will not change as the solver will not converge. + output = problem.evaluate([0, 0]) + output_S1, _ = problem.evaluateS1([0, 0]) for key in problem.signal: - assert np.isinf(res.get(key, [])).any() - assert np.isinf(res_grad).any() + assert np.allclose(output.get(key, [])[0], output.get(key, [])) + assert np.allclose(output_S1.get(key, [])[0], output_S1.get(key, [])) diff --git a/tests/unit/test_observer_unscented_kalman.py b/tests/unit/test_observer_unscented_kalman.py index 0b5d3067b..c83fae315 100644 --- a/tests/unit/test_observer_unscented_kalman.py +++ b/tests/unit/test_observer_unscented_kalman.py @@ -93,6 +93,15 @@ def test_cholupdate(self): SquareRootUKF.cholupdate(R1_, u.copy(), 1.0) np.testing.assert_array_almost_equal(R1, R1_) + # Test hypot + f = 10.0 + j = 20.0 + out_1 = f * np.sqrt(1 + 1.0 * f**2 / j**2) + np.testing.assert_allclose(SquareRootUKF.hypot(f, j, 1.0), out_1) + + j = 10.0 + np.testing.assert_allclose(SquareRootUKF.hypot(f, j, 1.0), float(0)) + @pytest.mark.unit def test_unscented_kalman_filter(self, dataset, observer): t_eval = dataset["Time [s]"] @@ -116,6 +125,11 @@ def test_unscented_kalman_filter(self, dataset, observer): decimal=4, ) + # Test get covariance + cov = observer.get_current_measure() + assert cov.shape == (1, 1) + assert float(0) <= cov[0] + @pytest.mark.unit def test_observe_no_measurement(self, observer): with pytest.raises(ValueError):