From 5fdee8a7cb1a026dcc803575a026bed3c318ef17 Mon Sep 17 00:00:00 2001 From: Marc Berliner <34451391+MarcBerliner@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:23:02 -0400 Subject: [PATCH 01/14] Update IDAKLU time stepping in tests and benchmarks (#4390) * time stepping updates * Update test_idaklu_solver.py * Update CHANGELOG.md --- CHANGELOG.md | 3 +- benchmarks/different_model_options.py | 24 +++-- benchmarks/time_solve_models.py | 45 +++++--- .../work_precision_sets/time_vs_abstols.py | 13 ++- .../work_precision_sets/time_vs_mesh_size.py | 1 + .../time_vs_no_of_states.py | 1 + .../work_precision_sets/time_vs_reltols.py | 13 ++- tests/integration/test_solvers/test_idaklu.py | 2 +- tests/unit/test_solvers/test_idaklu_solver.py | 100 ++++++++---------- 9 files changed, 113 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e8a720e7..38747ea7fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,14 @@ ## Optimizations +- Update `IDAKLU` tests and benchmarks to use adaptive time stepping. ([#4390](https://github.com/pybamm-team/PyBaMM/pull/4390)) - Improved adaptive time-stepping performance of the (`IDAKLUSolver`). ([#4351](https://github.com/pybamm-team/PyBaMM/pull/4351)) - Improved performance and reliability of DAE consistent initialization. ([#4301](https://github.com/pybamm-team/PyBaMM/pull/4301)) - Replaced rounded Faraday constant with its exact value in `bpx.py` for better comparison between different tools. ([#4290](https://github.com/pybamm-team/PyBaMM/pull/4290)) ## Bug Fixes -- Fixed memory issue that caused failure when `output variables` were specified with (`IDAKLUSolver`). ([#4379](https://github.com/pybamm-team/PyBaMM/issues/4379)) +- Fixed memory issue that caused failure when `output variables` were specified with (`IDAKLUSolver`). ([#4379](https://github.com/pybamm-team/PyBaMM/pull/4379)) - Fixed bug where IDAKLU solver failed when `output variables` were specified and an event triggered. ([#4300](https://github.com/pybamm-team/PyBaMM/pull/4300)) ## Breaking changes diff --git a/benchmarks/different_model_options.py b/benchmarks/different_model_options.py index 72767e9f65..91c362756f 100644 --- a/benchmarks/different_model_options.py +++ b/benchmarks/different_model_options.py @@ -34,6 +34,7 @@ class SolveModel: solver: pybamm.BaseSolver model: pybamm.BaseModel t_eval: np.ndarray + t_interp: np.ndarray | None def solve_setup(self, parameter, model_, option, value, solver_class): import importlib @@ -51,8 +52,13 @@ def solve_setup(self, parameter, model_, option, value, solver_class): self.model = model_({option: value}) c_rate = 1 tmax = 4000 / c_rate - nb_points = 500 - self.t_eval = np.linspace(0, tmax, nb_points) + if self.solver.supports_interp: + self.t_eval = np.array([0, tmax]) + self.t_interp = None + else: + nb_points = 500 + self.t_eval = np.linspace(0, tmax, nb_points) + self.t_interp = None geometry = self.model.default_geometry # load parameter values and process model and geometry @@ -77,7 +83,7 @@ def solve_setup(self, parameter, model_, option, value, solver_class): disc.process_model(self.model) def solve_model(self, _model, _params): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelLossActiveMaterial: @@ -109,7 +115,7 @@ def setup(self, model, params, solver_class): ) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelLithiumPlating: @@ -141,7 +147,7 @@ def setup(self, model, params, solver_class): ) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelSEI: @@ -187,7 +193,7 @@ def setup(self, model, params, solver_class): SolveModel.solve_setup(self, "Marquis2019", model, "SEI", params, solver_class) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelParticle: @@ -229,7 +235,7 @@ def setup(self, model, params, solver_class): ) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelThermal: @@ -261,7 +267,7 @@ def setup(self, model, params, solver_class): ) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeBuildModelSurfaceForm: @@ -299,4 +305,4 @@ def setup(self, model, params, solver_class): ) def time_solve_model(self, _model, _params, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) diff --git a/benchmarks/time_solve_models.py b/benchmarks/time_solve_models.py index e41a7ccd16..fbd663f540 100644 --- a/benchmarks/time_solve_models.py +++ b/benchmarks/time_solve_models.py @@ -6,8 +6,8 @@ import numpy as np -def solve_model_once(model, solver, t_eval): - solver.solve(model, t_eval=t_eval) +def solve_model_once(model, solver, t_eval, t_interp): + solver.solve(model, t_eval=t_eval, t_interp=t_interp) class TimeSolveSPM: @@ -31,6 +31,7 @@ class TimeSolveSPM: model: pybamm.BaseModel solver: pybamm.BaseSolver t_eval: np.ndarray + t_interp: np.ndarray | None def setup(self, solve_first, parameters, solver_class): set_random_seed() @@ -38,8 +39,14 @@ def setup(self, solve_first, parameters, solver_class): self.model = pybamm.lithium_ion.SPM() c_rate = 1 tmax = 4000 / c_rate - nb_points = 500 - self.t_eval = np.linspace(0, tmax, nb_points) + if self.solver.supports_interp: + self.t_eval = np.array([0, tmax]) + self.t_interp = None + else: + nb_points = 500 + self.t_eval = np.linspace(0, tmax, nb_points) + self.t_interp = None + geometry = self.model.default_geometry # load parameter values and process model and geometry @@ -63,10 +70,10 @@ def setup(self, solve_first, parameters, solver_class): disc = pybamm.Discretisation(mesh, self.model.default_spatial_methods) disc.process_model(self.model) if solve_first: - solve_model_once(self.model, self.solver, self.t_eval) + solve_model_once(self.model, self.solver, self.t_eval, self.t_interp) def time_solve_model(self, _solve_first, _parameters, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeSolveSPMe: @@ -97,8 +104,13 @@ def setup(self, solve_first, parameters, solver_class): self.model = pybamm.lithium_ion.SPMe() c_rate = 1 tmax = 4000 / c_rate - nb_points = 500 - self.t_eval = np.linspace(0, tmax, nb_points) + if self.solver.supports_interp: + self.t_eval = np.array([0, tmax]) + self.t_interp = None + else: + nb_points = 500 + self.t_eval = np.linspace(0, tmax, nb_points) + self.t_interp = None geometry = self.model.default_geometry # load parameter values and process model and geometry @@ -122,10 +134,10 @@ def setup(self, solve_first, parameters, solver_class): disc = pybamm.Discretisation(mesh, self.model.default_spatial_methods) disc.process_model(self.model) if solve_first: - solve_model_once(self.model, self.solver, self.t_eval) + solve_model_once(self.model, self.solver, self.t_eval, self.t_interp) def time_solve_model(self, _solve_first, _parameters, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) class TimeSolveDFN: @@ -161,8 +173,13 @@ def setup(self, solve_first, parameters, solver_class): self.model = pybamm.lithium_ion.DFN() c_rate = 1 tmax = 4000 / c_rate - nb_points = 500 - self.t_eval = np.linspace(0, tmax, nb_points) + if self.solver.supports_interp: + self.t_eval = np.array([0, tmax]) + self.t_interp = None + else: + nb_points = 500 + self.t_eval = np.linspace(0, tmax, nb_points) + self.t_interp = None geometry = self.model.default_geometry # load parameter values and process model and geometry @@ -186,7 +203,7 @@ def setup(self, solve_first, parameters, solver_class): disc = pybamm.Discretisation(mesh, self.model.default_spatial_methods) disc.process_model(self.model) if solve_first: - solve_model_once(self.model, self.solver, self.t_eval) + solve_model_once(self.model, self.solver, self.t_eval, self.t_interp) def time_solve_model(self, _solve_first, _parameters, _solver_class): - self.solver.solve(self.model, t_eval=self.t_eval) + self.solver.solve(self.model, t_eval=self.t_eval, t_interp=self.t_interp) diff --git a/benchmarks/work_precision_sets/time_vs_abstols.py b/benchmarks/work_precision_sets/time_vs_abstols.py index af76493abc..c5ca7b0c01 100644 --- a/benchmarks/work_precision_sets/time_vs_abstols.py +++ b/benchmarks/work_precision_sets/time_vs_abstols.py @@ -42,8 +42,13 @@ model = i[1].new_copy() c_rate = 1 tmax = 3500 / c_rate - nb_points = 500 - t_eval = np.linspace(0, tmax, nb_points) + if solver.supports_interp: + t_eval = np.array([0, tmax]) + t_interp = None + else: + nb_points = 500 + t_eval = np.linspace(0, tmax, nb_points) + t_interp = None geometry = model.default_geometry # load parameter values and process model and geometry @@ -69,11 +74,11 @@ for tol in abstols: solver.atol = tol - solver.solve(model, t_eval=t_eval) + solver.solve(model, t_eval=t_eval, t_interp=t_interp) time = 0 runs = 20 for _ in range(0, runs): - solution = solver.solve(model, t_eval=t_eval) + solution = solver.solve(model, t_eval=t_eval, t_interp=t_interp) time += solution.solve_time.value time = time / runs diff --git a/benchmarks/work_precision_sets/time_vs_mesh_size.py b/benchmarks/work_precision_sets/time_vs_mesh_size.py index 7b8ad525df..866541378a 100644 --- a/benchmarks/work_precision_sets/time_vs_mesh_size.py +++ b/benchmarks/work_precision_sets/time_vs_mesh_size.py @@ -17,6 +17,7 @@ npts = [4, 8, 16, 32, 64] solvers = { + "IDAKLUSolver": pybamm.IDAKLUSolver(), "Casadi - safe": pybamm.CasadiSolver(), "Casadi - fast": pybamm.CasadiSolver(mode="fast"), } diff --git a/benchmarks/work_precision_sets/time_vs_no_of_states.py b/benchmarks/work_precision_sets/time_vs_no_of_states.py index fdc039587f..cf0e34e1ea 100644 --- a/benchmarks/work_precision_sets/time_vs_no_of_states.py +++ b/benchmarks/work_precision_sets/time_vs_no_of_states.py @@ -16,6 +16,7 @@ npts = [4, 8, 16, 32, 64] solvers = { + "IDAKLUSolver": pybamm.IDAKLUSolver(), "Casadi - safe": pybamm.CasadiSolver(), "Casadi - fast": pybamm.CasadiSolver(mode="fast"), } diff --git a/benchmarks/work_precision_sets/time_vs_reltols.py b/benchmarks/work_precision_sets/time_vs_reltols.py index 4afcddf94d..f97c72ba4d 100644 --- a/benchmarks/work_precision_sets/time_vs_reltols.py +++ b/benchmarks/work_precision_sets/time_vs_reltols.py @@ -48,8 +48,13 @@ model = i[1].new_copy() c_rate = 1 tmax = 3500 / c_rate - nb_points = 500 - t_eval = np.linspace(0, tmax, nb_points) + if solver.supports_interp: + t_eval = np.array([0, tmax]) + t_interp = None + else: + nb_points = 500 + t_eval = np.linspace(0, tmax, nb_points) + t_interp = None geometry = model.default_geometry # load parameter values and process model and geometry @@ -75,11 +80,11 @@ for tol in reltols: solver.rtol = tol - solver.solve(model, t_eval=t_eval) + solver.solve(model, t_eval=t_eval, t_interp=t_interp) time = 0 runs = 20 for _ in range(0, runs): - solution = solver.solve(model, t_eval=t_eval) + solution = solver.solve(model, t_eval=t_eval, t_interp=t_interp) time += solution.solve_time.value time = time / runs diff --git a/tests/integration/test_solvers/test_idaklu.py b/tests/integration/test_solvers/test_idaklu.py index abc7741c0c..d70b64c783 100644 --- a/tests/integration/test_solvers/test_idaklu.py +++ b/tests/integration/test_solvers/test_idaklu.py @@ -32,7 +32,7 @@ def test_on_spme_sensitivities(self): disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) t_interp = np.linspace(0, 3500, 100) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] solver = pybamm.IDAKLUSolver(rtol=1e-10, atol=1e-10) solution = solver.solve( model, diff --git a/tests/unit/test_solvers/test_idaklu_solver.py b/tests/unit/test_solvers/test_idaklu_solver.py index 67e68e9c6a..5da4e7e628 100644 --- a/tests/unit/test_solvers/test_idaklu_solver.py +++ b/tests/unit/test_solvers/test_idaklu_solver.py @@ -20,9 +20,7 @@ def test_ida_roberts_klu(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -45,8 +43,10 @@ def test_ida_roberts_klu(self): options={"jax_evaluator": "iree"} if form == "iree" else {}, ) + # Test t_eval = np.linspace(0, 3, 100) - solution = solver.solve(model, t_eval) + t_interp = t_eval + solution = solver.solve(model, t_eval, t_interp=t_interp) # test that final time is time of event # y = 0.1 t + y0 so y=0.2 when t=2 @@ -66,9 +66,7 @@ def test_ida_roberts_klu(self): def test_model_events(self): for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -92,15 +90,8 @@ def test_model_events(self): options={"jax_evaluator": "iree"} if form == "iree" else {}, ) - if model.convert_to_format == "casadi" or ( - model.convert_to_format == "jax" - and solver._options["jax_evaluator"] == "iree" - ): - t_interp = np.linspace(0, 1, 100) - t_eval = np.array([t_interp[0], t_interp[-1]]) - else: - t_eval = np.linspace(0, 1, 100) - t_interp = t_eval + t_interp = np.linspace(0, 1, 100) + t_eval = [t_interp[0], t_interp[-1]] solution = solver.solve(model_disc, t_eval, t_interp=t_interp) np.testing.assert_array_equal( @@ -196,9 +187,7 @@ def test_model_events(self): def test_input_params(self): # test a mix of scalar and vector input params for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -224,7 +213,8 @@ def test_input_params(self): options={"jax_evaluator": "iree"} if form == "iree" else {}, ) - t_eval = np.linspace(0, 3, 100) + t_interp = np.linspace(0, 3, 100) + t_eval = [t_interp[0], t_interp[-1]] a_value = 0.1 b_value = np.array([[0.2], [0.3]]) @@ -232,6 +222,7 @@ def test_input_params(self): model, t_eval, inputs={"a": a_value, "b": b_value}, + t_interp=t_interp, ) # test that y[3] remains constant @@ -254,9 +245,9 @@ def test_input_params(self): def test_sensitivities_initial_condition(self): for form in ["casadi", "iree"]: for output_variables in [[], ["2v"]]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and ( + not pybamm.have_jax() or not pybamm.have_iree() + ): continue if form == "casadi": root_method = "casadi" @@ -283,7 +274,7 @@ def test_sensitivities_initial_condition(self): ) t_interp = np.linspace(0, 3, 100) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] a_value = 0.1 @@ -307,9 +298,7 @@ def test_ida_roberts_klu_sensitivities(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -334,7 +323,7 @@ def test_ida_roberts_klu_sensitivities(self): ) t_interp = np.linspace(0, 3, 100) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] a_value = 0.1 # solve first without sensitivities @@ -415,9 +404,7 @@ def test_ida_roberts_consistent_initialization(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -459,9 +446,7 @@ def test_sensitivities_with_events(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -487,7 +472,7 @@ def test_sensitivities_with_events(self): ) t_interp = np.linspace(0, 3, 100) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] a_value = 0.1 b_value = 0.0 @@ -582,7 +567,7 @@ def test_failures(self): solver = pybamm.IDAKLUSolver() - t_eval = np.linspace(0, 3, 100) + t_eval = [0, 3] with self.assertRaisesRegex(pybamm.SolverError, "KLU requires the Jacobian"): solver.solve(model, t_eval) @@ -597,7 +582,7 @@ def test_failures(self): solver = pybamm.IDAKLUSolver() # will give solver error - t_eval = np.linspace(0, -3, 100) + t_eval = [0, -3] with self.assertRaisesRegex( pybamm.SolverError, "t_eval must increase monotonically" ): @@ -614,15 +599,13 @@ def test_failures(self): solver = pybamm.IDAKLUSolver() - t_eval = np.linspace(0, 3, 100) + t_eval = [0, 3] with self.assertRaisesRegex(pybamm.SolverError, "FAILURE IDA"): solver.solve(model, t_eval) def test_dae_solver_algebraic_model(self): for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -641,7 +624,7 @@ def test_dae_solver_algebraic_model(self): root_method=root_method, options={"jax_evaluator": "iree"} if form == "iree" else {}, ) - t_eval = np.linspace(0, 1) + t_eval = [0, 1] solution = solver.solve(model, t_eval) np.testing.assert_array_equal(solution.y, -1) @@ -661,16 +644,17 @@ def test_banded(self): disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) - t_eval = np.linspace(0, 3600, 100) + t_interp = np.linspace(0, 3600, 100) + t_eval = [t_interp[0], t_interp[-1]] solver = pybamm.IDAKLUSolver() - soln = solver.solve(model, t_eval) + soln = solver.solve(model, t_eval, t_interp=t_interp) options = { "jacobian": "banded", "linear_solver": "SUNLinSol_Band", } solver_banded = pybamm.IDAKLUSolver(options=options) - soln_banded = solver_banded.solve(model, t_eval) + soln_banded = solver_banded.solve(model, t_eval, t_interp=t_interp) np.testing.assert_array_almost_equal(soln.y, soln_banded.y, 5) @@ -685,7 +669,7 @@ def test_setup_options(self): disc.process_model(model) t_interp = np.linspace(0, 1) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] solver = pybamm.IDAKLUSolver() soln_base = solver.solve(model, t_eval, t_interp=t_interp) @@ -750,7 +734,7 @@ def test_setup_options(self): np.testing.assert_array_almost_equal(soln.y, soln_base.y, 4) else: with self.assertRaises(ValueError): - soln = solver.solve(model, t_eval) + soln = solver.solve(model, t_eval, t_interp=t_interp) def test_solver_options(self): model = pybamm.BaseModel() @@ -763,7 +747,7 @@ def test_solver_options(self): disc.process_model(model) t_interp = np.linspace(0, 1) - t_eval = np.array([t_interp[0], t_interp[-1]]) + t_eval = [t_interp[0], t_interp[-1]] solver = pybamm.IDAKLUSolver() soln_base = solver.solve(model, t_eval, t_interp=t_interp) @@ -822,7 +806,8 @@ def test_with_output_variables(self): # the 'output_variables' option for each variable in turn, confirming # equivalence input_parameters = {} # Sensitivities dictionary - t_eval = np.linspace(0, 3600, 100) + t_interp = np.linspace(0, 3600, 100) + t_eval = [t_interp[0], t_interp[-1]] # construct model def construct_model(): @@ -891,6 +876,7 @@ def construct_model(): t_eval, inputs=input_parameters, calculate_sensitivities=True, + t_interp=t_interp, ) # Solve for a subset of variables and compare results @@ -904,6 +890,7 @@ def construct_model(): construct_model(), t_eval, inputs=input_parameters, + t_interp=t_interp, ) # Compare output to sol_all @@ -927,9 +914,7 @@ def test_with_output_variables_and_sensitivities(self): # equivalence for form in ["casadi", "iree"]: - if (form == "jax" or form == "iree") and not pybamm.have_jax(): - continue - if (form == "iree") and not pybamm.have_iree(): + if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): continue if form == "casadi": root_method = "casadi" @@ -953,7 +938,8 @@ def test_with_output_variables_and_sensitivities(self): disc = pybamm.Discretisation(mesh, model.default_spatial_methods) disc.process_model(model) - t_eval = np.linspace(0, 100, 5) + t_interp = np.linspace(0, 100, 5) + t_eval = [t_interp[0], t_interp[-1]] options = { "linear_solver": "SUNLinSol_KLU", @@ -985,6 +971,7 @@ def test_with_output_variables_and_sensitivities(self): t_eval, inputs=input_parameters, calculate_sensitivities=True, + t_interp=t_interp, ) # Solve for a subset of variables and compare results @@ -1000,14 +987,15 @@ def test_with_output_variables_and_sensitivities(self): t_eval, inputs=input_parameters, calculate_sensitivities=True, + t_interp=t_interp, ) # Compare output to sol_all tol = 1e-5 if form != "iree" else 1e-2 # iree has reduced precision for varname in output_variables: np.testing.assert_array_almost_equal( - sol[varname](t_eval), - sol_all[varname](t_eval), + sol[varname](t_interp), + sol_all[varname](t_interp), tol, err_msg=f"Failed for {varname} with form {form}", ) @@ -1114,7 +1102,7 @@ def test_python_idaklu_deprecation_errors(self): disc = pybamm.Discretisation() disc.process_model(model) - t_eval = np.linspace(0, 3, 100) + t_eval = [0, 3] solver = pybamm.IDAKLUSolver( root_method="lm", From ad41dbe9c483ae8cf74a05f37bf16c42769a54e2 Mon Sep 17 00:00:00 2001 From: "Eric G. Kratz" Date: Fri, 30 Aug 2024 15:39:28 -0400 Subject: [PATCH 02/14] Rename have_x to has_x to improve how logic reads (#4398) * Rename functions * style: pre-commit fixes * Update CHANGELOG.md --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 ++ docs/source/api/util.rst | 2 +- examples/scripts/compare_dae_solver.py | 2 +- src/pybamm/__init__.py | 4 ++-- .../operations/evaluate_python.py | 6 ++--- src/pybamm/solvers/idaklu_jax.py | 6 ++--- src/pybamm/solvers/idaklu_solver.py | 6 ++--- src/pybamm/solvers/jax_bdf_solver.py | 4 ++-- src/pybamm/solvers/jax_solver.py | 4 ++-- src/pybamm/util.py | 2 +- .../base_lithium_ion_tests.py | 4 ++-- .../test_lithium_ion/test_mpm.py | 2 +- tests/integration/test_solvers/test_idaklu.py | 2 +- tests/unit/test_citations.py | 4 ++-- .../test_simulation_with_experiment.py | 2 +- .../test_operations/test_evaluate_python.py | 18 +++++++------- tests/unit/test_solvers/test_base_solver.py | 4 ++-- tests/unit/test_solvers/test_idaklu_jax.py | 6 ++--- tests/unit/test_solvers/test_idaklu_solver.py | 24 +++++++++---------- .../unit/test_solvers/test_jax_bdf_solver.py | 4 ++-- tests/unit/test_solvers/test_jax_solver.py | 4 ++-- tests/unit/test_solvers/test_scipy_solver.py | 4 ++-- tests/unit/test_util.py | 2 +- 23 files changed, 59 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38747ea7fb..6c532e839c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ ## Breaking changes +- Replaced `have_jax` with `has_jax`, `have_idaklu` with `has_idaklu`, and + `have_iree` with `has_iree` ([#4398](https://github.com/pybamm-team/PyBaMM/pull/4398)) - Remove deprecated function `pybamm_install_jax` ([#4362](https://github.com/pybamm-team/PyBaMM/pull/4362)) - Removed legacy python-IDAKLU solver. ([#4326](https://github.com/pybamm-team/PyBaMM/pull/4326)) diff --git a/docs/source/api/util.rst b/docs/source/api/util.rst index 7496b59554..824ec6126d 100644 --- a/docs/source/api/util.rst +++ b/docs/source/api/util.rst @@ -16,6 +16,6 @@ Utility functions .. autofunction:: pybamm.load -.. autofunction:: pybamm.have_jax +.. autofunction:: pybamm.has_jax .. autofunction:: pybamm.is_jax_compatible diff --git a/examples/scripts/compare_dae_solver.py b/examples/scripts/compare_dae_solver.py index 815b458f1a..52ead1a242 100644 --- a/examples/scripts/compare_dae_solver.py +++ b/examples/scripts/compare_dae_solver.py @@ -28,7 +28,7 @@ casadi_sol = pybamm.CasadiSolver(atol=1e-8, rtol=1e-8).solve(model, t_eval) solutions = [casadi_sol] -if pybamm.have_idaklu(): +if pybamm.has_idaklu(): klu_sol = pybamm.IDAKLUSolver(atol=1e-8, rtol=1e-8).solve(model, t_eval) solutions.append(klu_sol) else: diff --git a/src/pybamm/__init__.py b/src/pybamm/__init__.py index 75f5f4f160..36ad0b137a 100644 --- a/src/pybamm/__init__.py +++ b/src/pybamm/__init__.py @@ -15,7 +15,7 @@ ) from .util import ( get_parameters_filepath, - have_jax, + has_jax, import_optional_dependency, is_jax_compatible, get_git_commit_info, @@ -170,7 +170,7 @@ from .solvers.jax_bdf_solver import jax_bdf_integrate from .solvers.idaklu_jax import IDAKLUJax -from .solvers.idaklu_solver import IDAKLUSolver, have_idaklu, have_iree +from .solvers.idaklu_solver import IDAKLUSolver, has_idaklu, has_iree # Experiments from .experiment.experiment import Experiment diff --git a/src/pybamm/expression_tree/operations/evaluate_python.py b/src/pybamm/expression_tree/operations/evaluate_python.py index 20a6d4b4a2..a8a37ea7b2 100644 --- a/src/pybamm/expression_tree/operations/evaluate_python.py +++ b/src/pybamm/expression_tree/operations/evaluate_python.py @@ -11,7 +11,7 @@ import pybamm -if pybamm.have_jax(): +if pybamm.has_jax(): import jax platform = jax.lib.xla_bridge.get_backend().platform.casefold() @@ -43,7 +43,7 @@ class JaxCooMatrix: def __init__( self, row: ArrayLike, col: ArrayLike, data: ArrayLike, shape: tuple[int, int] ): - if not pybamm.have_jax(): # pragma: no cover + if not pybamm.has_jax(): # pragma: no cover raise ModuleNotFoundError( "Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver" ) @@ -527,7 +527,7 @@ class EvaluatorJax: """ def __init__(self, symbol: pybamm.Symbol): - if not pybamm.have_jax(): # pragma: no cover + if not pybamm.has_jax(): # pragma: no cover raise ModuleNotFoundError( "Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver" ) diff --git a/src/pybamm/solvers/idaklu_jax.py b/src/pybamm/solvers/idaklu_jax.py index 5a73d42c6e..991c16775e 100644 --- a/src/pybamm/solvers/idaklu_jax.py +++ b/src/pybamm/solvers/idaklu_jax.py @@ -22,7 +22,7 @@ except ImportError: # pragma: no cover idaklu_spec = None -if pybamm.have_jax(): +if pybamm.has_jax(): import jax from jax import lax from jax import numpy as jnp @@ -57,11 +57,11 @@ def __init__( calculate_sensitivities=True, t_interp=None, ): - if not pybamm.have_jax(): + if not pybamm.has_jax(): raise ModuleNotFoundError( "Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver" ) # pragma: no cover - if not pybamm.have_idaklu(): + if not pybamm.has_idaklu(): raise ModuleNotFoundError( "IDAKLU is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/index.html" ) # pragma: no cover diff --git a/src/pybamm/solvers/idaklu_solver.py b/src/pybamm/solvers/idaklu_solver.py index b92006d12d..41e0c8855f 100644 --- a/src/pybamm/solvers/idaklu_solver.py +++ b/src/pybamm/solvers/idaklu_solver.py @@ -14,7 +14,7 @@ import warnings -if pybamm.have_jax(): +if pybamm.has_jax(): import jax from jax import numpy as jnp @@ -33,11 +33,11 @@ idaklu_spec = None -def have_idaklu(): +def has_idaklu(): return idaklu_spec is not None -def have_iree(): +def has_iree(): try: import iree.compiler # noqa: F401 diff --git a/src/pybamm/solvers/jax_bdf_solver.py b/src/pybamm/solvers/jax_bdf_solver.py index 2c7bdc6d17..6f0c62b9a8 100644 --- a/src/pybamm/solvers/jax_bdf_solver.py +++ b/src/pybamm/solvers/jax_bdf_solver.py @@ -7,7 +7,7 @@ import pybamm -if pybamm.have_jax(): +if pybamm.has_jax(): import jax import jax.numpy as jnp from jax import core, dtypes @@ -1007,7 +1007,7 @@ def jax_bdf_integrate(func, y0, t_eval, *args, rtol=1e-6, atol=1e-6, mass=None): calculated state vector at each of the m time points """ - if not pybamm.have_jax(): + if not pybamm.has_jax(): raise ModuleNotFoundError( "Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver" ) diff --git a/src/pybamm/solvers/jax_solver.py b/src/pybamm/solvers/jax_solver.py index 26a069e0fe..da5fd4983a 100644 --- a/src/pybamm/solvers/jax_solver.py +++ b/src/pybamm/solvers/jax_solver.py @@ -6,7 +6,7 @@ import pybamm -if pybamm.have_jax(): +if pybamm.has_jax(): import jax import jax.numpy as jnp from jax.experimental.ode import odeint @@ -59,7 +59,7 @@ def __init__( extrap_tol=None, extra_options=None, ): - if not pybamm.have_jax(): + if not pybamm.has_jax(): raise ModuleNotFoundError( "Jax or jaxlib is not installed, please see https://docs.pybamm.org/en/latest/source/user_guide/installation/gnu-linux-mac.html#optional-jaxsolver" ) diff --git a/src/pybamm/util.py b/src/pybamm/util.py index fd94eb88f4..527c55f526 100644 --- a/src/pybamm/util.py +++ b/src/pybamm/util.py @@ -264,7 +264,7 @@ def get_parameters_filepath(path): return os.path.join(pybamm.__path__[0], path) -def have_jax(): +def has_jax(): """ Check if jax and jaxlib are installed with the correct versions diff --git a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py index eddf2aa1e4..60e8dfb819 100644 --- a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py +++ b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py @@ -22,7 +22,7 @@ def test_sensitivities(self): param = pybamm.ParameterValues("Ecker2015") rtol = 1e-6 atol = 1e-6 - if pybamm.have_idaklu(): + if pybamm.has_idaklu(): solver = pybamm.IDAKLUSolver(rtol=rtol, atol=atol) else: solver = pybamm.CasadiSolver(rtol=rtol, atol=atol) @@ -53,7 +53,7 @@ def test_optimisations(self): to_python = optimtest.evaluate_model(to_python=True) np.testing.assert_array_almost_equal(original, to_python) - if pybamm.have_jax(): + if pybamm.has_jax(): to_jax = optimtest.evaluate_model(to_jax=True) np.testing.assert_array_almost_equal(original, to_jax) diff --git a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_mpm.py b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_mpm.py index 6e67f349fa..00bce1a9d7 100644 --- a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_mpm.py +++ b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_mpm.py @@ -25,7 +25,7 @@ def test_optimisations(self): to_python = optimtest.evaluate_model(to_python=True) np.testing.assert_array_almost_equal(original, to_python) - if pybamm.have_jax(): + if pybamm.has_jax(): to_jax = optimtest.evaluate_model(to_jax=True) np.testing.assert_array_almost_equal(original, to_jax) diff --git a/tests/integration/test_solvers/test_idaklu.py b/tests/integration/test_solvers/test_idaklu.py index d70b64c783..88faa80dde 100644 --- a/tests/integration/test_solvers/test_idaklu.py +++ b/tests/integration/test_solvers/test_idaklu.py @@ -3,7 +3,7 @@ import numpy as np -@pytest.mark.skipif(not pybamm.have_idaklu(), reason="idaklu solver is not installed") +@pytest.mark.skipif(not pybamm.has_idaklu(), reason="idaklu solver is not installed") class TestIDAKLUSolver: def test_on_spme(self): model = pybamm.lithium_ion.SPMe() diff --git a/tests/unit/test_citations.py b/tests/unit/test_citations.py index 0928cc993c..7133cf234a 100644 --- a/tests/unit/test_citations.py +++ b/tests/unit/test_citations.py @@ -423,14 +423,14 @@ def test_solver_citations(self): assert "Virtanen2020" in citations._papers_to_cite assert "Virtanen2020" in citations._citation_tags.keys() - if pybamm.have_idaklu(): + if pybamm.has_idaklu(): citations._reset() assert "Hindmarsh2005" not in citations._papers_to_cite pybamm.IDAKLUSolver() assert "Hindmarsh2005" in citations._papers_to_cite assert "Hindmarsh2005" in citations._citation_tags.keys() - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_jax_citations(self): citations = pybamm.citations citations._reset() diff --git a/tests/unit/test_experiments/test_simulation_with_experiment.py b/tests/unit/test_experiments/test_simulation_with_experiment.py index c4f55889a1..3507d6e5c1 100644 --- a/tests/unit/test_experiments/test_simulation_with_experiment.py +++ b/tests/unit/test_experiments/test_simulation_with_experiment.py @@ -168,7 +168,7 @@ def test_run_experiment_multiple_times(self): sol1["Voltage [V]"].data, sol2["Voltage [V]"].data ) - @unittest.skipIf(not pybamm.have_idaklu(), "idaklu solver is not installed") + @unittest.skipIf(not pybamm.has_idaklu(), "idaklu solver is not installed") def test_run_experiment_cccv_solvers(self): experiment_2step = pybamm.Experiment( [ diff --git a/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py index 518d8f8231..e6d8a0da83 100644 --- a/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py +++ b/tests/unit/test_expression_tree/test_operations/test_evaluate_python.py @@ -12,7 +12,7 @@ from collections import OrderedDict import re -if pybamm.have_jax(): +if pybamm.has_jax(): import jax from tests import ( function_test, @@ -446,7 +446,7 @@ def test_evaluator_python(self): result = evaluator(t=t, y=y) np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_find_symbols_jax(self): # test sparse conversion constant_symbols = OrderedDict() @@ -459,7 +459,7 @@ def test_find_symbols_jax(self): next(iter(constant_symbols.values())).toarray(), A.entries.toarray() ) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax(self): a = pybamm.StateVector(slice(0, 1)) b = pybamm.StateVector(slice(1, 2)) @@ -621,7 +621,7 @@ def test_evaluator_jax(self): result = evaluator(t=t, y=y) np.testing.assert_allclose(result, expr.evaluate(t=t, y=y)) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax_jacobian(self): a = pybamm.StateVector(slice(0, 1)) y_tests = [np.array([[2.0]]), np.array([[1.0]]), np.array([1.0])] @@ -636,7 +636,7 @@ def test_evaluator_jax_jacobian(self): result_true = evaluator_jac(t=None, y=y) np.testing.assert_allclose(result_test, result_true) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax_jvp(self): a = pybamm.StateVector(slice(0, 1)) y_tests = [np.array([[2.0]]), np.array([[1.0]]), np.array([1.0])] @@ -656,7 +656,7 @@ def test_evaluator_jax_jvp(self): np.testing.assert_allclose(result_test, result_true) np.testing.assert_allclose(result_test_times_v, result_true_times_v) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax_debug(self): a = pybamm.StateVector(slice(0, 1)) expr = a**2 @@ -664,7 +664,7 @@ def test_evaluator_jax_debug(self): evaluator = pybamm.EvaluatorJax(expr) evaluator.debug(y=y_test) - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax_inputs(self): a = pybamm.InputParameter("a") expr = a**2 @@ -672,7 +672,7 @@ def test_evaluator_jax_inputs(self): result = evaluator(inputs={"a": 2}) assert result == 4 - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_evaluator_jax_demotion(self): for demote in [True, False]: pybamm.demote_expressions_to_32bit = demote # global flag @@ -734,7 +734,7 @@ def test_evaluator_jax_demotion(self): assert all(str(c_i.dtype)[-2:] == target_dtype for c_i in c_demoted.col) pybamm.demote_expressions_to_32bit = False - @pytest.mark.skipif(not pybamm.have_jax(), reason="jax or jaxlib is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="jax or jaxlib is not installed") def test_jax_coo_matrix(self): A = pybamm.JaxCooMatrix([0, 1], [0, 1], [1.0, 2.0], (2, 2)) Adense = jax.numpy.array([[1.0, 0], [0, 2.0]]) diff --git a/tests/unit/test_solvers/test_base_solver.py b/tests/unit/test_solvers/test_base_solver.py index e86b0f702e..a4b43e1dd2 100644 --- a/tests/unit/test_solvers/test_base_solver.py +++ b/tests/unit/test_solvers/test_base_solver.py @@ -355,12 +355,12 @@ def test_multiprocess_context(self): assert solver.get_platform_context("Linux") == "fork" assert solver.get_platform_context("Darwin") == "fork" - @unittest.skipIf(not pybamm.have_idaklu(), "idaklu solver is not installed") + @unittest.skipIf(not pybamm.has_idaklu(), "idaklu solver is not installed") def test_sensitivities(self): def exact_diff_a(y, a, b): return np.array([[y[0] ** 2 + 2 * a], [y[0]]]) - @unittest.skipIf(not pybamm.have_jax(), "jax or jaxlib is not installed") + @unittest.skipIf(not pybamm.has_jax(), "jax or jaxlib is not installed") def exact_diff_b(y, a, b): return np.array([[y[0]], [0]]) diff --git a/tests/unit/test_solvers/test_idaklu_jax.py b/tests/unit/test_solvers/test_idaklu_jax.py index d985991929..a99f108f40 100644 --- a/tests/unit/test_solvers/test_idaklu_jax.py +++ b/tests/unit/test_solvers/test_idaklu_jax.py @@ -9,7 +9,7 @@ import unittest testcase = [] -if pybamm.have_idaklu() and pybamm.have_jax(): +if pybamm.has_idaklu() and pybamm.has_jax(): from jax.tree_util import tree_flatten import jax import jax.numpy as jnp @@ -87,7 +87,7 @@ def no_jit(f): # Check the interface throws an appropriate error if either IDAKLU or JAX not available @unittest.skipIf( - pybamm.have_idaklu() and pybamm.have_jax(), + pybamm.has_idaklu() and pybamm.has_jax(), "Both IDAKLU and JAX are available", ) class TestIDAKLUJax_NoJax(unittest.TestCase): @@ -97,7 +97,7 @@ def test_instantiate_fails(self): @unittest.skipIf( - not pybamm.have_idaklu() or not pybamm.have_jax(), + not pybamm.has_idaklu() or not pybamm.has_jax(), "IDAKLU Solver and/or JAX are not available", ) class TestIDAKLUJax(unittest.TestCase): diff --git a/tests/unit/test_solvers/test_idaklu_solver.py b/tests/unit/test_solvers/test_idaklu_solver.py index 5da4e7e628..5d71b5f945 100644 --- a/tests/unit/test_solvers/test_idaklu_solver.py +++ b/tests/unit/test_solvers/test_idaklu_solver.py @@ -13,14 +13,14 @@ @pytest.mark.cibw -@unittest.skipIf(not pybamm.have_idaklu(), "idaklu solver is not installed") +@unittest.skipIf(not pybamm.has_idaklu(), "idaklu solver is not installed") class TestIDAKLUSolver(unittest.TestCase): def test_ida_roberts_klu(self): # this test implements a python version of the ida Roberts # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -66,7 +66,7 @@ def test_ida_roberts_klu(self): def test_model_events(self): for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -187,7 +187,7 @@ def test_model_events(self): def test_input_params(self): # test a mix of scalar and vector input params for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -245,9 +245,7 @@ def test_input_params(self): def test_sensitivities_initial_condition(self): for form in ["casadi", "iree"]: for output_variables in [[], ["2v"]]: - if (form == "iree") and ( - not pybamm.have_jax() or not pybamm.have_iree() - ): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -298,7 +296,7 @@ def test_ida_roberts_klu_sensitivities(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -404,7 +402,7 @@ def test_ida_roberts_consistent_initialization(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -446,7 +444,7 @@ def test_sensitivities_with_events(self): # example provided in sundials # see sundials ida examples pdf for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -605,7 +603,7 @@ def test_failures(self): def test_dae_solver_algebraic_model(self): for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -914,7 +912,7 @@ def test_with_output_variables_and_sensitivities(self): # equivalence for form in ["casadi", "iree"]: - if (form == "iree") and (not pybamm.have_jax() or not pybamm.have_iree()): + if (form == "iree") and (not pybamm.has_jax() or not pybamm.has_iree()): continue if form == "casadi": root_method = "casadi" @@ -1087,7 +1085,7 @@ def test_interpolate_time_step_start_offset(self): def test_python_idaklu_deprecation_errors(self): for form in ["python", "", "jax"]: - if form == "jax" and not pybamm.have_jax(): + if form == "jax" and not pybamm.has_jax(): continue model = pybamm.BaseModel() diff --git a/tests/unit/test_solvers/test_jax_bdf_solver.py b/tests/unit/test_solvers/test_jax_bdf_solver.py index e02bdb2510..e0064ae463 100644 --- a/tests/unit/test_solvers/test_jax_bdf_solver.py +++ b/tests/unit/test_solvers/test_jax_bdf_solver.py @@ -5,11 +5,11 @@ import sys import numpy as np -if pybamm.have_jax(): +if pybamm.has_jax(): import jax -@unittest.skipIf(not pybamm.have_jax(), "jax or jaxlib is not installed") +@unittest.skipIf(not pybamm.has_jax(), "jax or jaxlib is not installed") class TestJaxBDFSolver(unittest.TestCase): def test_solver_(self): # Trailing _ manipulates the random seed # Create model diff --git a/tests/unit/test_solvers/test_jax_solver.py b/tests/unit/test_solvers/test_jax_solver.py index 4f34497626..b1c293c2f2 100644 --- a/tests/unit/test_solvers/test_jax_solver.py +++ b/tests/unit/test_solvers/test_jax_solver.py @@ -5,11 +5,11 @@ import sys import numpy as np -if pybamm.have_jax(): +if pybamm.has_jax(): import jax -@unittest.skipIf(not pybamm.have_jax(), "jax or jaxlib is not installed") +@unittest.skipIf(not pybamm.has_jax(), "jax or jaxlib is not installed") class TestJaxSolver(unittest.TestCase): def test_model_solver(self): # Create model diff --git a/tests/unit/test_solvers/test_scipy_solver.py b/tests/unit/test_solvers/test_scipy_solver.py index c6afd16704..446206e95c 100644 --- a/tests/unit/test_solvers/test_scipy_solver.py +++ b/tests/unit/test_solvers/test_scipy_solver.py @@ -11,7 +11,7 @@ class TestScipySolver(unittest.TestCase): def test_model_solver_python_and_jax(self): - if pybamm.have_jax(): + if pybamm.has_jax(): formats = ["python", "jax"] else: formats = ["python"] @@ -339,7 +339,7 @@ def test_model_solver_multiple_inputs_initial_conditions_error(self): solver.solve(model, t_eval, inputs=inputs_list, nproc=2) def test_model_solver_multiple_inputs_jax_format(self): - if pybamm.have_jax(): + if pybamm.has_jax(): # Create model model = pybamm.BaseModel() model.convert_to_format = "jax" diff --git a/tests/unit/test_util.py b/tests/unit/test_util.py index 1b621d98f0..058b7d4a14 100644 --- a/tests/unit/test_util.py +++ b/tests/unit/test_util.py @@ -88,7 +88,7 @@ def test_get_parameters_filepath(self): path = os.path.join(package_dir, tempfile_obj.name) assert pybamm.get_parameters_filepath(tempfile_obj.name) == path - @pytest.mark.skipif(not pybamm.have_jax(), reason="JAX is not installed") + @pytest.mark.skipif(not pybamm.has_jax(), reason="JAX is not installed") def test_is_jax_compatible(self): assert pybamm.is_jax_compatible() From 16e06f598dc60d7469d617a05a2fd1a68d22e76b Mon Sep 17 00:00:00 2001 From: Santhosh <52504160+santacodes@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:24:58 +0530 Subject: [PATCH 03/14] `uv` support in CI (#4353) * Using uv for testing and benchmark workflows * fix failing notebook tests --- .github/workflows/benchmark_on_push.yml | 7 +++++-- .github/workflows/periodic_benchmarks.yml | 7 +++++-- .github/workflows/run_periodic_tests.yml | 20 ++++++++++++++---- .github/workflows/test_on_push.yml | 25 ++++++++++++++++++----- noxfile.py | 4 ++-- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/.github/workflows/benchmark_on_push.yml b/.github/workflows/benchmark_on_push.yml index b0da71461e..2883eb5f26 100644 --- a/.github/workflows/benchmark_on_push.yml +++ b/.github/workflows/benchmark_on_push.yml @@ -23,10 +23,13 @@ jobs: sudo apt-get update sudo apt install gfortran gcc libopenblas-dev + - name: Set up uv + run: python -m pip install uv + - name: Install python dependencies run: | - python -m pip install --upgrade pip wheel setuptools wget cmake casadi numpy - python -m pip install asv[virtualenv] + python -m uv pip install --upgrade pip wheel setuptools wget cmake casadi numpy + python -m uv pip install asv[virtualenv] - name: Install SuiteSparse and SUNDIALS run: python scripts/install_KLU_Sundials.py diff --git a/.github/workflows/periodic_benchmarks.yml b/.github/workflows/periodic_benchmarks.yml index faa008ff05..641627c0ba 100644 --- a/.github/workflows/periodic_benchmarks.yml +++ b/.github/workflows/periodic_benchmarks.yml @@ -31,10 +31,13 @@ jobs: sudo apt-get update sudo apt-get install gfortran gcc libopenblas-dev + - name: Set up uv + run: python -m pip install uv + - name: Install python dependencies run: | - python -m pip install --upgrade pip wheel setuptools wget cmake casadi numpy - python -m pip install asv[virtualenv] + python -m uv pip install --upgrade pip wheel setuptools wget cmake casadi numpy + python -m uv pip install asv[virtualenv] - name: Install SuiteSparse and SUNDIALS run: python scripts/install_KLU_Sundials.py diff --git a/.github/workflows/run_periodic_tests.yml b/.github/workflows/run_periodic_tests.yml index 2dd9ef8a89..9f10a9c6f7 100644 --- a/.github/workflows/run_periodic_tests.yml +++ b/.github/workflows/run_periodic_tests.yml @@ -68,8 +68,11 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Install SuiteSparse and SUNDIALS on GNU/Linux and macOS timeout-minutes: 10 @@ -114,8 +117,11 @@ jobs: with: python-version: 3.11 + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Install docs dependencies and run doctests for GNU/Linux run: python -m nox -s doctests @@ -141,8 +147,11 @@ jobs: with: python-version: 3.12 + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Install SuiteSparse and SUNDIALS on GNU/Linux timeout-minutes: 10 @@ -169,8 +178,11 @@ jobs: with: python-version: 3.12 + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Install SuiteSparse and SUNDIALS on GNU/Linux timeout-minutes: 10 diff --git a/.github/workflows/test_on_push.yml b/.github/workflows/test_on_push.yml index adfb698a69..9224b7df36 100644 --- a/.github/workflows/test_on_push.yml +++ b/.github/workflows/test_on_push.yml @@ -27,9 +27,12 @@ jobs: with: python-version: 3.12 + - name: Set up uv + run: python -m pip install uv + - name: Check style run: | - python -m pip install pre-commit + python -m uv pip install pre-commit pre-commit run -a run_unit_integration_and_coverage_tests: @@ -86,8 +89,11 @@ jobs: python-version: ${{ matrix.python-version }} cache: 'pip' + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Cache pybamm-requires nox environment for GNU/Linux and macOS uses: actions/cache@v4 @@ -158,8 +164,11 @@ jobs: python-version: 3.11 cache: 'pip' + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Install docs dependencies and run doctests for GNU/Linux run: python -m nox -s doctests @@ -198,8 +207,11 @@ jobs: python-version: 3.12 cache: 'pip' + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Cache pybamm-requires nox environment for GNU/Linux uses: actions/cache@v4 @@ -251,8 +263,11 @@ jobs: python-version: 3.12 cache: 'pip' + - name: Set up uv + run: python -m pip install uv + - name: Install nox - run: python -m pip install nox + run: python -m uv pip install nox[uv] - name: Cache pybamm-requires nox environment for GNU/Linux uses: actions/cache@v4 diff --git a/noxfile.py b/noxfile.py index a34d6e81f4..6567ed167c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -7,7 +7,7 @@ # Options to modify nox behaviour -nox.options.default_venv_backend = "virtualenv" +nox.options.default_venv_backend = "uv|virtualenv" nox.options.reuse_existing_virtualenvs = True if sys.platform != "win32": nox.options.sessions = ["pre-commit", "pybamm-requires", "unit"] @@ -207,7 +207,7 @@ def run_examples(session): """Run the examples tests for Jupyter notebooks.""" set_environment_variables(PYBAMM_ENV, session=session) session.install("setuptools", silent=False) - session.install("-e", ".[all,dev]", silent=False) + session.install("-e", ".[all,dev,jax]", silent=False) notebooks_to_test = session.posargs if session.posargs else [] session.run( "pytest", "--nbmake", *notebooks_to_test, "docs/source/examples/", external=True From 4b4b98befd41dc9a0b18faf8dfc3fe70375cb801 Mon Sep 17 00:00:00 2001 From: "Eric G. Kratz" Date: Mon, 2 Sep 2024 10:20:26 -0400 Subject: [PATCH 04/14] Streamline release process (#4376) * Modify update version workflow * Simplify workflow * A few more fixes * Style * Fix link errors * Remove manual trigger * Remove redundant work * Fix workflow text * Test workflow * Change target branch * Fix * Remove some test code --- .github/release_workflow.md | 97 +++++++++++++++------------- .github/workflows/update_version.yml | 79 +++------------------- 2 files changed, 60 insertions(+), 116 deletions(-) diff --git a/.github/release_workflow.md b/.github/release_workflow.md index 89a22e7d38..00c7b73dbf 100644 --- a/.github/release_workflow.md +++ b/.github/release_workflow.md @@ -1,10 +1,13 @@ # Release workflow -This file contains the workflow required to make a `PyBaMM` release on GitHub, PyPI, and conda-forge by the maintainers. +This file contains the workflow required to make a `PyBaMM` release on +GitHub, PyPI, and conda-forge by the maintainers. -## rc0 releases (automated) +## Initial release (automated) -1. The `update_version.yml` workflow will run on every 1st of January, May and September, updating incrementing the version to `vYY.MMrc0` by running `scripts/update_version.py` in the following files - +1. The `update_version.yml` workflow will run on every 1st of January, May + and September, updating incrementing the version to `vYY.MM.0` by running + `scripts/update_version.py` in the following files: - `pybamm/version.py` - `docs/conf.py` @@ -13,21 +16,27 @@ This file contains the workflow required to make a `PyBaMM` release on GitHub, P - `vcpkg.json` - `CHANGELOG.md` - These changes will be automatically pushed to a new branch `vYY.MM` and a PR from `vvYY.MM` to `develop` will be created (to sync the branches). + These changes will be automatically pushed to a new branch `vYY.MM` + and a PR from `vYY.MM` to `main` will be created. -2. Create a new GitHub _pre-release_ with the tag `vYY.MMrc0` from the `vYY.MM` branch and a description copied from `CHANGELOG.md`. +2. Create a new GitHub _release_ with the tag `vYY.MM.0` from the `vYY.MM` + branch and a description copied from `CHANGELOG.md`. -3. This release will automatically trigger `publish_pypi.yml` and create a _pre-release_ on PyPI. +3. This release will automatically trigger `publish_pypi.yml` and create a + _release_ on PyPI. -## rcX releases (manual) +## Bug fix releases (manual) -If a new release candidate is required after the release of `rc{X-1}` - +If a new release is required after the release of `vYY.MM.{x-1}` - -1. Cherry-pick the bug fix (no new features should be added to `vYY.MM` once `rc{X-1}` is released) commit to `vYY.MM` branch once the fix is merged into `develop`. The CHANGELOG entry for such fixes should go under the `rc{X-1}` heading in `CHANGELOG.md` +1. Create a new branch for the `vYY.MM.x` release using the `vYY.MM.{x-1}` tag. -2. Run `update_version.yml` manually while using `append_to_tag` to specify the release candidate version number (`rc1`, `rc2`, ...). +2. Cherry-pick the bug fixes to `vYY.MM.x` branch once the fix is + merged into `develop`. The CHANGELOG entry for such fixes should go under the + `YY.MM.x` heading in `CHANGELOG.md` -3. This will increment the version to `vYY.MMrcX` by running `scripts/update_version.py` in the following files - +3. Run `scripts/update_version.py` manually while setting `VERSION=vYY.MM.x` + in your environment. This will update the version in the following files: - `pybamm/version.py` - `docs/conf.py` @@ -36,45 +45,41 @@ If a new release candidate is required after the release of `rc{X-1}` - - `vcpkg.json` - `CHANGELOG.md` - These changes will be automatically pushed to the existing `vYY.MM` branch and a PR will be created to update version strings in `develop`. + Commit the changes to your release branch. -4. Create a new GitHub _pre-release_ with the same tag (`vYY.MMrcX`) from the `vYY.MM` branch and a description copied from `CHANGELOG.md`. +4. Create a PR for the release and configure it to merge into the `main` branch. -5. This release will automatically trigger `publish_pypi.yml` and create a _pre-release_ on PyPI. - -## Actual release (manual) - -Once satisfied with the release candidates - - -1. Run `update_version.yml` manually, leaving the `append_to_tag` field blank ("") for an actual release. - -2. This will increment the version to `vYY.MMrcX` by running `scripts/update_version.py` in the following files - - - - `pybamm/version.py` - - `docs/conf.py` - - `CITATION.cff` - - `pyproject.toml` - - `vcpkg.json` - - `CHANGELOG.md` - - These changes will be automatically pushed to the existing `vYY.MM` branch and a PR will be created to update version strings in `develop`. - -3. Next, a PR from `vYY.MM` to `main` will be generated that should be merged once all the tests pass. - -4. Create a new GitHub _release_ with the same tag from the `main` branch and a description copied from `CHANGELOG.md`. - -5. This release will automatically trigger `publish_pypi.yml` and create a _release_ on PyPI. +5. Create a new GitHub release with the same tag (`YY.MM.x`) from the `main` + branch and a description copied from `CHANGELOG.md`. This release will + automatically trigger `publish_pypi.yml` and create a _release_ on PyPI. ## Other checks Some other essential things to check throughout the release process - -- If updating our custom vcpkg registory entries [pybamm-team/sundials-vcpkg-registry](https://github.com/pybamm-team/sundials-vcpkg-registry) or [pybamm-team/casadi-vcpkg-registry](https://github.com/pybamm-team/casadi-vcpkg-registry) (used to build Windows wheels), make sure to update the baseline of the registories in vcpkg-configuration.json to the latest commit id. -- Update jax and jaxlib to the latest version in `pybamm.util` and `pyproject.toml`, fixing any bugs that arise -- As the release workflow is initiated by the `release` event, it's important to note that the default `GITHUB_REF` used by `actions/checkout` during the checkout process will correspond to the tag created during the release process. Consequently, the workflows will consistently build PyBaMM based on the commit associated with this tag. Should new commits be introduced to the `vYY.MM` branch, such as those addressing build issues, it becomes necessary to manually update this tag to point to the most recent commit - - ``` - git tag -f - git push -f # can only be carried out by the maintainers - ``` -- If changes are made to the API, console scripts, entry points, new optional dependencies are added, support for major Python versions is dropped or added, or core project information and metadata are modified at the time of the release, make sure to update the `meta.yaml` file in the `recipe/` folder of the [conda-forge/pybamm-feedstock](https://github.com/conda-forge/pybamm-feedstock) repository accordingly by following the instructions in the [conda-forge documentation](https://conda-forge.org/docs/maintainer/updating_pkgs.html#updating-the-feedstock-repository) and re-rendering the recipe -- The conda-forge release workflow will automatically be triggered following a stable PyPI release, and the aforementioned updates should be carried out directly in the main repository by pushing changes to the automated PR created by the conda-forge-bot. A manual PR can also be created if the updates are not included in the automated PR for some reason. This manual PR **must** bump the build number in `meta.yaml` and **must** be from a personal fork of the repository. +- If updating our custom vcpkg registry entries + [sundials-vcpkg-registry][SUNDIALS_VCPKG] + or [casadi-vcpkg-registry][CASADI_VCPKG] (used to build Windows + wheels), make sure to update the baseline of the registries in + vcpkg-configuration.json to the latest commit id. +- Update jax and jaxlib to the latest version in `pybamm.util` and + `pyproject.toml`, fixing any bugs that arise. +- If changes are made to the API, console scripts, entry points, new optional + dependencies are added, support for major Python versions is dropped or + added, or core project information and metadata are modified at the time + of the release, make sure to update the `meta.yaml` file in the `recipe/` + folder of the [pybamm-feedstock][PYBAMM_FEED] repository accordingly by + following the instructions in the [conda-forge documentation][FEED_GUIDE] and + re-rendering the recipe. +- The conda-forge release workflow will automatically be triggered following + a stable PyPI release, and the aforementioned updates should be carried + out directly in the main repository by pushing changes to the automated PR + created by the conda-forge-bot. A manual PR can also be created if the + updates are not included in the automated PR for some reason. This manual + PR **must** bump the build number in `meta.yaml` and **must** be from a + personal fork of the repository. + +[SUNDIALS_VCPKG]: https://github.com/pybamm-team/sundials-vcpkg-registry +[CASADI_VCPKG]: https://github.com/pybamm-team/casadi-vcpkg-registry +[PYBAMM_FEED]: https://github.com/conda-forge/pybamm-feedstock +[FEED_GUIDE]: https://conda-forge.org/docs/maintainer/updating_pkgs.html#updating-the-feedstock-repository diff --git a/.github/workflows/update_version.yml b/.github/workflows/update_version.yml index eb62469778..899667d2de 100644 --- a/.github/workflows/update_version.yml +++ b/.github/workflows/update_version.yml @@ -1,11 +1,6 @@ name: Update version on: - workflow_dispatch: - inputs: - append_to_tag: - description: 'Leave blank for an actual release or "rc1", "rc2", ..., for release candidates."' - default: "" schedule: # Run at 10 am UTC on day-of-month 1 in January, May, and September. - cron: "0 10 1 1,5,9 *" @@ -18,29 +13,13 @@ jobs: steps: - name: Get current date for the first release candidate - if: github.event_name == 'schedule' run: | - echo "VERSION=$(date +'v%y.%-m')rc0" >> $GITHUB_ENV - echo "NON_RC_VERSION=$(date +'v%y.%-m')" >> $GITHUB_ENV + echo "VERSION=$(date +'v%y.%-m').0" >> $GITHUB_ENV - - name: Get current date for a manual release - if: github.event_name == 'workflow_dispatch' - run: | - echo "VERSION=$(date +'v%y.%-m')${{ github.event.inputs.append_to_tag }}" >> $GITHUB_ENV - echo "NON_RC_VERSION=$(date +'v%y.%-m')" >> $GITHUB_ENV - - # the schedule workflow is for rc0 release - uses: actions/checkout@v4 - if: github.event_name == 'schedule' with: ref: 'develop' - # the dispatch workflow is for rcX and final releases - - uses: actions/checkout@v4 - if: github.event_name == 'workflow_dispatch' - with: - ref: '${{ env.NON_RC_VERSION }}' - - name: Set up Python uses: actions/setup-python@v5 with: @@ -48,65 +27,25 @@ jobs: - name: Install dependencies run: | - pip install wheel - pip install --editable ".[all]" + pip install -e ".[all]" - # update all the version strings and add CHANGELOG headings + # Update all the version strings and add CHANGELOG headings - name: Update version run: python scripts/update_version.py - # create a new version branch for rc0 release and commit + # Create a new version branch for the release and commit - uses: EndBug/add-and-commit@v9 - if: github.event_name == 'schedule' with: message: 'Bump to ${{ env.VERSION }}' - new_branch: '${{ env.NON_RC_VERSION }}' - - # use the already created release branch for rcX + final releases - # and commit - - uses: EndBug/add-and-commit@v9 - if: github.event_name == 'workflow_dispatch' - with: - message: 'Bump to ${{ env.VERSION }}' - - # checkout to develop for updating versions in the same - - uses: actions/checkout@v4 - with: - ref: 'develop' - - # update all the version strings - - name: Update version - if: github.event_name == 'workflow_dispatch' - run: python scripts/update_version.py - - # create a pull request updating versions in develop - - name: Create Pull Request - id: version_pr - uses: peter-evans/create-pull-request@v6 - with: - delete-branch: true - branch-suffix: short-commit-hash - base: develop - commit-message: Update version to ${{ env.VERSION }} - title: Bump to ${{ env.VERSION }} - body: | - - [x] Update to ${{ env.VERSION }} - - [ ] Check the [release workflow](https://github.com/pybamm-team/PyBaMM/blob/develop/.github/release_workflow.md) - - # checkout to the version branch for the final release - - uses: actions/checkout@v4 - if: github.event_name == 'workflow_dispatch' && !startsWith(github.event.inputs.append_to_tag, 'rc') - with: - ref: '${{ env.NON_RC_VERSION }}' + new_branch: '${{ env.VERSION }}' - # for final releases, create a PR from version branch to main - - name: Make a PR from ${{ env.NON_RC_VERSION }} to main + # Create a PR from version branch to main + - name: Make a PR from ${{ env.VERSION }} to main id: release_pr - if: github.event_name == 'workflow_dispatch' && !startsWith(github.event.inputs.append_to_tag, 'rc') uses: repo-sync/pull-request@v2 with: - source_branch: '${{ env.NON_RC_VERSION }}' + source_branch: '${{ env.VERSION }}' destination_branch: "main" - pr_title: "Make release ${{ env.NON_RC_VERSION }}" + pr_title: "Make release ${{ env.VERSION }}" pr_body: "**Check the [release workflow](https://github.com/pybamm-team/PyBaMM/blob/develop/.github/release_workflow.md)**" github_token: ${{ secrets.GITHUB_TOKEN }} From 396741eec6076a83c3104aa9b73d2f7957201ab7 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 2 Sep 2024 22:04:34 +0530 Subject: [PATCH 05/14] Fix CasADi libs workaround for macOS wheels, update to CasADi 3.6.6 for Windows wheels (#4391) * Fix CasADi libs workaround for macOS wheels * Bump to CasADi 3.6.6 * Update vcpkg baseline for CasADi 3.6.6 update * libc++ is still not fixed * Fix a typo in the build-system table * Fix GHA macOS versions for images * Fix Windows access violation with `msvcp140.dll` --------- Co-authored-by: Eric G. Kratz --- .github/workflows/publish_pypi.yml | 11 ++++++----- pyproject.toml | 6 +++--- vcpkg-configuration.json | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml index 7482f03003..9ca277b653 100644 --- a/.github/workflows/publish_pypi.yml +++ b/.github/workflows/publish_pypi.yml @@ -84,7 +84,9 @@ jobs: CMAKE_BUILD_PARALLEL_LEVEL=${{ steps.get_num_cores.outputs.count }} CIBW_ARCHS: AMD64 CIBW_BEFORE_BUILD: python -m pip install setuptools wheel delvewheel # skip CasADi and CMake - CIBW_REPAIR_WHEEL_COMMAND: delvewheel repair -w {dest_dir} {wheel} + # Fix access violation because GHA runners have modified PATH that picks wrong + # msvcp140.dll, see https://github.com/adang1345/delvewheel/issues/54 + CIBW_REPAIR_WHEEL_COMMAND: delvewheel repair --add-path C:/Windows/System32 -w {dest_dir} {wheel} CIBW_TEST_EXTRAS: "all,dev,jax" CIBW_TEST_COMMAND: | python -c "import pybamm; print(pybamm.IDAKLUSolver())" @@ -149,9 +151,6 @@ jobs: - name: Clone pybind11 repo (no history) run: git clone --depth 1 --branch v2.12.0 https://github.com/pybind/pybind11.git -c advice.detachedHead=false - - name: Set macOS-specific environment variables - run: echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV - - name: Install cibuildwheel run: python -m pip install cibuildwheel @@ -243,13 +242,15 @@ jobs: python scripts/install_KLU_Sundials.py python -m cibuildwheel --output-dir wheelhouse env: + # 10.13 for Intel (macos-12/macos-13), 11.0 for Apple Silicon (macos-14 and macos-latest) + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os == 'macos-14' && '11.0' || '10.13' }} CIBW_ARCHS_MACOS: auto CIBW_BEFORE_BUILD: python -m pip install cmake casadi setuptools wheel delocate CIBW_REPAIR_WHEEL_COMMAND: | if [[ $(uname -m) == "x86_64" ]]; then delocate-listdeps {wheel} && delocate-wheel -v -w {dest_dir} {wheel} elif [[ $(uname -m) == "arm64" ]]; then - # Use higher macOS target for now: https://github.com/casadi/casadi/issues/3698 + # Use higher macOS target for now since casadi/libc++.1.0.dylib is still not fixed delocate-listdeps {wheel} && delocate-wheel -v -w {dest_dir} {wheel} --require-target-macos-version 11.1 for file in {dest_dir}/*.whl; do mv "$file" "${file//macosx_11_1/macosx_11_0}"; done fi diff --git a/pyproject.toml b/pyproject.toml index e4cce3eccd..34ccd05e20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,9 @@ requires = [ "setuptools>=64", "wheel", # On Windows, use the CasADi vcpkg registry and CMake bundled from MSVC - "casadi>=3.6.5; platform_system!='Windows'", + "casadi>=3.6.6; platform_system!='Windows'", # Note: the version of CasADi as a build-time dependency should be matched - # cross platforms, so updates to its minimum version here should be accompanied + # across platforms, so updates to its minimum version here should be accompanied # by a version bump in https://github.com/pybamm-team/casadi-vcpkg-registry. "cmake; platform_system!='Windows'", ] @@ -37,7 +37,7 @@ classifiers = [ dependencies = [ "numpy>=1.23.5,<2.0.0", "scipy>=1.11.4", - "casadi>=3.6.5", + "casadi>=3.6.6", "xarray>=2022.6.0", "anytree>=2.8.0", "sympy>=1.12", diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 11505be46e..8d5c64ac47 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -13,7 +13,7 @@ { "kind": "git", "repository": "https://github.com/pybamm-team/casadi-vcpkg-registry.git", - "baseline": "ceee3ed50246744cdef43517d7d7617b8ac291e7", + "baseline": "1cb93f2fb71be26c874db724940ef8e604ee558e", "packages": ["casadi"] } ] From 1ab27d1e3721e1d150d7f548e14f343c2cbdfdfc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 03:26:10 +0530 Subject: [PATCH 06/14] chore: update pre-commit hooks (#4404) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.2 → v0.6.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.2...v0.6.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .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 835678e034..43928bbc56 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.6.2" + rev: "v0.6.3" hooks: - id: ruff args: [--fix, --show-fixes] From bac7570b9bb85c3372dd32f09c8059a899b31c0e Mon Sep 17 00:00:00 2001 From: kratman Date: Tue, 3 Sep 2024 11:46:41 -0400 Subject: [PATCH 07/14] Fix update version script --- scripts/update_version.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/scripts/update_version.py b/scripts/update_version.py index 3543f0b07b..a8fd884537 100644 --- a/scripts/update_version.py +++ b/scripts/update_version.py @@ -6,9 +6,6 @@ import os import re from datetime import date -from dateutil.relativedelta import relativedelta - - import pybamm @@ -17,11 +14,7 @@ def update_version(): Opens file and updates the version number """ release_version = os.getenv("VERSION")[1:] - release_date = ( - date.today() - if "rc" in release_version - else date.today() + relativedelta(day=31) - ) + release_date = date.today() # pybamm/version.py with open( @@ -84,15 +77,7 @@ def update_version(): with open(os.path.join(pybamm.root_dir(), "CHANGELOG.md"), "r+") as file: output_list = file.readlines() output_list[0] = changelog_line1 - # add a new heading for rc0 releases - if "rc0" in release_version: - output_list.insert(2, changelog_line2) - else: - # for rcX and final releases, update the already existing rc - # release heading - for i in range(0, len(output_list)): - if re.search("[v]\d\d\.\drc\d", output_list[i]): - output_list[i] = changelog_line2[:-1] + output_list.insert(2, changelog_line2) file.truncate(0) file.seek(0) file.writelines(output_list) From c212bb03b3e6bfb13fd2005b479586ee187d951a Mon Sep 17 00:00:00 2001 From: kratman Date: Tue, 3 Sep 2024 12:24:46 -0400 Subject: [PATCH 08/14] Update change log --- CHANGELOG.md | 2 ++ CITATION.cff | 2 +- pyproject.toml | 2 +- src/pybamm/version.py | 2 +- vcpkg.json | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c532e839c..f5a959748f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # [Unreleased](https://github.com/pybamm-team/PyBaMM/) +# [v24.9.0](https://github.com/pybamm-team/PyBaMM/tree/v24.9.0) - 2024-09-03 + ## Features - Added additional user-configurable options to the (`IDAKLUSolver`) and adjusted the default values to improve performance. ([#4282](https://github.com/pybamm-team/PyBaMM/pull/4282)) diff --git a/CITATION.cff b/CITATION.cff index cc2479e8f3..d128cf485e 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -24,6 +24,6 @@ keywords: - "expression tree" - "python" - "symbolic differentiation" -version: "24.5" +version: "24.9.0" repository-code: "https://github.com/pybamm-team/PyBaMM" title: "Python Battery Mathematical Modelling (PyBaMM)" diff --git a/pyproject.toml b/pyproject.toml index 34ccd05e20..7fb1a5ce95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ build-backend = "setuptools.build_meta" [project] name = "pybamm" -version = "24.5" +version = "24.9.0" license = { file = "LICENSE.txt" } description = "Python Battery Mathematical Modelling" authors = [{name = "The PyBaMM Team", email = "pybamm@pybamm.org"}] diff --git a/src/pybamm/version.py b/src/pybamm/version.py index edeca1094b..ca0cfd956e 100644 --- a/src/pybamm/version.py +++ b/src/pybamm/version.py @@ -1 +1 @@ -__version__ = "24.5" +__version__ = "24.9.0" diff --git a/vcpkg.json b/vcpkg.json index a4ae73f302..6c50d65524 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "pybamm", - "version-string": "24.5", + "version-string": "24.9.0", "dependencies": [ "casadi", { From ac9380685ea445644734d3f993b8e62b6eb633c3 Mon Sep 17 00:00:00 2001 From: "Eric G. Kratz" Date: Tue, 3 Sep 2024 16:26:38 -0400 Subject: [PATCH 09/14] Remove outdated reminders (#4409) --- .github/release_reminder.md | 10 ---------- .github/workflows/release_reminder.yml | 22 ---------------------- 2 files changed, 32 deletions(-) delete mode 100644 .github/release_reminder.md delete mode 100644 .github/workflows/release_reminder.yml diff --git a/.github/release_reminder.md b/.github/release_reminder.md deleted file mode 100644 index 09c524fbec..0000000000 --- a/.github/release_reminder.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Create {{ date | date('YY.MM') }} (final or rc0) release -labels: "priority: high" ---- -Quarterly reminder to create a - - -1. pre-release if the month has just started. -2. non-pre-release if the month is about to end (**before the end of the month**). - -See [Release Workflow](https://github.com/pybamm-team/PyBaMM/blob/develop/.github/release_workflow.md) for more information. diff --git a/.github/workflows/release_reminder.yml b/.github/workflows/release_reminder.yml deleted file mode 100644 index f838c8d57a..0000000000 --- a/.github/workflows/release_reminder.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Create a release reminder - -on: - schedule: - # Run at 10 am UTC on days-of-month 1 and 28 in January, May, and September. - - cron: "0 10 1,28 1,5,9 *" - -permissions: - contents: read - issues: write - -jobs: - remind: - if: github.repository_owner == 'pybamm-team' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: JasonEtco/create-an-issue@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - filename: .github/release_reminder.md From 38984536f4ace6e380fde8d970e81e913092e079 Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 3 Sep 2024 14:47:44 -0700 Subject: [PATCH 10/14] Update CHANGELOG.md to include surface thermal model (#4412) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5a959748f..55c6369ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added additional user-configurable options to the (`IDAKLUSolver`) and adjusted the default values to improve performance. ([#4282](https://github.com/pybamm-team/PyBaMM/pull/4282)) - Added the diffusion element to be used in the Thevenin model. ([#4254](https://github.com/pybamm-team/PyBaMM/pull/4254)) +- Added lumped surface thermal model ([#4203](https://github.com/pybamm-team/PyBaMM/pull/4203)) ## Optimizations From 4241246019c30a6eb413aaff531e4bc87e7b19e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:28:00 +0530 Subject: [PATCH 11/14] Build(deps): bump the actions group across 1 directory with 3 updates (#4411) * Build(deps): bump the actions group across 1 directory with 3 updates Bumps the actions group with 3 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact), [github/codeql-action](https://github.com/github/codeql-action) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request). Updates `actions/upload-artifact` from 4.3.6 to 4.4.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4.3.6...v4.4.0) Updates `github/codeql-action` from 3.26.5 to 3.26.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/2c779ab0d087cd7fe7b826087247c2c81f27bfa6...4dd16135b69a43b6c8efb853346f8437d92d3c93) Updates `peter-evans/create-pull-request` from 6 to 7 - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions ... Signed-off-by: dependabot[bot] * Update .github/workflows/scorecard.yml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eric G. Kratz --- .github/workflows/periodic_benchmarks.yml | 2 +- .github/workflows/publish_pypi.yml | 8 ++++---- .github/workflows/run_benchmarks_over_history.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- .github/workflows/work_precision_sets.yml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/periodic_benchmarks.yml b/.github/workflows/periodic_benchmarks.yml index 641627c0ba..b99e2ab7b0 100644 --- a/.github/workflows/periodic_benchmarks.yml +++ b/.github/workflows/periodic_benchmarks.yml @@ -51,7 +51,7 @@ jobs: LD_LIBRARY_PATH: $HOME/.local/lib - name: Upload results as artifact - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: asv_periodic_results path: results diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml index 9ca277b653..5f68bd2b45 100644 --- a/.github/workflows/publish_pypi.yml +++ b/.github/workflows/publish_pypi.yml @@ -92,7 +92,7 @@ jobs: python -c "import pybamm; print(pybamm.IDAKLUSolver())" python -m pytest -m cibw {project}/tests/unit - name: Upload Windows wheels - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: wheels_windows path: ./wheelhouse/*.whl @@ -129,7 +129,7 @@ jobs: python -m pytest -m cibw {project}/tests/unit - name: Upload wheels for Linux - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: wheels_manylinux path: ./wheelhouse/*.whl @@ -261,7 +261,7 @@ jobs: python -m pytest -m cibw {project}/tests/unit - name: Upload wheels for macOS (amd64, arm64) - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: wheels_${{ matrix.os }} path: ./wheelhouse/*.whl @@ -281,7 +281,7 @@ jobs: run: pipx run build --sdist - name: Upload SDist - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: sdist path: ./dist/*.tar.gz diff --git a/.github/workflows/run_benchmarks_over_history.yml b/.github/workflows/run_benchmarks_over_history.yml index d01564b210..71687a8b02 100644 --- a/.github/workflows/run_benchmarks_over_history.yml +++ b/.github/workflows/run_benchmarks_over_history.yml @@ -46,7 +46,7 @@ jobs: ${{ github.event.inputs.commit_start }}..${{ github.event.inputs.commit_end }} - name: Upload results as artifact - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: asv_over_history_results path: results diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 8b33553737..784ccebc4f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: SARIF file path: results.sarif @@ -68,6 +68,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 + uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 with: sarif_file: results.sarif diff --git a/.github/workflows/work_precision_sets.yml b/.github/workflows/work_precision_sets.yml index fafc5b1738..c167bf5747 100644 --- a/.github/workflows/work_precision_sets.yml +++ b/.github/workflows/work_precision_sets.yml @@ -27,7 +27,7 @@ jobs: python benchmarks/work_precision_sets/time_vs_reltols.py python benchmarks/work_precision_sets/time_vs_abstols.py - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: delete-branch: true branch-suffix: short-commit-hash From b073fc7152694c8cfa35fc77a7741d1b2c7e80dd Mon Sep 17 00:00:00 2001 From: Marc Berliner <34451391+MarcBerliner@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:58:40 -0400 Subject: [PATCH 12/14] Remove unnecessary `dt` checks (#4416) * remove unnecessary time checks * comments * Update CHANGELOG.md --- CHANGELOG.md | 3 +++ src/pybamm/settings.py | 1 - src/pybamm/simulation.py | 13 ++++++------- src/pybamm/solvers/base_solver.py | 13 +++++-------- tests/unit/test_solvers/test_base_solver.py | 6 ++---- tests/unit/test_solvers/test_casadi_solver.py | 2 +- tests/unit/test_solvers/test_idaklu_solver.py | 2 +- tests/unit/test_solvers/test_scipy_solver.py | 2 +- 8 files changed, 19 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c6369ee7..5203229bd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # [Unreleased](https://github.com/pybamm-team/PyBaMM/) +## Optimizations +- Removed the `start_step_offset` setting and disabled minimum `dt` warnings for drive cycles with the (`IDAKLUSolver`). ([#4416](https://github.com/pybamm-team/PyBaMM/pull/4416)) + # [v24.9.0](https://github.com/pybamm-team/PyBaMM/tree/v24.9.0) - 2024-09-03 ## Features diff --git a/src/pybamm/settings.py b/src/pybamm/settings.py index d190eaf47e..6b7a628195 100644 --- a/src/pybamm/settings.py +++ b/src/pybamm/settings.py @@ -12,7 +12,6 @@ class Settings: _abs_smoothing = "exact" max_words_in_line = 4 max_y_value = 1e5 - step_start_offset = 1e-9 tolerances = { "D_e__c_e": 10, # dimensional "kappa_e__c_e": 10, # dimensional diff --git a/src/pybamm/simulation.py b/src/pybamm/simulation.py index 5b999d6c83..0aa85d1c20 100644 --- a/src/pybamm/simulation.py +++ b/src/pybamm/simulation.py @@ -8,7 +8,6 @@ import numpy as np import hashlib import warnings -import sys from functools import lru_cache from datetime import timedelta from pybamm.util import import_optional_dependency @@ -464,9 +463,9 @@ def solve( # the time data (to ensure the resolution of t_eval is fine enough). # We only raise a warning here as users may genuinely only want # the solution returned at some specified points. - elif ( - set(np.round(time_data, 12)).issubset(set(np.round(t_eval, 12))) - ) is False: + elif not isinstance(solver, pybamm.IDAKLUSolver) and not set( + np.round(time_data, 12) + ).issubset(set(np.round(t_eval, 12))): warnings.warn( """ t_eval does not contain all of the time points in the data @@ -478,7 +477,7 @@ def solve( ) dt_data_min = np.min(np.diff(time_data)) dt_eval_max = np.max(np.diff(t_eval)) - if dt_eval_max > dt_data_min + sys.float_info.epsilon: + if dt_eval_max > np.nextafter(dt_data_min, np.inf): warnings.warn( f""" The largest timestep in t_eval ({dt_eval_max}) is larger than @@ -581,7 +580,7 @@ def solve( + timedelta(seconds=float(current_solution.t[-1])) ) ).total_seconds() - if rest_time > pybamm.settings.step_start_offset: + if rest_time > 0: # logs["step operating conditions"] = "Initial rest for padding" # callbacks.on_step_start(logs) @@ -738,7 +737,7 @@ def solve( + timedelta(seconds=float(step_solution.t[-1])) ) ).total_seconds() - if rest_time > pybamm.settings.step_start_offset: + if rest_time > 0: logs["step number"] = (step_num, cycle_length) logs["step operating conditions"] = "Rest for padding" callbacks.on_step_start(logs) diff --git a/src/pybamm/solvers/base_solver.py b/src/pybamm/solvers/base_solver.py index efef7e9357..9c0d94f1a9 100644 --- a/src/pybamm/solvers/base_solver.py +++ b/src/pybamm/solvers/base_solver.py @@ -1142,12 +1142,9 @@ def step( # Make sure model isn't empty self._check_empty_model(model) - # Make sure dt is greater than the offset - step_start_offset = pybamm.settings.step_start_offset - if dt <= step_start_offset: - raise pybamm.SolverError( - f"Step time must be at least {pybamm.TimerTime(step_start_offset)}" - ) + # Make sure dt is greater than zero + if dt <= 0: + raise pybamm.SolverError("Step time must be >0") # Raise deprecation warning for npts and convert it to t_eval if npts is not None: @@ -1176,11 +1173,11 @@ def step( if t_start == 0: t_start_shifted = t_start else: - # offset t_start by t_start_offset (default 1 ns) + # find the next largest floating point value for t_start # to avoid repeated times in the solution # from having the same time at the end of the previous step and # the start of the next step - t_start_shifted = t_start + step_start_offset + t_start_shifted = np.nextafter(t_start, np.inf) t_eval[0] = t_start_shifted if t_interp.size > 0 and t_interp[0] == t_start: t_interp[0] = t_start_shifted diff --git a/tests/unit/test_solvers/test_base_solver.py b/tests/unit/test_solvers/test_base_solver.py index a4b43e1dd2..9a1e87acec 100644 --- a/tests/unit/test_solvers/test_base_solver.py +++ b/tests/unit/test_solvers/test_base_solver.py @@ -70,10 +70,8 @@ def test_nonmonotonic_teval(self): solver.solve(model, np.array([1, 2, 3, 2])) # Check stepping with step size too small - dt = 1e-9 - with self.assertRaisesRegex( - pybamm.SolverError, "Step time must be at least 1.000 ns" - ): + dt = -1e-9 + with self.assertRaisesRegex(pybamm.SolverError, "Step time must be >0"): solver.step(None, model, dt) # Checking if array t_eval lies within range diff --git a/tests/unit/test_solvers/test_casadi_solver.py b/tests/unit/test_solvers/test_casadi_solver.py index eaaeedf0d0..76f5a6c9dc 100644 --- a/tests/unit/test_solvers/test_casadi_solver.py +++ b/tests/unit/test_solvers/test_casadi_solver.py @@ -289,7 +289,7 @@ def test_model_step(self): # Step again (return 5 points) step_sol_2 = solver.step(step_sol, model, dt, npts=5) np.testing.assert_array_equal( - step_sol_2.t, np.array([0, 1, 1 + 1e-9, 1.25, 1.5, 1.75, 2]) + step_sol_2.t, np.array([0, 1, np.nextafter(1, np.inf), 1.25, 1.5, 1.75, 2]) ) np.testing.assert_array_almost_equal( step_sol_2.y.full()[0], np.exp(0.1 * step_sol_2.t) diff --git a/tests/unit/test_solvers/test_idaklu_solver.py b/tests/unit/test_solvers/test_idaklu_solver.py index 5d71b5f945..3f9dcf0508 100644 --- a/tests/unit/test_solvers/test_idaklu_solver.py +++ b/tests/unit/test_solvers/test_idaklu_solver.py @@ -1079,7 +1079,7 @@ def test_interpolate_time_step_start_offset(self): sim = pybamm.Simulation(model, experiment=experiment, solver=solver) sol = sim.solve() np.testing.assert_equal( - sol.sub_solutions[0].t[-1] + pybamm.settings.step_start_offset, + np.nextafter(sol.sub_solutions[0].t[-1], np.inf), sol.sub_solutions[1].t[0], ) diff --git a/tests/unit/test_solvers/test_scipy_solver.py b/tests/unit/test_solvers/test_scipy_solver.py index 446206e95c..dfaa6c7201 100644 --- a/tests/unit/test_solvers/test_scipy_solver.py +++ b/tests/unit/test_solvers/test_scipy_solver.py @@ -181,7 +181,7 @@ def test_model_step_python(self): # Step again (return 5 points) step_sol_2 = solver.step(step_sol, model, dt, npts=5) np.testing.assert_array_equal( - step_sol_2.t, np.array([0, 1, 1 + 1e-9, 1.25, 1.5, 1.75, 2]) + step_sol_2.t, np.array([0, 1, np.nextafter(1, np.inf), 1.25, 1.5, 1.75, 2]) ) np.testing.assert_array_almost_equal( step_sol_2.y[0], np.exp(0.1 * step_sol_2.t) From 613230c4255b789bd5f77dd24cbcd4f85cbf395d Mon Sep 17 00:00:00 2001 From: Medha Bhardwaj <143182673+medha-14@users.noreply.github.com> Date: Sat, 7 Sep 2024 00:25:54 +0530 Subject: [PATCH 13/14] Renames `set_events` to `add_events_from` (#4421) * changed set_events to add_events_from * all changes made * changelog added * changelog updated * corrected changelog --- CHANGELOG.md | 3 +++ src/pybamm/models/base_model.py | 2 +- src/pybamm/models/full_battery_models/base_battery_model.py | 2 +- src/pybamm/models/submodels/base_submodel.py | 2 +- .../submodels/electrolyte_diffusion/constant_concentration.py | 2 +- .../equivalent_circuit_elements/diffusion_element.py | 2 +- .../submodels/equivalent_circuit_elements/ocv_element.py | 2 +- .../submodels/equivalent_circuit_elements/voltage_model.py | 2 +- .../interface_utilisation/current_driven_utilisation.py | 2 +- .../models/submodels/particle_mechanics/crack_propagation.py | 2 +- src/pybamm/models/submodels/porosity/constant_porosity.py | 2 +- .../models/submodels/porosity/reaction_driven_porosity.py | 2 +- .../models/submodels/porosity/reaction_driven_porosity_ode.py | 2 +- tests/unit/test_models/test_base_model.py | 4 ++-- 14 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5203229bd3..7764a3b24a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## Optimizations - Removed the `start_step_offset` setting and disabled minimum `dt` warnings for drive cycles with the (`IDAKLUSolver`). ([#4416](https://github.com/pybamm-team/PyBaMM/pull/4416)) +## Breaking changes +- Renamed `set_events` function to `add_events_from` to better reflect its purpose. ([#4421](https://github.com/pybamm-team/PyBaMM/pull/4421)) + # [v24.9.0](https://github.com/pybamm-team/PyBaMM/tree/v24.9.0) - 2024-09-03 ## Features diff --git a/src/pybamm/models/base_model.py b/src/pybamm/models/base_model.py index 0d4638e178..989465e375 100644 --- a/src/pybamm/models/base_model.py +++ b/src/pybamm/models/base_model.py @@ -757,7 +757,7 @@ def build_model_equations(self): f"Setting initial conditions for {submodel_name} submodel ({self.name})" ) submodel.set_initial_conditions(self.variables) - submodel.set_events(self.variables) + submodel.add_events_from(self.variables) pybamm.logger.verbose(f"Updating {submodel_name} submodel ({self.name})") self.update(submodel) self.check_no_repeated_keys() diff --git a/src/pybamm/models/full_battery_models/base_battery_model.py b/src/pybamm/models/full_battery_models/base_battery_model.py index ccda594b14..e0ade7b429 100644 --- a/src/pybamm/models/full_battery_models/base_battery_model.py +++ b/src/pybamm/models/full_battery_models/base_battery_model.py @@ -1033,7 +1033,7 @@ def build_model_equations(self): f"Setting initial conditions for {submodel_name} submodel ({self.name})" ) submodel.set_initial_conditions(self.variables) - submodel.set_events(self.variables) + submodel.add_events_from(self.variables) pybamm.logger.verbose(f"Updating {submodel_name} submodel ({self.name})") self.update(submodel) self.check_no_repeated_keys() diff --git a/src/pybamm/models/submodels/base_submodel.py b/src/pybamm/models/submodels/base_submodel.py index e120691edd..d5e313e153 100644 --- a/src/pybamm/models/submodels/base_submodel.py +++ b/src/pybamm/models/submodels/base_submodel.py @@ -221,7 +221,7 @@ def set_initial_conditions(self, variables): """ pass - def set_events(self, variables): + def add_events_from(self, variables): """ A method to set events related to the state of submodel variable. Note: this method modifies the state of self.events. Unless overwritten by a submodel, the diff --git a/src/pybamm/models/submodels/electrolyte_diffusion/constant_concentration.py b/src/pybamm/models/submodels/electrolyte_diffusion/constant_concentration.py index eee441446f..006619e8bb 100644 --- a/src/pybamm/models/submodels/electrolyte_diffusion/constant_concentration.py +++ b/src/pybamm/models/submodels/electrolyte_diffusion/constant_concentration.py @@ -76,6 +76,6 @@ def set_boundary_conditions(self, variables): } } - def set_events(self, variables): + def add_events_from(self, variables): # No event since the concentration is constant pass diff --git a/src/pybamm/models/submodels/equivalent_circuit_elements/diffusion_element.py b/src/pybamm/models/submodels/equivalent_circuit_elements/diffusion_element.py index c7f1b4bcd5..bf9a183875 100644 --- a/src/pybamm/models/submodels/equivalent_circuit_elements/diffusion_element.py +++ b/src/pybamm/models/submodels/equivalent_circuit_elements/diffusion_element.py @@ -102,7 +102,7 @@ def set_initial_conditions(self, variables): z = variables["Distributed SoC"] self.initial_conditions = {z: self.param.initial_soc} - def set_events(self, variables): + def add_events_from(self, variables): z_surf = variables["Surface SoC"] self.events += [ pybamm.Event("Minimum surface SoC", z_surf), diff --git a/src/pybamm/models/submodels/equivalent_circuit_elements/ocv_element.py b/src/pybamm/models/submodels/equivalent_circuit_elements/ocv_element.py index 9d1adf3d57..901b63cf74 100644 --- a/src/pybamm/models/submodels/equivalent_circuit_elements/ocv_element.py +++ b/src/pybamm/models/submodels/equivalent_circuit_elements/ocv_element.py @@ -54,7 +54,7 @@ def set_initial_conditions(self, variables): soc = variables["SoC"] self.initial_conditions = {soc: self.param.initial_soc} - def set_events(self, variables): + def add_events_from(self, variables): soc = variables["SoC"] self.events += [ pybamm.Event("Minimum SoC", soc), diff --git a/src/pybamm/models/submodels/equivalent_circuit_elements/voltage_model.py b/src/pybamm/models/submodels/equivalent_circuit_elements/voltage_model.py index 380902fca5..89f8904f32 100644 --- a/src/pybamm/models/submodels/equivalent_circuit_elements/voltage_model.py +++ b/src/pybamm/models/submodels/equivalent_circuit_elements/voltage_model.py @@ -54,7 +54,7 @@ def x_not_zero(x): return variables - def set_events(self, variables): + def add_events_from(self, variables): voltage = variables["Voltage [V]"] # Add voltage events diff --git a/src/pybamm/models/submodels/interface/interface_utilisation/current_driven_utilisation.py b/src/pybamm/models/submodels/interface/interface_utilisation/current_driven_utilisation.py index bbd9af4fb6..e785204882 100644 --- a/src/pybamm/models/submodels/interface/interface_utilisation/current_driven_utilisation.py +++ b/src/pybamm/models/submodels/interface/interface_utilisation/current_driven_utilisation.py @@ -89,7 +89,7 @@ def set_initial_conditions(self, variables): self.initial_conditions = {u: u_init} - def set_events(self, variables): + def add_events_from(self, variables): domain, Domain = self.domain_Domain if self.reaction_loc == "full electrode": diff --git a/src/pybamm/models/submodels/particle_mechanics/crack_propagation.py b/src/pybamm/models/submodels/particle_mechanics/crack_propagation.py index 3bb9ecb7eb..b51f1d1ebd 100644 --- a/src/pybamm/models/submodels/particle_mechanics/crack_propagation.py +++ b/src/pybamm/models/submodels/particle_mechanics/crack_propagation.py @@ -102,7 +102,7 @@ def set_initial_conditions(self, variables): l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} electrode") self.initial_conditions = {l_cr: l_cr_0} - def set_events(self, variables): + def add_events_from(self, variables): domain, Domain = self.domain_Domain if self.x_average is True: diff --git a/src/pybamm/models/submodels/porosity/constant_porosity.py b/src/pybamm/models/submodels/porosity/constant_porosity.py index 0b9f3c0da4..6d6b93d76f 100644 --- a/src/pybamm/models/submodels/porosity/constant_porosity.py +++ b/src/pybamm/models/submodels/porosity/constant_porosity.py @@ -27,6 +27,6 @@ def get_fundamental_variables(self): return variables - def set_events(self, variables): + def add_events_from(self, variables): # No events since porosity is constant pass diff --git a/src/pybamm/models/submodels/porosity/reaction_driven_porosity.py b/src/pybamm/models/submodels/porosity/reaction_driven_porosity.py index fc69d0f1fd..989c90cd9c 100644 --- a/src/pybamm/models/submodels/porosity/reaction_driven_porosity.py +++ b/src/pybamm/models/submodels/porosity/reaction_driven_porosity.py @@ -64,7 +64,7 @@ def get_coupled_variables(self, variables): return variables - def set_events(self, variables): + def add_events_from(self, variables): eps_p = variables["Positive electrode porosity"] self.events.append( pybamm.Event( diff --git a/src/pybamm/models/submodels/porosity/reaction_driven_porosity_ode.py b/src/pybamm/models/submodels/porosity/reaction_driven_porosity_ode.py index 476845f054..f82a73ae68 100644 --- a/src/pybamm/models/submodels/porosity/reaction_driven_porosity_ode.py +++ b/src/pybamm/models/submodels/porosity/reaction_driven_porosity_ode.py @@ -94,7 +94,7 @@ def set_initial_conditions(self, variables): eps = variables["Porosity"] self.initial_conditions = {eps: self.param.epsilon_init} - def set_events(self, variables): + def add_events_from(self, variables): for domain in self.options.whole_cell_domains: if domain == "separator": continue diff --git a/tests/unit/test_models/test_base_model.py b/tests/unit/test_models/test_base_model.py index 4d5f71201a..d50cd66d2d 100644 --- a/tests/unit/test_models/test_base_model.py +++ b/tests/unit/test_models/test_base_model.py @@ -231,7 +231,7 @@ def set_initial_conditions(self, variables): u = variables["u"] self.initial_conditions = {u: c} - def set_events(self, variables): + def add_events_from(self, variables): e = pybamm.InputParameter("e") u = variables["u"] self.events = [pybamm.Event("u=e", u - e)] @@ -1178,7 +1178,7 @@ def set_initial_conditions(self, variables): v = variables["v"] self.initial_conditions = {u: 0, v: 0} - def set_events(self, variables): + def add_events_from(self, variables): u = variables["u"] self.events.append( pybamm.Event( From ee325c74178d9aebe1be5019af3a640c2589e5fd Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 20:01:53 +0100 Subject: [PATCH 14/14] docs: add medha-14 as a contributor for code (#4423) * docs: update all_contributors.md [skip ci] * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: Eric G. Kratz --- .all-contributorsrc | 9 +++++++++ README.md | 2 +- all_contributors.md | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4366246007..00b86f3474 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -960,6 +960,15 @@ "code", "test" ] + }, + { + "login": "medha-14", + "name": "Medha Bhardwaj", + "avatar_url": "https://avatars.githubusercontent.com/u/143182673?v=4", + "profile": "https://github.com/medha-14", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index a904e5a67c..611d8adcfe 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/pybamm-team/PyBaMM/badge)](https://scorecard.dev/viewer/?uri=github.com/pybamm-team/PyBaMM) -[![All Contributors](https://img.shields.io/badge/all_contributors-90-orange.svg)](#-contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-91-orange.svg)](#-contributors) diff --git a/all_contributors.md b/all_contributors.md index 9bb1e373d5..49a5f1d1ef 100644 --- a/all_contributors.md +++ b/all_contributors.md @@ -120,6 +120,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Ubham16
Ubham16

💻 Mehrdad Babazadeh
Mehrdad Babazadeh

💻 ⚠️ Pip Liggins
Pip Liggins

💻 ⚠️ + Medha Bhardwaj
Medha Bhardwaj

💻