From 21d87d32612d0fba7bf7ef0610aca095289a9530 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:42:45 +0100 Subject: [PATCH] Remove init_soc from problem --- .../multi_model_identification.ipynb | 6 ++-- .../multi_optimiser_identification.ipynb | 6 ++-- .../notebooks/optimiser_calibration.ipynb | 8 ++--- examples/notebooks/spm_electrode_design.ipynb | 3 +- examples/scripts/cuckoo.py | 8 ++--- examples/scripts/spm_AdamW.py | 8 ++--- examples/scripts/spm_NelderMead.py | 8 ++--- examples/scripts/spm_scipymin.py | 3 +- examples/scripts/spme_max_energy.py | 6 ++-- examples/standalone/problem.py | 5 +--- pybop/observers/observer.py | 7 +---- pybop/observers/unscented_kalman.py | 30 +++++++++++++------ pybop/problems/base_problem.py | 6 +--- pybop/problems/design_problem.py | 9 +----- pybop/problems/fitting_problem.py | 8 +---- tests/unit/test_cost.py | 10 +++---- tests/unit/test_likelihoods.py | 10 +++---- 17 files changed, 60 insertions(+), 81 deletions(-) diff --git a/examples/notebooks/multi_model_identification.ipynb b/examples/notebooks/multi_model_identification.ipynb index a66a78f2..933a6002 100644 --- a/examples/notebooks/multi_model_identification.ipynb +++ b/examples/notebooks/multi_model_identification.ipynb @@ -179,7 +179,8 @@ }, "outputs": [], "source": [ - "synth_model.build(dataset, init_soc=init_soc)\n", + "synth_model.set_init_soc(init_soc)\n", + "synth_model.build(dataset)\n", "synth_model.signal = [\"Voltage [V]\"]\n", "values = synth_model.simulate(t_eval=t_eval, inputs={})" ] @@ -3811,7 +3812,8 @@ "xs = []\n", "for model in models:\n", " print(f\"Running {model.name}\")\n", - " problem = pybop.FittingProblem(model, parameters, dataset, init_soc=init_soc)\n", + " model.set_init_soc(init_soc)\n", + " problem = pybop.FittingProblem(model, parameters, dataset)\n", " cost = pybop.SumSquaredError(problem)\n", " optim = pybop.XNES(\n", " cost, verbose=True, max_iterations=60, max_unchanged_iterations=15\n", diff --git a/examples/notebooks/multi_optimiser_identification.ipynb b/examples/notebooks/multi_optimiser_identification.ipynb index c4fc3b92..a1e13270 100644 --- a/examples/notebooks/multi_optimiser_identification.ipynb +++ b/examples/notebooks/multi_optimiser_identification.ipynb @@ -169,8 +169,8 @@ "outputs": [], "source": [ "t_eval = np.arange(0, 2000, 10)\n", - "init_soc = 1.0\n", - "values = synth_model.predict(t_eval=t_eval, init_soc=init_soc)" + "model.set_init_soc(1.0)\n", + "values = synth_model.predict(t_eval=t_eval)" ] }, { @@ -510,7 +510,7 @@ "source": [ "optims = []\n", "xs = []\n", - "problem = pybop.FittingProblem(model, parameters, dataset, init_soc=init_soc)\n", + "problem = pybop.FittingProblem(model, parameters, dataset)\n", "cost = pybop.SumSquaredError(problem)\n", "for optimiser in gradient_optimisers:\n", " print(f\"Running {optimiser.__name__}\")\n", diff --git a/examples/notebooks/optimiser_calibration.ipynb b/examples/notebooks/optimiser_calibration.ipynb index 3b09cd37..7ad7d2f0 100644 --- a/examples/notebooks/optimiser_calibration.ipynb +++ b/examples/notebooks/optimiser_calibration.ipynb @@ -133,7 +133,7 @@ " }\n", ")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)\n", - "init_soc = 0.4\n", + "model.set_init_soc(0.4)\n", "experiment = pybop.Experiment(\n", " [\n", " (\n", @@ -143,7 +143,7 @@ " ]\n", " * 2\n", ")\n", - "values = model.predict(init_soc=init_soc, experiment=experiment)" + "values = model.predict(experiment=experiment)" ] }, { @@ -298,7 +298,7 @@ } ], "source": [ - "problem = pybop.FittingProblem(model, parameters, dataset, init_soc=init_soc)\n", + "problem = pybop.FittingProblem(model, parameters, dataset)\n", "cost = pybop.SumSquaredError(problem)\n", "optim = pybop.GradientDescent(cost, sigma0=0.2, max_iterations=100)" ] @@ -457,7 +457,7 @@ "optims = []\n", "for sigma in sigmas:\n", " print(sigma)\n", - " problem = pybop.FittingProblem(model, parameters, dataset, init_soc=init_soc)\n", + " problem = pybop.FittingProblem(model, parameters, dataset)\n", " cost = pybop.SumSquaredError(problem)\n", " optim = pybop.GradientDescent(cost, sigma0=sigma, max_iterations=100)\n", " x, final_cost = optim.run()\n", diff --git a/examples/notebooks/spm_electrode_design.ipynb b/examples/notebooks/spm_electrode_design.ipynb index 90571c99..2df1415a 100644 --- a/examples/notebooks/spm_electrode_design.ipynb +++ b/examples/notebooks/spm_electrode_design.ipynb @@ -205,7 +205,8 @@ }, "outputs": [], "source": [ - "problem = pybop.DesignProblem(model, parameters, experiment, init_soc=1.0)\n", + "model.set_init_soc(1.0)\n", + "problem = pybop.DesignProblem(model, parameters, experiment)\n", "cost = pybop.GravimetricEnergyDensity(problem)" ] }, diff --git a/examples/scripts/cuckoo.py b/examples/scripts/cuckoo.py index fcdfadc1..3f3c14a6 100644 --- a/examples/scripts/cuckoo.py +++ b/examples/scripts/cuckoo.py @@ -23,7 +23,7 @@ true_value=0.67, ), ) -init_soc = 0.7 +model.set_init_soc(0.7) experiment = pybop.Experiment( [ ( @@ -32,9 +32,7 @@ ), ] ) -values = model.predict( - init_soc=init_soc, experiment=experiment, inputs=parameters.as_dict("true") -) +values = model.predict(experiment=experiment, inputs=parameters.as_dict("true")) sigma = 0.002 corrupt_values = values["Voltage [V]"].data + np.random.normal( @@ -51,7 +49,7 @@ ) # Generate problem, cost function, and optimisation class -problem = pybop.FittingProblem(model, parameters, dataset, init_soc=init_soc) +problem = pybop.FittingProblem(model, parameters, dataset) cost = pybop.GaussianLogLikelihood(problem, sigma0=sigma * 4) optim = pybop.Optimisation( cost, diff --git a/examples/scripts/spm_AdamW.py b/examples/scripts/spm_AdamW.py index 796849be..2a9264bf 100644 --- a/examples/scripts/spm_AdamW.py +++ b/examples/scripts/spm_AdamW.py @@ -19,7 +19,7 @@ ) # Generate data -init_soc = 0.5 +model.set_init_soc(0.5) sigma = 0.003 experiment = pybop.Experiment( [ @@ -30,7 +30,7 @@ ] * 2 ) -values = model.predict(init_soc=init_soc, experiment=experiment) +values = model.predict(experiment=experiment) def noise(sigma): @@ -50,9 +50,7 @@ def noise(sigma): signal = ["Voltage [V]", "Bulk open-circuit voltage [V]"] # Generate problem, cost function, and optimisation class -problem = pybop.FittingProblem( - model, parameters, dataset, signal=signal, init_soc=init_soc -) +problem = pybop.FittingProblem(model, parameters, dataset, signal=signal) cost = pybop.RootMeanSquaredError(problem) optim = pybop.AdamW( cost, diff --git a/examples/scripts/spm_NelderMead.py b/examples/scripts/spm_NelderMead.py index e07801e0..57e40bcc 100644 --- a/examples/scripts/spm_NelderMead.py +++ b/examples/scripts/spm_NelderMead.py @@ -19,7 +19,7 @@ ) # Generate data -init_soc = 0.5 +model.set_init_soc(0.5) sigma = 0.003 experiment = pybop.Experiment( [ @@ -30,7 +30,7 @@ ] * 2 ) -values = model.predict(init_soc=init_soc, experiment=experiment) +values = model.predict(experiment=experiment) def noise(sigma): @@ -50,9 +50,7 @@ def noise(sigma): signal = ["Voltage [V]", "Bulk open-circuit voltage [V]"] # Generate problem, cost function, and optimisation class -problem = pybop.FittingProblem( - model, parameters, dataset, signal=signal, init_soc=init_soc -) +problem = pybop.FittingProblem(model, parameters, dataset, signal=signal) cost = pybop.RootMeanSquaredError(problem) optim = pybop.NelderMead( cost, diff --git a/examples/scripts/spm_scipymin.py b/examples/scripts/spm_scipymin.py index b6cec3f0..24fe36fc 100644 --- a/examples/scripts/spm_scipymin.py +++ b/examples/scripts/spm_scipymin.py @@ -34,7 +34,8 @@ # Define the cost to optimise signal = ["Voltage [V]"] -problem = pybop.FittingProblem(model, parameters, dataset, signal=signal, init_soc=0.98) +model.set_init_soc(0.98) +problem = pybop.FittingProblem(model, parameters, dataset, signal=signal) cost = pybop.RootMeanSquaredError(problem) # Build the optimisation problem diff --git a/examples/scripts/spme_max_energy.py b/examples/scripts/spme_max_energy.py index f5b7c827..0c4d81f6 100644 --- a/examples/scripts/spme_max_energy.py +++ b/examples/scripts/spme_max_energy.py @@ -37,13 +37,11 @@ experiment = pybop.Experiment( ["Discharge at 1C until 2.5 V (5 seconds period)"], ) -init_soc = 1 # start from full charge +model.set_init_soc(1.0) # start from full charge signal = ["Voltage [V]", "Current [A]"] # Generate problem -problem = pybop.DesignProblem( - model, parameters, experiment, signal=signal, init_soc=init_soc -) +problem = pybop.DesignProblem(model, parameters, experiment, signal=signal) # Generate cost function and optimisation class: cost = pybop.GravimetricEnergyDensity(problem) diff --git a/examples/standalone/problem.py b/examples/standalone/problem.py index 18bf1f7d..0c1220cb 100644 --- a/examples/standalone/problem.py +++ b/examples/standalone/problem.py @@ -16,11 +16,8 @@ def __init__( check_model=True, signal=None, additional_variables=None, - init_soc=None, ): - super().__init__( - parameters, model, check_model, signal, additional_variables, init_soc - ) + super().__init__(parameters, model, check_model, signal, additional_variables) self._dataset = dataset.data # Check that the dataset contains time and current diff --git a/pybop/observers/observer.py b/pybop/observers/observer.py index 66b92250..89109ef8 100644 --- a/pybop/observers/observer.py +++ b/pybop/observers/observer.py @@ -26,8 +26,6 @@ class Observer(BaseProblem): The signal to observe. additional_variables : list[str], optional Additional variables to observe and store in the solution (default: []). - init_soc : float, optional - Initial state of charge (default: None). """ # define a subtype for covariance matrices for use by derived classes @@ -40,11 +38,8 @@ def __init__( check_model: bool = True, signal: Optional[list[str]] = None, additional_variables: Optional[list[str]] = None, - init_soc: Optional[float] = None, ) -> None: - super().__init__( - parameters, model, check_model, signal, additional_variables, init_soc - ) + super().__init__(parameters, model, check_model, signal, additional_variables) if model._built_model is None: raise ValueError("Only built models can be used in Observers") diff --git a/pybop/observers/unscented_kalman.py b/pybop/observers/unscented_kalman.py index df81b084..d21bf7d3 100644 --- a/pybop/observers/unscented_kalman.py +++ b/pybop/observers/unscented_kalman.py @@ -34,8 +34,6 @@ class UnscentedKalmanFilterObserver(Observer): Flag to indicate if the model should be checked (default: True). signal: str The signal to observe. - init_soc : float, optional - Initial state of charge (default: None). """ Covariance = np.ndarray @@ -51,16 +49,30 @@ def __init__( check_model: bool = True, signal: Optional[list[str]] = None, additional_variables: Optional[list[str]] = None, - init_soc: Optional[float] = None, ) -> None: - super().__init__( - parameters, model, check_model, signal, additional_variables, init_soc - ) if dataset is not None: - self._dataset = dataset.data + # Check that the dataset contains necessary variables + dataset.check([*signal, "Current function [A]"]) + dataset = dataset.data + + if model is not None: + # Clear any existing built model and its properties + if model._built_model is not None: + model._model_with_set_params = None + model._built_model = None + model._mesh = None + model._disc = None + + # Build the model from scratch + model.build( + dataset=dataset, + parameters=parameters, + check_model=check_model, + ) - # Check that the dataset contains time and current - dataset.check([*self.signal, "Current function [A]"]) + super().__init__(parameters, model, check_model, signal, additional_variables) + if dataset is not None: + self._dataset = dataset self._time_data = self._dataset["Time [s]"] self.n_time_data = len(self._time_data) diff --git a/pybop/problems/base_problem.py b/pybop/problems/base_problem.py index 7ed36e87..e0eff1cc 100644 --- a/pybop/problems/base_problem.py +++ b/pybop/problems/base_problem.py @@ -20,8 +20,6 @@ class BaseProblem: The signal to observe. additional_variables : list[str], optional Additional variables to observe and store in the solution (default: []). - init_soc : float, optional - Initial state of charge (default: None). Attributes ---------- @@ -36,7 +34,6 @@ def __init__( check_model: bool = True, signal: Optional[list[str]] = None, additional_variables: Optional[list[str]] = None, - init_soc: Optional[float] = None, ): if signal is None: signal = ["Voltage [V]"] @@ -71,7 +68,6 @@ def __init__( if additional_variables is not None: self.variables.extend(additional_variables) self.variables = list(set(self.variables)) - self.init_soc = init_soc self.n_outputs = len(self.signal) self._dataset = None self._time_data = None @@ -180,7 +176,7 @@ def set_target(self, dataset: Dataset): Parameters ---------- - target : np.ndarray + target : Dataset The target dataset array. """ if self.signal is None: diff --git a/pybop/problems/design_problem.py b/pybop/problems/design_problem.py index 5fd86636..39516e79 100644 --- a/pybop/problems/design_problem.py +++ b/pybop/problems/design_problem.py @@ -26,8 +26,6 @@ class DesignProblem(BaseProblem): The signal to fit (default: "Voltage [V]"). additional_variables : list[str], optional Additional variables to observe and store in the solution (default additions are: ["Time [s]", "Current [A]"]). - init_soc : float, optional - Initial state of charge (default: None). """ def __init__( @@ -38,11 +36,8 @@ def __init__( check_model: bool = True, signal: Optional[list[str]] = None, additional_variables: Optional[list[str]] = None, - init_soc: Optional[float] = None, ): - super().__init__( - parameters, model, check_model, signal, additional_variables, init_soc - ) + super().__init__(parameters, model, check_model, signal, additional_variables) # Add time and current as additional variables and remove duplicates self.variables.extend(["Time [s]", "Current [A]"]) @@ -60,7 +55,6 @@ def __init__( experiment=self.experiment, parameters=self.parameters, check_model=self.check_model, - init_soc=self.init_soc, ) # Add an example dataset for plotting comparison @@ -86,7 +80,6 @@ def _evaluate(self, inputs: Inputs): sol = self._model.predict( inputs=inputs, experiment=self.experiment, - init_soc=self.init_soc, ) if sol == [np.inf]: diff --git a/pybop/problems/fitting_problem.py b/pybop/problems/fitting_problem.py index bce03a77..e92a7e2b 100644 --- a/pybop/problems/fitting_problem.py +++ b/pybop/problems/fitting_problem.py @@ -27,8 +27,6 @@ class FittingProblem(BaseProblem): The variable used for fitting (default: "Voltage [V]"). additional_variables : list[str], optional Additional variables to observe and store in the solution (default: []). - init_soc : float, optional - Initial state of charge (default: None). Additional Attributes --------------------- @@ -50,11 +48,8 @@ def __init__( check_model: bool = True, signal: Optional[list[str]] = None, additional_variables: Optional[list[str]] = None, - init_soc: Optional[float] = None, ): - super().__init__( - parameters, model, check_model, signal, additional_variables, init_soc - ) + super().__init__(parameters, model, check_model, signal, additional_variables) self._dataset = dataset.data self.parameters.initial_value() @@ -79,7 +74,6 @@ def __init__( dataset=self._dataset, parameters=self.parameters, check_model=self.check_model, - init_soc=self.init_soc, ) def _evaluate(self, inputs: Inputs): diff --git a/tests/unit/test_cost.py b/tests/unit/test_cost.py index c08d010b..28bfc116 100644 --- a/tests/unit/test_cost.py +++ b/tests/unit/test_cost.py @@ -64,9 +64,8 @@ def signal(self): def problem(self, model, parameters, dataset, signal, request): cut_off = request.param model._parameter_set.update({"Lower voltage cut-off [V]": cut_off}) - problem = pybop.FittingProblem( - model, parameters, dataset, signal=signal, init_soc=1.0 - ) + model.set_init_soc(1.0) + problem = pybop.FittingProblem(model, parameters, dataset, signal=signal) return problem @pytest.fixture( @@ -229,9 +228,8 @@ def test_design_costs( signal, ): # Construct Problem - problem = pybop.DesignProblem( - model, parameters, experiment, signal=signal, init_soc=0.5 - ) + model.set_init_soc(0.5) + problem = pybop.DesignProblem(model, parameters, experiment, signal=signal) # Construct Cost cost = cost_class(problem) diff --git a/tests/unit/test_likelihoods.py b/tests/unit/test_likelihoods.py index aa68cc0e..f993ddcb 100644 --- a/tests/unit/test_likelihoods.py +++ b/tests/unit/test_likelihoods.py @@ -54,16 +54,14 @@ def dataset(self, model, experiment, ground_truth): @pytest.fixture def one_signal_problem(self, model, parameters, dataset): signal = ["Voltage [V]"] - return pybop.FittingProblem( - model, parameters, dataset, signal=signal, init_soc=1.0 - ) + model.set_init_soc(1.0) + return pybop.FittingProblem(model, parameters, dataset, signal=signal) @pytest.fixture def two_signal_problem(self, model, parameters, dataset): signal = ["Time [s]", "Voltage [V]"] - return pybop.FittingProblem( - model, parameters, dataset, signal=signal, init_soc=1.0 - ) + model.set_init_soc(1.0) + return pybop.FittingProblem(model, parameters, dataset, signal=signal) @pytest.mark.parametrize( "problem_name, n_outputs",