From 692548e45bbafa6c345d1b44c518495e4ffe4748 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:58:17 +0000 Subject: [PATCH 01/12] chore: update pre-commit hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.8 → v0.4.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.8...v0.4.9) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 401b5338..990f1e80 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.4.8" + rev: "v0.4.9" hooks: - id: ruff args: [--fix, --show-fixes] From ec11c2c4d74167f70ecc373ada94afa1fd86acfb Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:34:15 +0100 Subject: [PATCH 02/12] Update np.array to np.asarray --- examples/notebooks/multi_model_identification.ipynb | 2 +- .../notebooks/multi_optimiser_identification.ipynb | 2 +- examples/notebooks/optimiser_calibration.ipynb | 2 +- examples/notebooks/spm_AdamW.ipynb | 2 +- examples/scripts/ecm_CMAES.py | 2 +- examples/scripts/spm_AdamW.py | 2 +- examples/scripts/spm_IRPropMin.py | 2 +- examples/scripts/spm_MAP.py | 2 +- examples/scripts/spm_MLE.py | 2 +- examples/scripts/spm_NelderMead.py | 2 +- examples/scripts/spm_descent.py | 2 +- pybop/costs/_likelihoods.py | 10 +++++----- pybop/costs/fitting_costs.py | 8 ++++---- pybop/models/base_model.py | 4 ++-- pybop/observers/observer.py | 2 +- pybop/observers/unscented_kalman.py | 8 ++++---- pybop/plotting/plot2d.py | 12 +++++++----- tests/integration/test_optimisation_options.py | 2 +- tests/integration/test_spm_parameterisations.py | 2 +- tests/integration/test_thevenin_parameterisation.py | 2 +- 20 files changed, 37 insertions(+), 35 deletions(-) diff --git a/examples/notebooks/multi_model_identification.ipynb b/examples/notebooks/multi_model_identification.ipynb index 699b2eda..e7c6b158 100644 --- a/examples/notebooks/multi_model_identification.ipynb +++ b/examples/notebooks/multi_model_identification.ipynb @@ -3958,7 +3958,7 @@ } ], "source": [ - "bounds = np.array([[5.5e-05, 8e-05], [7.5e-05, 9e-05]])\n", + "bounds = np.asarray([[5.5e-05, 8e-05], [7.5e-05, 9e-05]])\n", "for optim in optims:\n", " pybop.plot2d(optim, bounds=bounds, steps=10, title=optim.cost.problem.model.name)" ] diff --git a/examples/notebooks/multi_optimiser_identification.ipynb b/examples/notebooks/multi_optimiser_identification.ipynb index f85b2609..8b2a8350 100644 --- a/examples/notebooks/multi_optimiser_identification.ipynb +++ b/examples/notebooks/multi_optimiser_identification.ipynb @@ -925,7 +925,7 @@ ], "source": [ "# Plot the cost landscape with optimisation path and updated bounds\n", - "bounds = np.array([[0.5, 0.8], [0.55, 0.8]])\n", + "bounds = np.asarray([[0.5, 0.8], [0.55, 0.8]])\n", "for optim in optims:\n", " pybop.plot2d(optim, bounds=bounds, steps=10, title=optim.name())" ] diff --git a/examples/notebooks/optimiser_calibration.ipynb b/examples/notebooks/optimiser_calibration.ipynb index 3199fadb..accfbf25 100644 --- a/examples/notebooks/optimiser_calibration.ipynb +++ b/examples/notebooks/optimiser_calibration.ipynb @@ -677,7 +677,7 @@ ], "source": [ "# Plot the cost landscape with optimisation path and updated bounds\n", - "bounds = np.array([[0.6, 0.9], [0.5, 0.8]])\n", + "bounds = np.asarray([[0.6, 0.9], [0.5, 0.8]])\n", "for optim, sigma in zip(optims, sigmas):\n", " pybop.plot2d(optim, bounds=bounds, steps=10, title=f\"Sigma: {sigma}\")" ] diff --git a/examples/notebooks/spm_AdamW.ipynb b/examples/notebooks/spm_AdamW.ipynb index 20b73330..6b233090 100644 --- a/examples/notebooks/spm_AdamW.ipynb +++ b/examples/notebooks/spm_AdamW.ipynb @@ -530,7 +530,7 @@ "# Plot the cost landscape\n", "pybop.plot2d(cost, steps=15)\n", "# Plot the cost landscape with optimisation path and updated bounds\n", - "bounds = np.array([[0.6, 0.9], [0.5, 0.8]])\n", + "bounds = np.asarray([[0.6, 0.9], [0.5, 0.8]])\n", "pybop.plot2d(optim, bounds=bounds, steps=15);" ] }, diff --git a/examples/scripts/ecm_CMAES.py b/examples/scripts/ecm_CMAES.py index fc711cab..96a36ec4 100644 --- a/examples/scripts/ecm_CMAES.py +++ b/examples/scripts/ecm_CMAES.py @@ -101,5 +101,5 @@ pybop.plot2d(cost, steps=15) # Plot the cost landscape with optimisation path and updated bounds -bounds = np.array([[1e-4, 1e-2], [1e-5, 1e-2]]) +bounds = np.asarray([[1e-4, 1e-2], [1e-5, 1e-2]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_AdamW.py b/examples/scripts/spm_AdamW.py index 10351512..44bbf8b1 100644 --- a/examples/scripts/spm_AdamW.py +++ b/examples/scripts/spm_AdamW.py @@ -77,5 +77,5 @@ def noise(sigma): pybop.plot_parameters(optim) # Plot the cost landscape with optimisation path -bounds = np.array([[0.5, 0.8], [0.4, 0.7]]) +bounds = np.asarray([[0.5, 0.8], [0.4, 0.7]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_IRPropMin.py b/examples/scripts/spm_IRPropMin.py index 3b38668c..727536ff 100644 --- a/examples/scripts/spm_IRPropMin.py +++ b/examples/scripts/spm_IRPropMin.py @@ -51,5 +51,5 @@ pybop.plot_parameters(optim) # Plot the cost landscape with optimisation path -bounds = np.array([[0.5, 0.8], [0.4, 0.7]]) +bounds = np.asarray([[0.5, 0.8], [0.4, 0.7]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_MAP.py b/examples/scripts/spm_MAP.py index 191f93d8..d8460915 100644 --- a/examples/scripts/spm_MAP.py +++ b/examples/scripts/spm_MAP.py @@ -69,5 +69,5 @@ pybop.plot2d(cost, steps=15) # Plot the cost landscape with optimisation path -bounds = np.array([[0.55, 0.77], [0.48, 0.68]]) +bounds = np.asarray([[0.55, 0.77], [0.48, 0.68]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_MLE.py b/examples/scripts/spm_MLE.py index 7e1b3c93..6fc0238c 100644 --- a/examples/scripts/spm_MLE.py +++ b/examples/scripts/spm_MLE.py @@ -69,5 +69,5 @@ pybop.plot2d(likelihood, steps=15) # Plot the cost landscape with optimisation path -bounds = np.array([[0.55, 0.77], [0.48, 0.68]]) +bounds = np.asarray([[0.55, 0.77], [0.48, 0.68]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_NelderMead.py b/examples/scripts/spm_NelderMead.py index 82639632..569dbadf 100644 --- a/examples/scripts/spm_NelderMead.py +++ b/examples/scripts/spm_NelderMead.py @@ -77,5 +77,5 @@ def noise(sigma): pybop.plot_parameters(optim) # Plot the cost landscape with optimisation path -bounds = np.array([[0.5, 0.8], [0.4, 0.7]]) +bounds = np.asarray([[0.5, 0.8], [0.4, 0.7]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/examples/scripts/spm_descent.py b/examples/scripts/spm_descent.py index df57a7ca..7c7629b0 100644 --- a/examples/scripts/spm_descent.py +++ b/examples/scripts/spm_descent.py @@ -57,5 +57,5 @@ pybop.plot_parameters(optim) # Plot the cost landscape with optimisation path -bounds = np.array([[0.5, 0.8], [0.4, 0.7]]) +bounds = np.asarray([[0.5, 0.8], [0.4, 0.7]]) pybop.plot2d(optim, bounds=bounds, steps=15) diff --git a/pybop/costs/_likelihoods.py b/pybop/costs/_likelihoods.py index cd5e4a9c..cce09f9b 100644 --- a/pybop/costs/_likelihoods.py +++ b/pybop/costs/_likelihoods.py @@ -47,7 +47,7 @@ def set_sigma(self, sigma): ) if not isinstance(sigma, np.ndarray): - sigma = np.array(sigma) + sigma = np.asarray(sigma) if not np.issubdtype(sigma.dtype, np.number): raise ValueError("Sigma must contain only numeric values") @@ -74,7 +74,7 @@ def _evaluate(self, x, grad=None): if len(y.get(key, [])) != len(self._target.get(key, [])): return -np.float64(np.inf) # prediction doesn't match target - e = np.array( + e = np.asarray( [ np.sum( self._offset @@ -102,7 +102,7 @@ def _evaluateS1(self, x, grad=None): dl = self._dl * np.ones(self.n_parameters) return -likelihood, -dl - r = np.array([self._target[signal] - y[signal] for signal in self.signal]) + r = np.asarray([self._target[signal] - y[signal] for signal in self.signal]) likelihood = self._evaluate(x) dl = np.sum((self.sigma2 * np.sum((r * dy.T), axis=2)), axis=1) return likelihood, dl @@ -148,7 +148,7 @@ def _evaluate(self, x, grad=None): if len(y.get(key, [])) != len(self._target.get(key, [])): return -np.float64(np.inf) # prediction doesn't match target - e = np.array( + e = np.asarray( [ np.sum( self._logpi @@ -181,7 +181,7 @@ def _evaluateS1(self, x, grad=None): dl = self._dl * np.ones(self.n_parameters) return -likelihood, -dl - r = np.array([self._target[signal] - y[signal] for signal in self.signal]) + r = np.asarray([self._target[signal] - y[signal] for signal in self.signal]) likelihood = self._evaluate(x) dl = sigma ** (-2.0) * np.sum((r * dy.T), axis=2) dsigma = -self.n_time_data / sigma + sigma**-(3.0) * np.sum(r**2, axis=1) diff --git a/pybop/costs/fitting_costs.py b/pybop/costs/fitting_costs.py index 569e590e..eff56059 100644 --- a/pybop/costs/fitting_costs.py +++ b/pybop/costs/fitting_costs.py @@ -47,7 +47,7 @@ def _evaluate(self, x, grad=None): if len(prediction.get(key, [])) != len(self._target.get(key, [])): return np.float64(np.inf) # prediction doesn't match target - e = np.array( + e = np.asarray( [ np.sqrt(np.mean((prediction[signal] - self._target[signal]) ** 2)) for signal in self.signal @@ -87,7 +87,7 @@ def _evaluateS1(self, x): de = self._de * np.ones(self.n_parameters) return e, de - r = np.array([y[signal] - self._target[signal] for signal in self.signal]) + r = np.asarray([y[signal] - self._target[signal] for signal in self.signal]) e = np.sqrt(np.mean(r**2, axis=1)) de = np.mean((r * dy.T), axis=2) / (e + np.finfo(float).eps) @@ -159,7 +159,7 @@ def _evaluate(self, x, grad=None): if len(prediction.get(key, [])) != len(self._target.get(key, [])): return np.float64(np.inf) # prediction doesn't match target - e = np.array( + e = np.asarray( [ np.sum(((prediction[signal] - self._target[signal]) ** 2)) for signal in self.signal @@ -197,7 +197,7 @@ def _evaluateS1(self, x): de = self._de * np.ones(self.n_parameters) return e, de - r = np.array([y[signal] - self._target[signal] for signal in self.signal]) + r = np.asarray([y[signal] - self._target[signal] for signal in self.signal]) e = np.sum(np.sum(r**2, axis=0), axis=0) de = 2 * np.sum(np.sum((r * dy.T), axis=2), axis=1) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index e9809bc4..a0506267 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -292,7 +292,7 @@ def reinit( if x is None: x = self._built_model.y0 - sol = pybamm.Solution([np.array([t])], [x], self._built_model, inputs) + sol = pybamm.Solution([np.asarray([t])], [x], self._built_model, inputs) return TimeSeriesState(sol=sol, inputs=inputs, t=t) @@ -303,7 +303,7 @@ def get_state(self, inputs: Inputs, t: float, x: np.ndarray) -> TimeSeriesState: if self._built_model is None: raise ValueError("Model must be built before calling get_state") - sol = pybamm.Solution([np.array([t])], [x], self._built_model, inputs) + sol = pybamm.Solution([np.asarray([t])], [x], self._built_model, inputs) return TimeSeriesState(sol=sol, inputs=inputs, t=t) diff --git a/pybop/observers/observer.py b/pybop/observers/observer.py index 162d03de..1b81c5ac 100644 --- a/pybop/observers/observer.py +++ b/pybop/observers/observer.py @@ -134,7 +134,7 @@ def get_current_covariance(self) -> Covariance: def get_measure(self, x: TimeSeriesState) -> np.ndarray: measures = [x.sol[s].data[-1] for s in self._signal] - return np.array([[m] for m in measures]) + return np.asarray([[m] for m in measures]) def get_current_time(self) -> float: """ diff --git a/pybop/observers/unscented_kalman.py b/pybop/observers/unscented_kalman.py index b7ea0f35..0b6425db 100644 --- a/pybop/observers/unscented_kalman.py +++ b/pybop/observers/unscented_kalman.py @@ -118,7 +118,7 @@ def observe(self, time: float, value: np.ndarray) -> float: if value is None: raise ValueError("Measurement must be provided.") elif isinstance(value, np.floating): - value = np.array([value]) + value = np.asarray([value]) dt = time - self.get_current_time() if dt < 0: @@ -201,7 +201,7 @@ def __init__( zero_cols = np.logical_and(np.all(P0 == 0, axis=1), np.all(Rp == 0, axis=1)) zeros = np.logical_and(zero_rows, zero_cols) ones = np.logical_not(zeros) - states = np.array(range(len(x0)))[ones] + states = np.asarray(range(len(x0)))[ones] bool_mask = np.ix_(ones, ones) S_filtered = linalg.cholesky(P0[ones, :][:, ones]) @@ -276,11 +276,11 @@ def gen_sigma_points( # Define the weights of the sigma points w_m0 = sigma / (L + sigma) - w_m = np.array([w_m0] + [1 / (2 * (L + sigma))] * (2 * L)) + w_m = np.asarray([w_m0] + [1 / (2 * (L + sigma))] * (2 * L)) # Define the weights of the covariance of the sigma points w_c0 = w_m0 + (1 - alpha**2 + beta) - w_c = np.array([w_c0] + [1 / (2 * (L + sigma))] * (2 * L)) + w_c = np.asarray([w_c0] + [1 / (2 * (L + sigma))] * (2 * L)) return (points, w_m, w_c) diff --git a/pybop/plotting/plot2d.py b/pybop/plotting/plot2d.py index 2e7d4f26..961bc7c4 100644 --- a/pybop/plotting/plot2d.py +++ b/pybop/plotting/plot2d.py @@ -77,19 +77,19 @@ def plot2d( # Populate cost matrix for i, xi in enumerate(x): for j, yj in enumerate(y): - costs[j, i] = cost(np.array([xi, yj])) + costs[j, i] = cost(np.asarray([xi, yj])) if gradient: grad_parameter_costs = [] # Determine the number of gradient outputs from cost.evaluateS1 - num_gradients = len(cost.evaluateS1(np.array([x[0], y[0]]))[1]) + num_gradients = len(cost.evaluateS1(np.asarray([x[0], y[0]]))[1]) # Create an array to hold each gradient output & populate grads = [np.zeros((len(y), len(x))) for _ in range(num_gradients)] for i, xi in enumerate(x): for j, yj in enumerate(y): - (*current_grads,) = cost.evaluateS1(np.array([xi, yj]))[1] + (*current_grads,) = cost.evaluateS1(np.asarray([xi, yj]))[1] for k, grad_output in enumerate(current_grads): grads[k][j, i] = grad_output @@ -103,7 +103,7 @@ def plot2d( flat_costs = costs.flatten() # Append the optimisation trace to the data - parameter_log = np.array(optim.log["x_best"]) + parameter_log = np.asarray(optim.log["x_best"]) flat_x = np.concatenate((flat_x, parameter_log[:, 0])) flat_y = np.concatenate((flat_y, parameter_log[:, 1])) flat_costs = np.concatenate((flat_costs, optim.log["cost"])) @@ -140,7 +140,9 @@ def plot2d( if plot_optim: # Plot the optimisation trace - optim_trace = np.array([item for sublist in optim.log["x"] for item in sublist]) + optim_trace = np.asarray( + [item for sublist in optim.log["x"] for item in sublist] + ) optim_trace = optim_trace.reshape(-1, 2) fig.add_trace( go.Scatter( diff --git a/tests/integration/test_optimisation_options.py b/tests/integration/test_optimisation_options.py index dcd94276..01702ba2 100644 --- a/tests/integration/test_optimisation_options.py +++ b/tests/integration/test_optimisation_options.py @@ -13,7 +13,7 @@ class TestOptimisation: @pytest.fixture(autouse=True) def setup(self): - self.ground_truth = np.array([0.55, 0.55]) + np.random.normal( + self.ground_truth = np.asarray([0.55, 0.55]) + np.random.normal( loc=0.0, scale=0.05, size=2 ) diff --git a/tests/integration/test_spm_parameterisations.py b/tests/integration/test_spm_parameterisations.py index 9ae2b421..3ee58957 100644 --- a/tests/integration/test_spm_parameterisations.py +++ b/tests/integration/test_spm_parameterisations.py @@ -11,7 +11,7 @@ class Test_SPM_Parameterisation: @pytest.fixture(autouse=True) def setup(self): - self.ground_truth = np.array([0.55, 0.55]) + np.random.normal( + self.ground_truth = np.asarray([0.55, 0.55]) + np.random.normal( loc=0.0, scale=0.05, size=2 ) diff --git a/tests/integration/test_thevenin_parameterisation.py b/tests/integration/test_thevenin_parameterisation.py index 57bb0689..1ef1bc3e 100644 --- a/tests/integration/test_thevenin_parameterisation.py +++ b/tests/integration/test_thevenin_parameterisation.py @@ -11,7 +11,7 @@ class TestTheveninParameterisation: @pytest.fixture(autouse=True) def setup(self): - self.ground_truth = np.array([0.05, 0.05]) + np.random.normal( + self.ground_truth = np.asarray([0.05, 0.05]) + np.random.normal( loc=0.0, scale=0.01, size=2 ) From c59460fd586ac155f07e5cf0e7520a427c58f4fa Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:34:53 +0100 Subject: [PATCH 03/12] Switch tests from CMAES to XNES --- tests/integration/test_spm_parameterisations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_spm_parameterisations.py b/tests/integration/test_spm_parameterisations.py index 3ee58957..7eeb0b7c 100644 --- a/tests/integration/test_spm_parameterisations.py +++ b/tests/integration/test_spm_parameterisations.py @@ -160,7 +160,7 @@ def spm_two_signal_cost(self, parameters, model, cost_class): [ pybop.SciPyDifferentialEvolution, pybop.IRPropMin, - pybop.CMAES, + pybop.XNES, ], ) @pytest.mark.integration @@ -218,7 +218,7 @@ def test_model_misparameterisation(self, parameters, model, init_soc): cost = pybop.RootMeanSquaredError(problem) # Select optimiser - optimiser = pybop.CMAES + optimiser = pybop.XNES # Build the optimisation problem optim = optimiser(cost=cost) From e63711015579278ae1b58e647821ff1fa0d5a7c3 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Mon, 24 Jun 2024 10:51:44 +0100 Subject: [PATCH 04/12] add changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f398e077..8a04d46b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ ## Bug Fixes - +- [#372](https://github.com/pybop-team/PyBOP/pull/372) - Converts `np.array` to `np.asarray` for Numpy v2.0 support. - [#165](https://github.com/pybop-team/PyBOP/issues/165) - Stores the attempted and best parameter values and the best cost for each iteration in the log attribute of the optimiser and updates the associated plots. - [#354](https://github.com/pybop-team/PyBOP/issues/354) - Fixes the calculation of the gradient in the `RootMeanSquaredError` cost. - [#347](https://github.com/pybop-team/PyBOP/issues/347) - Resets options between MSMR tests to cope with a bug in PyBaMM v23.9 which is fixed in PyBaMM v24.1. From efde62d5336ce1d8fbcc2ac8cbdb2fb49a6641a4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:59:20 +0000 Subject: [PATCH 05/12] chore: update pre-commit hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.9 → v0.4.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.9...v0.4.10) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 990f1e80..e5c6f51f 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.4.9" + rev: "v0.4.10" hooks: - id: ruff args: [--fix, --show-fixes] From ac16694e6194e8d4ac73e378d1752cc0cacffc58 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 28 Jun 2024 10:27:29 +0100 Subject: [PATCH 06/12] feat: add model.simulateS1 to benchmarks, add build clean between CI --- .github/workflows/periodic_benchmarks.yaml | 7 +++++++ .github/workflows/scheduled_tests.yaml | 7 +++++++ CHANGELOG.md | 1 + benchmarks/benchmark_model.py | 10 ++++++++++ 4 files changed, 25 insertions(+) diff --git a/.github/workflows/periodic_benchmarks.yaml b/.github/workflows/periodic_benchmarks.yaml index 63771150..e015bf24 100644 --- a/.github/workflows/periodic_benchmarks.yaml +++ b/.github/workflows/periodic_benchmarks.yaml @@ -22,6 +22,13 @@ jobs: runs-on: [self-hosted, macOS, ARM64] if: github.repository == 'pybop-team/PyBOP' steps: + - name: Cleanup build folder + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + - uses: actions/checkout@v4 - name: Install python & create virtualenv diff --git a/.github/workflows/scheduled_tests.yaml b/.github/workflows/scheduled_tests.yaml index ade88188..1daf7c23 100644 --- a/.github/workflows/scheduled_tests.yaml +++ b/.github/workflows/scheduled_tests.yaml @@ -113,6 +113,13 @@ jobs: matrix: ${{fromJson(needs.filter_pybamm_matrix.outputs.filtered_pybop_matrix)}} steps: + - name: Cleanup build folder + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + - uses: actions/checkout@v4 - name: Install python & create virtualenv shell: bash diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a04d46b..93752e1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Features +- [#379](https://github.com/pybop-team/PyBOP/pull/379) - Adds model.simulateS1 to weekly benchmarks. - [#174](https://github.com/pybop-team/PyBOP/issues/174) - Adds new logo and updates Readme for accessibility. - [#316](https://github.com/pybop-team/PyBOP/pull/316) - Adds Adam with weight decay (AdamW) optimiser, adds depreciation warning for pints.Adam implementation. - [#271](https://github.com/pybop-team/PyBOP/issues/271) - Aligns the output of the optimisers via a generalisation of Result class. diff --git a/benchmarks/benchmark_model.py b/benchmarks/benchmark_model.py index df0335c2..97f1b0f0 100644 --- a/benchmarks/benchmark_model.py +++ b/benchmarks/benchmark_model.py @@ -81,3 +81,13 @@ def time_model_simulate(self, model, parameter_set): parameter_set (str): The name of the parameter set being used. """ self.problem._model.simulate(inputs=self.inputs, t_eval=self.t_eval) + + def time_model_simulateS1(self, model, parameter_set): + """ + Benchmark the simulate method of the model. + + Args: + model (pybop.Model): The model class being benchmarked. + parameter_set (str): The name of the parameter set being used. + """ + self.problem._model.simulateS1(inputs=self.inputs, t_eval=self.t_eval) From f72a85e6e4f3046ebc660e3b7d445a60b6431cec Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 28 Jun 2024 13:19:41 +0100 Subject: [PATCH 07/12] fix: docstrings, remove ls -la command --- .github/workflows/periodic_benchmarks.yaml | 2 -- .github/workflows/scheduled_tests.yaml | 2 -- benchmarks/benchmark_model.py | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/periodic_benchmarks.yaml b/.github/workflows/periodic_benchmarks.yaml index e015bf24..704c7975 100644 --- a/.github/workflows/periodic_benchmarks.yaml +++ b/.github/workflows/periodic_benchmarks.yaml @@ -24,10 +24,8 @@ jobs: steps: - name: Cleanup build folder run: | - ls -la ./ rm -rf ./* || true rm -rf ./.??* || true - ls -la ./ - uses: actions/checkout@v4 diff --git a/.github/workflows/scheduled_tests.yaml b/.github/workflows/scheduled_tests.yaml index 1daf7c23..159152f0 100644 --- a/.github/workflows/scheduled_tests.yaml +++ b/.github/workflows/scheduled_tests.yaml @@ -115,10 +115,8 @@ jobs: steps: - name: Cleanup build folder run: | - ls -la ./ rm -rf ./* || true rm -rf ./.??* || true - ls -la ./ - uses: actions/checkout@v4 - name: Install python & create virtualenv diff --git a/benchmarks/benchmark_model.py b/benchmarks/benchmark_model.py index 97f1b0f0..843b03bc 100644 --- a/benchmarks/benchmark_model.py +++ b/benchmarks/benchmark_model.py @@ -84,7 +84,7 @@ def time_model_simulate(self, model, parameter_set): def time_model_simulateS1(self, model, parameter_set): """ - Benchmark the simulate method of the model. + Benchmark the simulateS1 method of the model. Args: model (pybop.Model): The model class being benchmarked. From dfe4009314df1b7776a557500197cab6a804e97c Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 28 Jun 2024 19:01:27 +0100 Subject: [PATCH 08/12] fix: restore boundaries to PSO --- pybop/optimisers/base_pints_optimiser.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/pybop/optimisers/base_pints_optimiser.py b/pybop/optimisers/base_pints_optimiser.py index a5140df0..f5698c8e 100644 --- a/pybop/optimisers/base_pints_optimiser.py +++ b/pybop/optimisers/base_pints_optimiser.py @@ -134,22 +134,20 @@ def _sanitise_inputs(self): # Convert bounds to PINTS boundaries if self.bounds is not None: - if issubclass( - self.pints_optimiser, - (PintsGradientDescent, PintsAdam, PintsNelderMead), - ): + ignored_optimisers = (PintsGradientDescent, PintsAdam, PintsNelderMead) + if issubclass(self.pints_optimiser, ignored_optimisers): print(f"NOTE: Boundaries ignored by {self.pints_optimiser}") self.bounds = None - elif issubclass(self.pints_optimiser, PintsPSO): - if not all( - np.isfinite(value) - for sublist in self.bounds.values() - for value in sublist - ): - raise ValueError( - "Either all bounds or no bounds must be set for Pints PSO." - ) else: + if issubclass(self.pints_optimiser, PintsPSO): + if not all( + np.isfinite(value) + for sublist in self.bounds.values() + for value in sublist + ): + raise ValueError( + f"Either all bounds or no bounds must be set for {self.pints_optimiser.__name__}." + ) self._boundaries = PintsRectangularBoundaries( self.bounds["lower"], self.bounds["upper"] ) From febcce8f655074dc1f9c769c09e165b9bfa64320 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 28 Jun 2024 19:13:37 +0100 Subject: [PATCH 09/12] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93752e1d..063d0e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ## Bug Fixes +- [#380](https://github.com/pybop-team/PyBOP/pull/380) - Restore self._boundaries construction for `pybop.PSO` - [#372](https://github.com/pybop-team/PyBOP/pull/372) - Converts `np.array` to `np.asarray` for Numpy v2.0 support. - [#165](https://github.com/pybop-team/PyBOP/issues/165) - Stores the attempted and best parameter values and the best cost for each iteration in the log attribute of the optimiser and updates the associated plots. - [#354](https://github.com/pybop-team/PyBOP/issues/354) - Fixes the calculation of the gradient in the `RootMeanSquaredError` cost. From afadac10c94344be269210a6494ef31eedc133a0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:10:47 +0000 Subject: [PATCH 10/12] chore: update pre-commit hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.10 → v0.5.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.10...v0.5.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e5c6f51f..47ef467c 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.4.10" + rev: "v0.5.0" hooks: - id: ruff args: [--fix, --show-fixes] From 02e18bf8dbdc65f9aaeddcceff62d1ea7ad72cbc Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Tue, 2 Jul 2024 13:47:13 +0100 Subject: [PATCH 11/12] fix: assertion in plotly_manager causing ruff complaints --- tests/plotting/test_plotly_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plotting/test_plotly_manager.py b/tests/plotting/test_plotly_manager.py index 80bc3bb5..ba0adbd8 100644 --- a/tests/plotting/test_plotly_manager.py +++ b/tests/plotting/test_plotly_manager.py @@ -95,7 +95,7 @@ def test_cancel_installation(mocker, uninstall_plotly_if_installed): with pytest.raises(SystemExit) as pytest_wrapped_e: PlotlyManager().prompt_for_plotly_installation() - assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.type is SystemExit assert pytest_wrapped_e.value.code == 1 assert not is_package_installed("plotly") From b49ede48210b8f5f32976ea04eceee88c7deded2 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:06:39 +0100 Subject: [PATCH 12/12] Add keys to ParameterSet and update ECM OCV check (#388) * Add keys to ParameterSet * Remove pybamm import from exp_UKF * Update CHANGELOG.md * Update standalone model --- CHANGELOG.md | 1 + examples/scripts/exp_UKF.py | 3 +-- examples/standalone/model.py | 8 +++++--- pybop/models/empirical/base_ecm.py | 6 +++--- pybop/models/lithium_ion/base_echem.py | 5 +---- pybop/parameters/parameter_set.py | 7 +++++++ 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 063d0e17..eedda555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ## Bug Fixes +- [#387](https://github.com/pybop-team/PyBOP/issues/387) - Adds keys to ParameterSet and updates ECM OCV check. - [#380](https://github.com/pybop-team/PyBOP/pull/380) - Restore self._boundaries construction for `pybop.PSO` - [#372](https://github.com/pybop-team/PyBOP/pull/372) - Converts `np.array` to `np.asarray` for Numpy v2.0 support. - [#165](https://github.com/pybop-team/PyBOP/issues/165) - Stores the attempted and best parameter values and the best cost for each iteration in the log attribute of the optimiser and updates the associated plots. diff --git a/examples/scripts/exp_UKF.py b/examples/scripts/exp_UKF.py index d469c781..ff7a7045 100644 --- a/examples/scripts/exp_UKF.py +++ b/examples/scripts/exp_UKF.py @@ -1,11 +1,10 @@ import numpy as np -import pybamm import pybop from examples.standalone.model import ExponentialDecay # Parameter set and model definition -parameter_set = pybamm.ParameterValues({"k": "[input]", "y0": "[input]"}) +parameter_set = {"k": "[input]", "y0": "[input]"} model = ExponentialDecay(parameter_set=parameter_set, n_states=1) # Fitting parameters diff --git a/examples/standalone/model.py b/examples/standalone/model.py index e6747746..f5d5a7ab 100644 --- a/examples/standalone/model.py +++ b/examples/standalone/model.py @@ -18,7 +18,8 @@ def __init__( parameter_set: pybamm.ParameterValues = None, n_states: int = 1, ): - super().__init__() + super().__init__(name=name, parameter_set=parameter_set) + self.n_states = n_states if n_states < 1: raise ValueError("The number of states (n_states) must be greater than 0") @@ -38,10 +39,11 @@ def __init__( ) self._unprocessed_model = self.pybamm_model - self.name = name self.default_parameter_values = ( - default_parameter_values if parameter_set is None else parameter_set + default_parameter_values + if self._parameter_set is None + else self._parameter_set ) self._parameter_set = self.default_parameter_values self._unprocessed_parameter_set = self._parameter_set diff --git a/pybop/models/empirical/base_ecm.py b/pybop/models/empirical/base_ecm.py index 8d15442d..c8252c04 100644 --- a/pybop/models/empirical/base_ecm.py +++ b/pybop/models/empirical/base_ecm.py @@ -52,14 +52,14 @@ def __init__( # Correct OCP if set to default if ( parameter_set is not None - and "Open-circuit voltage [V]" in parameter_set.params + and "Open-circuit voltage [V]" in parameter_set.keys() ): default_ocp = self.pybamm_model.default_parameter_values[ "Open-circuit voltage [V]" ] - if parameter_set.params["Open-circuit voltage [V]"] == "default": + if parameter_set["Open-circuit voltage [V]"] == "default": print("Setting open-circuit voltage to default function") - parameter_set.params["Open-circuit voltage [V]"] = default_ocp + parameter_set["Open-circuit voltage [V]"] = default_ocp super().__init__(name=name, parameter_set=parameter_set) diff --git a/pybop/models/lithium_ion/base_echem.py b/pybop/models/lithium_ion/base_echem.py index 6947774b..23aae9d9 100644 --- a/pybop/models/lithium_ion/base_echem.py +++ b/pybop/models/lithium_ion/base_echem.py @@ -47,10 +47,7 @@ def __init__( solver=None, **model_kwargs, ): - super().__init__( - name=name, - parameter_set=parameter_set, - ) + super().__init__(name=name, parameter_set=parameter_set) model_options = dict(build=False) for key, value in model_kwargs.items(): diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index a1ab63cd..cf0d1142 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -1,5 +1,6 @@ import json import types +from typing import List from pybamm import ParameterValues, parameter_sets @@ -34,6 +35,12 @@ def __setitem__(self, key, value): def __getitem__(self, key): return self.params[key] + def keys(self) -> List: + """ + A list of parameter names + """ + return list(self.params.keys()) + def import_parameters(self, json_path=None): """ Imports parameters from a JSON file specified by the `json_path` attribute.