From d978be8b6028e6e4551876f9d7ecbeaca27dfe34 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:58:43 +0000 Subject: [PATCH 01/14] Align ParameterSet with ParameterValues --- pybop/models/base_model.py | 13 ++-- pybop/parameters/parameter_set.py | 102 ++++++++++++++++++++++++++---- tests/unit/test_models.py | 6 +- tests/unit/test_parameter_sets.py | 53 ++++++++-------- 4 files changed, 121 insertions(+), 53 deletions(-) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 1344ef92d..0ba1f1335 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -81,7 +81,7 @@ def __init__( ---------- name : str, optional The name given to the model instance. - parameter_set : Union[pybop.ParameterSet, pybamm.ParameterValues], optional + parameter_set : Union[pybop.ParameterSet, pybamm.ParameterValues, dict], optional A dict-like object containing the parameter values. check_params : Callable, optional A compatibility check for the model parameters. Function, with @@ -107,14 +107,9 @@ def __init__( """ self.name = name self.eis = eis - if parameter_set is None: - self._parameter_set = None - elif isinstance(parameter_set, dict): - self._parameter_set = pybamm.ParameterValues(parameter_set).copy() - elif isinstance(parameter_set, pybamm.ParameterValues): - self._parameter_set = parameter_set.copy() - else: # a pybop parameter set - self._parameter_set = pybamm.ParameterValues(parameter_set.params).copy() + if not isinstance(parameter_set, ParameterSet): + parameter_set = ParameterSet(parameter_set) + self._parameter_set = parameter_set() self.param_checker = check_params self.pybamm_model = None diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 97b166ce1..12616ac17 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -1,7 +1,7 @@ import json import types from numbers import Number -from typing import Union +from typing import Optional, Union import numpy as np from pybamm import ( @@ -25,19 +25,67 @@ class ParameterSet: Parameters ---------- + parameter_set : Union[str, dict, ParameterValues], optional + A dictionary of parameters to initialise the ParameterSet with. If not provided, an empty dictionary is used. json_path : str, optional - Path to a JSON file containing parameter data. If provided, parameters will be imported from this file during initialization. - params_dict : dict, optional - A dictionary of parameters to initialize the ParameterSet with. If not provided, an empty dictionary is used. + Path to a JSON file containing parameter data. If provided, parameters will be imported from this file during + initialisation. """ - def __init__(self, json_path=None, params_dict=None): + def __init__( + self, + parameter_set: Union[str, dict, ParameterValues] = None, + json_path: Optional[str] = None, + formation_concentrations: bool = False, + ): + if parameter_set is not None and json_path is not None: + raise ValueError( + "ParameterSet needs either a parameter_set or json_path as an input, not both." + ) self.json_path = json_path - self.params = params_dict or {} + self.params = None self.chemistry = None + self.formation_concentrations = formation_concentrations - def __call__(self): - return self.params + if isinstance(parameter_set, str): + # Use class method + self.params = ParameterSet.pybamm(parameter_set) + elif isinstance(parameter_set, dict): + # Keep as dictionary to allow "default" as value + self.params = parameter_set + elif isinstance(parameter_set, ParameterValues): + self.params = parameter_set + + if self.params is not None: + self.chemistry = self.params.get("chemistry", None) + + def __call__(self, formation_concentrations: Optional[bool] = False): + """ + Obtain a copy of the parameter set as a PyBaMM ParameterValues object. + + Parameters + ---------- + set_formation_concentrations : bool, optional + If True, re-calculates the initial concentrations of lithium in the active material (default: False). + + Returns + ------- + pybamm.ParameterValues + A PyBaMM parameter set corresponding to the parameter set stored in self.params. + """ + self.formation_concentrations = formation_concentrations + + if self.params is None: + return None + elif isinstance(self.params, dict): + parameter_set = ParameterValues(self.params).copy() + else: + parameter_set = self.params.copy() + + if self.formation_concentrations: + set_formation_concentrations(parameter_set) + + return parameter_set def __setitem__(self, key, value): self.params[key] = value @@ -78,13 +126,35 @@ def keys(self) -> list: """ return list(self.params.keys()) - def update(self, params_dict=None): + def update(self, params_dict: dict = None, check_already_exists: bool = True): """ Update the parameter dictionary. + + Parameters + ---------- + params_dict : dict + Dictionary of parameter values to update parameter dictionary with. + check_already_exists : bool, optional + Whether to check that a parameter in `params_dict` already exists when trying + to update it. This is to avoid cases where an intended change in the parameters + is ignored due a typo in the parameter name (default: True). """ - self.params.update(params_dict) + if isinstance(self.params, ParameterValues): + self.params.update(params_dict, check_already_exists=check_already_exists) + elif check_already_exists is True: + for key, value in params_dict.items(): + try: + self.params.update({key: value}) + except KeyError as err: + raise KeyError( + f"Cannot update parameter '{key}' as it does not have a default value. " + f"({err.args[0]}). If you are sure you want to update this parameter, " + "use param.update({name: value}, check_already_exists=False)" + ) from err + else: + self.params.update(params_dict) - def import_parameters(self, json_path=None): + def import_parameters(self, json_path: Optional[str] = None): """ Imports parameters from a JSON file specified by the `json_path` attribute. @@ -107,6 +177,8 @@ def import_parameters(self, json_path=None): FileNotFoundError If the specified JSON file cannot be found. """ + if json_path is not None: + self.json_path = json_path # Read JSON file if not self.params and self.json_path: @@ -116,8 +188,8 @@ def import_parameters(self, json_path=None): raise ValueError( "Parameter set already constructed, or path to json file not provided." ) - if self.params["chemistry"] is not None: - self.chemistry = self.params["chemistry"] + self.chemistry = self.params.get("chemistry", None) + return self.params def import_from_bpx(self, json_path=None): @@ -144,6 +216,8 @@ def import_from_bpx(self, json_path=None): FileNotFoundError If the specified JSON file cannot be found. """ + if json_path is not None: + self.json_path = json_path # Read JSON file if not self.params and self.json_path: @@ -152,6 +226,8 @@ def import_from_bpx(self, json_path=None): raise ValueError( "Parameter set already constructed, or path to bpx file not provided." ) + self.chemistry = self.params.get("chemistry", None) + return self.params def export_parameters(self, output_json_path, fit_params=None): diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index c36118027..b30ffe3e8 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -51,9 +51,7 @@ def test_model_classes(self, model_class, expected_name, options): if model_class is pybop.lithium_ion.MSMR: # Reset the options to cope with a bug in PyBaMM v23.9 msmr.py:23 which is fixed in v24.1 options = {"number of MSMR reactions": ("6", "4")} - parameter_set = pybop.ParameterSet( - params_dict={"Nominal cell capacity [A.h]": 5} - ) + parameter_set = pybop.ParameterSet({"Nominal cell capacity [A.h]": 5}) model = model_class(options=options, build=True, parameter_set=parameter_set) @pytest.fixture( @@ -219,7 +217,7 @@ def test_parameter_set_definition(self): model = pybop.BaseModel(parameter_set=parameter_set) assert model.parameter_set == parameter_set - pybop_parameter_set = pybop.ParameterSet(params_dict=param_dict) + pybop_parameter_set = pybop.ParameterSet(param_dict) model = pybop.BaseModel(parameter_set=pybop_parameter_set) assert model.parameter_set == parameter_set diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 35dbd9c1c..6b0289c61 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -48,35 +48,34 @@ def test_ecm_parameter_sets(self): ): json_params.import_parameters() - params = pybop.ParameterSet( - params_dict={ - "chemistry": "ecm", - "Initial SoC": 0.5, - "Initial temperature [K]": 25 + 273.15, - "Cell capacity [A.h]": 5, - "Nominal cell capacity [A.h]": 5, - "Ambient temperature [K]": 25 + 273.15, - "Current function [A]": 5, - "Upper voltage cut-off [V]": 4.2, - "Lower voltage cut-off [V]": 3.0, - "Cell thermal mass [J/K]": 1000, - "Cell-jig heat transfer coefficient [W/K]": 10, - "Jig thermal mass [J/K]": 500, - "Jig-air heat transfer coefficient [W/K]": 10, - "Open-circuit voltage [V]": "default", - "R0 [Ohm]": 0.001, - "Element-1 initial overpotential [V]": 0, - "Element-2 initial overpotential [V]": 0, - "R1 [Ohm]": 0.0002, - "R2 [Ohm]": 0.0003, - "C1 [F]": 10000, - "C2 [F]": 5000, - "Entropic change [V/K]": 0.0004, - } - ) + params_dict = { + "chemistry": "ecm", + "Initial SoC": 0.5, + "Initial temperature [K]": 25 + 273.15, + "Cell capacity [A.h]": 5, + "Nominal cell capacity [A.h]": 5, + "Ambient temperature [K]": 25 + 273.15, + "Current function [A]": 5, + "Upper voltage cut-off [V]": 4.2, + "Lower voltage cut-off [V]": 3.0, + "Cell thermal mass [J/K]": 1000, + "Cell-jig heat transfer coefficient [W/K]": 10, + "Jig thermal mass [J/K]": 500, + "Jig-air heat transfer coefficient [W/K]": 10, + "Open-circuit voltage [V]": "default", + "R0 [Ohm]": 0.001, + "Element-1 initial overpotential [V]": 0, + "Element-2 initial overpotential [V]": 0, + "R1 [Ohm]": 0.0002, + "R2 [Ohm]": 0.0003, + "C1 [F]": 10000, + "C2 [F]": 5000, + "Entropic change [V/K]": 0.0004, + } + params = pybop.ParameterSet(params_dict) assert json_params.params == params.params - assert params() == params.params + assert params_dict == params.params # Test exporting a json file parameters = pybop.Parameters( From 75d58dd410a92d17d6ec00c1d82600d905cde351 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:12:59 +0000 Subject: [PATCH 02/14] Update single_pulse_circuit_model.ipynb --- .../battery_parameterisation/single_pulse_circuit_model.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notebooks/battery_parameterisation/single_pulse_circuit_model.ipynb b/examples/notebooks/battery_parameterisation/single_pulse_circuit_model.ipynb index b976533ef..d505c2d1a 100644 --- a/examples/notebooks/battery_parameterisation/single_pulse_circuit_model.ipynb +++ b/examples/notebooks/battery_parameterisation/single_pulse_circuit_model.ipynb @@ -286,7 +286,7 @@ "outputs": [], "source": [ "params = pybop.ParameterSet(\n", - " params_dict={\n", + " {\n", " \"chemistry\": \"ecm\",\n", " \"Initial SoC\": 0.9 - 0.01,\n", " \"Initial temperature [K]\": 25 + 273.15,\n", From cc09091186bb8760f1ffd6c9c8879e61f4bad8f9 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:40:23 +0000 Subject: [PATCH 03/14] Increase coverage --- pybop/models/lithium_ion/echem.py | 6 +- pybop/parameters/parameter_set.py | 38 ++++++----- tests/unit/test_parameter_sets.py | 105 +++++++++++++++++++++--------- 3 files changed, 100 insertions(+), 49 deletions(-) diff --git a/pybop/models/lithium_ion/echem.py b/pybop/models/lithium_ion/echem.py index 121d921ef..7572902db 100644 --- a/pybop/models/lithium_ion/echem.py +++ b/pybop/models/lithium_ion/echem.py @@ -302,7 +302,8 @@ def __init__( "Negative electrode thickness [m]": default_parameter_set[ "Negative electrode thickness [m]" ], - } + }, + check_already_exists=False, ) # Update dimensions to equal their dimensionless values if "Positive electrode relative thickness" in parameter_set.keys(): @@ -322,7 +323,8 @@ def __init__( ), "Positive particle radius [m]": 1, "Negative particle radius [m]": 1, - } + }, + check_already_exists=False, ) model_kwargs["parameter_set"] = parameter_set diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 12616ac17..654167a65 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -141,17 +141,15 @@ def update(self, params_dict: dict = None, check_already_exists: bool = True): """ if isinstance(self.params, ParameterValues): self.params.update(params_dict, check_already_exists=check_already_exists) - elif check_already_exists is True: - for key, value in params_dict.items(): - try: - self.params.update({key: value}) - except KeyError as err: - raise KeyError( - f"Cannot update parameter '{key}' as it does not have a default value. " - f"({err.args[0]}). If you are sure you want to update this parameter, " - "use param.update({name: value}, check_already_exists=False)" - ) from err else: + if check_already_exists is True: + for key in params_dict.keys(): + if key not in self.params.keys(): + raise KeyError( + f"Cannot update parameter '{key}' as it does not have a default " + "value. If you are sure you want to update this parameter, use " + "param.update({name: value}, check_already_exists=False)" + ) self.params.update(params_dict) def import_parameters(self, json_path: Optional[str] = None): @@ -177,17 +175,19 @@ def import_parameters(self, json_path: Optional[str] = None): FileNotFoundError If the specified JSON file cannot be found. """ + if self.params: + raise ValueError("Parameter set already constructed.") + if json_path is not None: self.json_path = json_path # Read JSON file - if not self.params and self.json_path: + if self.json_path: with open(self.json_path) as file: self.params = json.load(file) else: - raise ValueError( - "Parameter set already constructed, or path to json file not provided." - ) + raise ValueError("No path was provided.") + self.chemistry = self.params.get("chemistry", None) return self.params @@ -216,16 +216,18 @@ def import_from_bpx(self, json_path=None): FileNotFoundError If the specified JSON file cannot be found. """ + if self.params: + raise ValueError("Parameter set already constructed.") + if json_path is not None: self.json_path = json_path # Read JSON file - if not self.params and self.json_path: + if self.json_path: self.params = ParameterValues.create_from_bpx(self.json_path) else: - raise ValueError( - "Parameter set already constructed, or path to bpx file not provided." - ) + raise ValueError("No path was provided.") + self.chemistry = self.params.get("chemistry", None) return self.params diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 6b0289c61..93bf7f6ca 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -10,12 +10,44 @@ class TestParameterSets: A class to test parameter sets. """ + @pytest.fixture + def params_dict(self): + return { + "chemistry": "ecm", + "Initial SoC": 0.5, + "Initial temperature [K]": 25 + 273.15, + "Cell capacity [A.h]": 5, + "Nominal cell capacity [A.h]": 5, + "Ambient temperature [K]": 25 + 273.15, + "Current function [A]": 5, + "Upper voltage cut-off [V]": 4.2, + "Lower voltage cut-off [V]": 3.0, + "Cell thermal mass [J/K]": 1000, + "Cell-jig heat transfer coefficient [W/K]": 10, + "Jig thermal mass [J/K]": 500, + "Jig-air heat transfer coefficient [W/K]": 10, + "Open-circuit voltage [V]": "default", + "R0 [Ohm]": 0.001, + "Element-1 initial overpotential [V]": 0, + "Element-2 initial overpotential [V]": 0, + "R1 [Ohm]": 0.0002, + "R2 [Ohm]": 0.0003, + "C1 [F]": 10000, + "C2 [F]": 5000, + "Entropic change [V/K]": 0.0004, + } + @pytest.mark.unit def test_parameter_set(self): # Tests parameter set creation and validation with pytest.raises(ValueError): pybop.ParameterSet.pybamm("sChen2010s") + parameter_test = pybop.ParameterSet("Chen2020") + np.testing.assert_allclose( + parameter_test["Negative electrode active material volume fraction"], 0.75 + ) + parameter_test = pybop.ParameterSet.pybamm("Chen2020") np.testing.assert_allclose( parameter_test["Negative electrode active material volume fraction"], 0.75 @@ -28,12 +60,12 @@ def test_parameter_set(self): ) @pytest.mark.unit - def test_ecm_parameter_sets(self): + def test_ecm_parameter_sets(self, params_dict): # Test importing a json file json_params = pybop.ParameterSet() with pytest.raises( ValueError, - match="Parameter set already constructed, or path to json file not provided.", + match="No path was provided.", ): json_params.import_parameters() @@ -44,39 +76,28 @@ def test_ecm_parameter_sets(self): with pytest.raises( ValueError, - match="Parameter set already constructed, or path to json file not provided.", + match="Parameter set already constructed.", ): json_params.import_parameters() - params_dict = { - "chemistry": "ecm", - "Initial SoC": 0.5, - "Initial temperature [K]": 25 + 273.15, - "Cell capacity [A.h]": 5, - "Nominal cell capacity [A.h]": 5, - "Ambient temperature [K]": 25 + 273.15, - "Current function [A]": 5, - "Upper voltage cut-off [V]": 4.2, - "Lower voltage cut-off [V]": 3.0, - "Cell thermal mass [J/K]": 1000, - "Cell-jig heat transfer coefficient [W/K]": 10, - "Jig thermal mass [J/K]": 500, - "Jig-air heat transfer coefficient [W/K]": 10, - "Open-circuit voltage [V]": "default", - "R0 [Ohm]": 0.001, - "Element-1 initial overpotential [V]": 0, - "Element-2 initial overpotential [V]": 0, - "R1 [Ohm]": 0.0002, - "R2 [Ohm]": 0.0003, - "C1 [F]": 10000, - "C2 [F]": 5000, - "Entropic change [V/K]": 0.0004, - } + json_params = pybop.ParameterSet() + json_params.import_parameters( + json_path="examples/parameters/initial_ecm_parameters.json" + ) + params = pybop.ParameterSet(params_dict) assert json_params.params == params.params assert params_dict == params.params + with pytest.raises( + ValueError, + match="ParameterSet needs either a parameter_set or json_path as an input, not both.", + ): + pybop.ParameterSet( + params_dict, json_path="examples/parameters/initial_ecm_parameters.json" + ) + # Test exporting a json file parameters = pybop.Parameters( pybop.Parameter( @@ -109,7 +130,7 @@ def test_bpx_parameter_sets(self): bpx_parameters = pybop.ParameterSet() with pytest.raises( ValueError, - match="Parameter set already constructed, or path to bpx file not provided.", + match="No path was provided.", ): bpx_parameters.import_from_bpx() @@ -120,7 +141,7 @@ def test_bpx_parameter_sets(self): with pytest.raises( ValueError, - match="Parameter set already constructed, or path to bpx file not provided.", + match="Parameter set already constructed.", ): bpx_parameters.import_from_bpx() @@ -137,6 +158,16 @@ def test_set_formation_concentrations(self): parameter_set["Initial concentration in positive electrode [mol.m-3]"] > 0 ) + parameter_set = pybop.ParameterSet(parameter_set) + parameter_set = parameter_set(formation_concentrations=True) + + assert ( + parameter_set["Initial concentration in negative electrode [mol.m-3]"] == 0 + ) + assert ( + parameter_set["Initial concentration in positive electrode [mol.m-3]"] > 0 + ) + @pytest.mark.unit def test_evaluate_symbol(self): parameter_set = pybop.ParameterSet.pybamm("Chen2020") @@ -152,3 +183,19 @@ def test_evaluate_symbol(self): value = pybop.ParameterSet.evaluate_symbol(param, parameter_set) assert isinstance(value, float) np.testing.assert_allclose(value, 1.0 + porosity) + + @pytest.mark.unit + def test_check_already_exists(self, params_dict): + parameter_set = pybop.ParameterSet(params_dict) + + parameter_set.update({"Nominal cell capacity [A.h]": 3}) + np.testing.assert_allclose(parameter_set["Nominal cell capacity [A.h]"], 3) + + with pytest.raises( + KeyError, + match="If you are sure you want to update this parameter,", + ): + parameter_set.update({"Unused parameter name": 3}) + + parameter_set.update({"Unused parameter name": 3}, check_already_exists=False) + np.testing.assert_allclose(parameter_set["Unused parameter name"], 3) From 53a708abaff286f518ee100793b92f71a4c07dde Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:05:25 +0000 Subject: [PATCH 04/14] Add two more tests --- tests/unit/test_parameter_sets.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 93bf7f6ca..cb400a43f 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -145,6 +145,11 @@ def test_bpx_parameter_sets(self): ): bpx_parameters.import_from_bpx() + bpx_parameters = pybop.ParameterSet() + bpx_parameters.import_parameters( + json_path="examples/parameters/example_BPX.json" + ) + @pytest.mark.unit def test_set_formation_concentrations(self): parameter_set = pybop.ParameterSet.pybamm( @@ -199,3 +204,7 @@ def test_check_already_exists(self, params_dict): parameter_set.update({"Unused parameter name": 3}, check_already_exists=False) np.testing.assert_allclose(parameter_set["Unused parameter name"], 3) + + parameter_set = pybop.ParameterSet("Chen2020") + parameter_set.update({"Nominal cell capacity [A.h]": 3}) + np.testing.assert_allclose(parameter_set["Nominal cell capacity [A.h]"], 3) From 341d0f8b0538bbd992c0d536bb31bcca2214e17a Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:45:33 +0000 Subject: [PATCH 05/14] Fix test --- tests/unit/test_parameter_sets.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index cb400a43f..c853fae1b 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -146,9 +146,7 @@ def test_bpx_parameter_sets(self): bpx_parameters.import_from_bpx() bpx_parameters = pybop.ParameterSet() - bpx_parameters.import_parameters( - json_path="examples/parameters/example_BPX.json" - ) + bpx_parameters.import_from_bpx(json_path="examples/parameters/example_BPX.json") @pytest.mark.unit def test_set_formation_concentrations(self): From 7059714a9937de0ec26d78faf2e4c3935a0e9b66 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:52:30 +0000 Subject: [PATCH 06/14] Apply suggestions from code review Co-authored-by: Brady Planden <55357039+BradyPlanden@users.noreply.github.com> --- pybop/parameters/parameter_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 654167a65..1c653c0b4 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -49,7 +49,7 @@ def __init__( if isinstance(parameter_set, str): # Use class method - self.params = ParameterSet.pybamm(parameter_set) + self.params = self.pybamm(parameter_set) elif isinstance(parameter_set, dict): # Keep as dictionary to allow "default" as value self.params = parameter_set @@ -133,7 +133,7 @@ def update(self, params_dict: dict = None, check_already_exists: bool = True): Parameters ---------- params_dict : dict - Dictionary of parameter values to update parameter dictionary with. + A dictionary of parameters and values used to update the parameter values check_already_exists : bool, optional Whether to check that a parameter in `params_dict` already exists when trying to update it. This is to avoid cases where an intended change in the parameters From f39ea84cc6009406af0c13893eec5ec9f0b19038 Mon Sep 17 00:00:00 2001 From: Brady Planden Date: Fri, 24 Jan 2025 10:13:56 +0000 Subject: [PATCH 07/14] refactor: updates default ECM OCV application --- examples/parameters/initial_ecm_parameters.json | 1 - pybop/models/empirical/base_ecm.py | 13 +++++-------- tests/unit/test_models.py | 1 - tests/unit/test_parameter_sets.py | 1 - 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/parameters/initial_ecm_parameters.json b/examples/parameters/initial_ecm_parameters.json index 8da710968..06e9b8b29 100644 --- a/examples/parameters/initial_ecm_parameters.json +++ b/examples/parameters/initial_ecm_parameters.json @@ -12,7 +12,6 @@ "Cell-jig heat transfer coefficient [W/K]": 10, "Jig thermal mass [J/K]": 500, "Jig-air heat transfer coefficient [W/K]": 10, - "Open-circuit voltage [V]": "default", "R0 [Ohm]": 0.001, "Element-1 initial overpotential [V]": 0, "Element-2 initial overpotential [V]": 0, diff --git a/pybop/models/empirical/base_ecm.py b/pybop/models/empirical/base_ecm.py index a0f3e0b27..206e20be5 100644 --- a/pybop/models/empirical/base_ecm.py +++ b/pybop/models/empirical/base_ecm.py @@ -56,17 +56,14 @@ def __init__( model_options[key] = value pybamm_model = pybamm_model(**model_options) - # Correct OCP if set to default + # Add OCV if not provided if ( parameter_set is not None - and "Open-circuit voltage [V]" in parameter_set.keys() + and "Open-circuit voltage [V]" not in parameter_set.keys() ): - default_ocp = pybamm_model.default_parameter_values[ - "Open-circuit voltage [V]" - ] - if parameter_set["Open-circuit voltage [V]"] == "default": - print("Setting open-circuit voltage to default function") - parameter_set["Open-circuit voltage [V]"] = default_ocp + parameter_set["Open-circuit voltage [V]"] = ( + pybamm_model.default_parameter_values["Open-circuit voltage [V]"] + ) super().__init__( name=name, parameter_set=parameter_set, check_params=check_params, eis=eis diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index b7ac65238..8b4f78a97 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -377,7 +377,6 @@ def test_thevenin_model(self): json_path="examples/parameters/initial_ecm_parameters.json" ) parameter_set.import_parameters() - assert parameter_set["Open-circuit voltage [V]"] == "default" model = pybop.empirical.Thevenin( parameter_set=parameter_set, options={"number of rc elements": 2} ) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index c853fae1b..12d44f7d7 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -26,7 +26,6 @@ def params_dict(self): "Cell-jig heat transfer coefficient [W/K]": 10, "Jig thermal mass [J/K]": 500, "Jig-air heat transfer coefficient [W/K]": 10, - "Open-circuit voltage [V]": "default", "R0 [Ohm]": 0.001, "Element-1 initial overpotential [V]": 0, "Element-2 initial overpotential [V]": 0, From 8c2e22f8e72085e008d70477ffdaa05bba9fc6b5 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:07:07 +0000 Subject: [PATCH 08/14] Move ParameterValues construction to init --- .../equivalent_circuit_identification.ipynb | 3 +- .../getting_started/optimiser_interface.ipynb | 1 - .../battery_parameterisation/ecm_CMAES.py | 1 - examples/scripts/getting_started/BPX_spm.py | 3 +- pybop/models/base_model.py | 8 +- pybop/models/empirical/base_ecm.py | 9 +- pybop/parameters/parameter_set.py | 166 +++++++----------- tests/integration/test_classification.py | 9 +- .../integration/test_monte_carlo_thevenin.py | 3 +- .../test_thevenin_parameterisation.py | 3 +- tests/integration/test_transformation.py | 3 +- tests/unit/test_models.py | 1 - tests/unit/test_parameter_sets.py | 41 +---- 13 files changed, 89 insertions(+), 162 deletions(-) diff --git a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification.ipynb b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification.ipynb index f2d7bfa7e..f589958f1 100644 --- a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification.ipynb +++ b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification.ipynb @@ -116,8 +116,7 @@ "source": [ "# parameter_set = pybop.ParameterSet(\n", "# json_path=\"examples/parameters/initial_ecm_parameters.json\"\n", - "# )\n", - "# parameter_set.import_parameters()" + "# )" ] }, { diff --git a/examples/notebooks/getting_started/optimiser_interface.ipynb b/examples/notebooks/getting_started/optimiser_interface.ipynb index eca6ee01b..e53d1bd33 100644 --- a/examples/notebooks/getting_started/optimiser_interface.ipynb +++ b/examples/notebooks/getting_started/optimiser_interface.ipynb @@ -100,7 +100,6 @@ "parameter_set = pybop.ParameterSet(\n", " json_path=\"../../parameters/initial_ecm_parameters.json\"\n", ")\n", - "parameter_set.import_parameters()\n", "# Define the model\n", "model = pybop.empirical.Thevenin(\n", " parameter_set=parameter_set, options={\"number of rc elements\": 1}\n", diff --git a/examples/scripts/battery_parameterisation/ecm_CMAES.py b/examples/scripts/battery_parameterisation/ecm_CMAES.py index f426eed21..4a5e3f971 100644 --- a/examples/scripts/battery_parameterisation/ecm_CMAES.py +++ b/examples/scripts/battery_parameterisation/ecm_CMAES.py @@ -6,7 +6,6 @@ parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) -parameter_set.import_parameters() # Alternatively, define the initial parameter set with a dictionary # Add definitions for R's, C's, and initial overpotentials for any additional RC elements diff --git a/examples/scripts/getting_started/BPX_spm.py b/examples/scripts/getting_started/BPX_spm.py index 1fde8923e..14be90352 100644 --- a/examples/scripts/getting_started/BPX_spm.py +++ b/examples/scripts/getting_started/BPX_spm.py @@ -3,8 +3,7 @@ import pybop # Define model -bpx_parameters = pybop.ParameterSet(json_path="examples/parameters/example_BPX.json") -parameter_set = bpx_parameters.import_from_bpx() +parameter_set = pybop.ParameterSet(json_path="examples/parameters/example_BPX.json") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index df5cc037d..8206d3bbe 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -109,9 +109,11 @@ def __init__( self.eis = eis self._calculate_sensitivities = False - if not isinstance(parameter_set, ParameterSet): - parameter_set = ParameterSet(parameter_set) - self._parameter_set = parameter_set() + self._parameter_set = None + if parameter_set is not None: + if not isinstance(parameter_set, ParameterSet): + parameter_set = ParameterSet(parameter_set) + self._parameter_set = parameter_set().copy() self.param_checker = check_params self.pybamm_model = None diff --git a/pybop/models/empirical/base_ecm.py b/pybop/models/empirical/base_ecm.py index 206e20be5..eca1533d3 100644 --- a/pybop/models/empirical/base_ecm.py +++ b/pybop/models/empirical/base_ecm.py @@ -61,8 +61,13 @@ def __init__( parameter_set is not None and "Open-circuit voltage [V]" not in parameter_set.keys() ): - parameter_set["Open-circuit voltage [V]"] = ( - pybamm_model.default_parameter_values["Open-circuit voltage [V]"] + parameter_set.update( + { + "Open-circuit voltage [V]": pybamm_model.default_parameter_values[ + "Open-circuit voltage [V]" + ] + }, + check_already_exists=False, ) super().__init__( diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 1c653c0b4..a8896b043 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -30,68 +30,71 @@ class ParameterSet: json_path : str, optional Path to a JSON file containing parameter data. If provided, parameters will be imported from this file during initialisation. + formation_concentrations : bool, optional + If True, re-calculates the initial concentrations of lithium in the active material (default: False). """ def __init__( self, parameter_set: Union[str, dict, ParameterValues] = None, json_path: Optional[str] = None, - formation_concentrations: bool = False, + formation_concentrations: Optional[bool] = False, ): if parameter_set is not None and json_path is not None: raise ValueError( "ParameterSet needs either a parameter_set or json_path as an input, not both." ) - self.json_path = json_path - self.params = None + self._json_path = None + self.parameter_values = None self.chemistry = None self.formation_concentrations = formation_concentrations - if isinstance(parameter_set, str): + if json_path is not None: + self.import_parameters(json_path) + else: + self.parameter_values = self.convert_to_parameter_values(parameter_set) + + if self.parameter_values is not None: + self.chemistry = self.parameter_values.get("chemistry", None) + + if self.formation_concentrations: + set_formation_concentrations(self.parameter_values) + + def convert_to_parameter_values(self, parameter_set): + """ + Converts a parameter set to a PyBaMM ParameterValues object. + """ + if parameter_set is None: + return None + elif isinstance(parameter_set, str): # Use class method - self.params = self.pybamm(parameter_set) + return self.pybamm(parameter_set) elif isinstance(parameter_set, dict): - # Keep as dictionary to allow "default" as value - self.params = parameter_set + return ParameterValues(parameter_set) elif isinstance(parameter_set, ParameterValues): - self.params = parameter_set - - if self.params is not None: - self.chemistry = self.params.get("chemistry", None) + return parameter_set + else: + return parameter_set.parameter_values - def __call__(self, formation_concentrations: Optional[bool] = False): + def __call__(self): """ - Obtain a copy of the parameter set as a PyBaMM ParameterValues object. - - Parameters - ---------- - set_formation_concentrations : bool, optional - If True, re-calculates the initial concentrations of lithium in the active material (default: False). + Return the parameter set as a pybamm.ParameterValues object. Returns ------- pybamm.ParameterValues - A PyBaMM parameter set corresponding to the parameter set stored in self.params. + The parameter set for a PyBaMM model. """ - self.formation_concentrations = formation_concentrations - - if self.params is None: - return None - elif isinstance(self.params, dict): - parameter_set = ParameterValues(self.params).copy() - else: - parameter_set = self.params.copy() - if self.formation_concentrations: - set_formation_concentrations(parameter_set) + set_formation_concentrations(self.parameter_values) - return parameter_set + return self.parameter_values def __setitem__(self, key, value): - self.params[key] = value + self.parameter_values[key] = value def __getitem__(self, key): - return self.params[key] + return self.parameter_values[key] @staticmethod def evaluate_symbol(symbol: Union[Symbol, Number], params: dict): @@ -124,7 +127,7 @@ def keys(self) -> list: """ A list of parameter names """ - return list(self.params.keys()) + return list(self.parameter_values.keys()) def update(self, params_dict: dict = None, check_already_exists: bool = True): """ @@ -139,18 +142,9 @@ def update(self, params_dict: dict = None, check_already_exists: bool = True): to update it. This is to avoid cases where an intended change in the parameters is ignored due a typo in the parameter name (default: True). """ - if isinstance(self.params, ParameterValues): - self.params.update(params_dict, check_already_exists=check_already_exists) - else: - if check_already_exists is True: - for key in params_dict.keys(): - if key not in self.params.keys(): - raise KeyError( - f"Cannot update parameter '{key}' as it does not have a default " - "value. If you are sure you want to update this parameter, use " - "param.update({name: value}, check_already_exists=False)" - ) - self.params.update(params_dict) + self.parameter_values.update( + params_dict, check_already_exists=check_already_exists + ) def import_parameters(self, json_path: Optional[str] = None): """ @@ -175,62 +169,30 @@ def import_parameters(self, json_path: Optional[str] = None): FileNotFoundError If the specified JSON file cannot be found. """ - if self.params: + if self.parameter_values: raise ValueError("Parameter set already constructed.") - if json_path is not None: - self.json_path = json_path - # Read JSON file - if self.json_path: - with open(self.json_path) as file: - self.params = json.load(file) + if json_path: + self._json_path = json_path + try: + self.parameter_values = ParameterValues.create_from_bpx(self._json_path) + except Exception: + print( + "The JSON file was not recognised as a BPX parameter set. Importing as a JSON file." + ) + with open(self._json_path) as file: + params = json.load(file) + self.parameter_values = ParameterValues(params) else: raise ValueError("No path was provided.") - self.chemistry = self.params.get("chemistry", None) - - return self.params - - def import_from_bpx(self, json_path=None): - """ - Imports parameters from a JSON file in the BPX format specified by the `json_path` - attribute. - Credit: PyBaMM - - If a `json_path` is provided at initialization or as an argument, that JSON file - is loaded and the parameters are stored in the `params` attribute. - - Parameters - ---------- - json_path : str, optional - Path to the JSON file from which to import parameters. If provided, it overrides the instance's `json_path`. - - Returns - ------- - dict - The dictionary containing the imported parameters. - - Raises - ------ - FileNotFoundError - If the specified JSON file cannot be found. - """ - if self.params: - raise ValueError("Parameter set already constructed.") - - if json_path is not None: - self.json_path = json_path - - # Read JSON file - if self.json_path: - self.params = ParameterValues.create_from_bpx(self.json_path) - else: - raise ValueError("No path was provided.") + self.chemistry = self.parameter_values.get("chemistry", None) - self.chemistry = self.params.get("chemistry", None) + if self.formation_concentrations: + set_formation_concentrations(self.parameter_values) - return self.params + return self.parameter_values def export_parameters(self, output_json_path, fit_params=None): """ @@ -252,11 +214,14 @@ def export_parameters(self, output_json_path, fit_params=None): ValueError If there are no parameters to export. """ - if not self.params: + if not self.parameter_values: raise ValueError("No parameters to export. Please import parameters first.") # Prepare a copy of the params to avoid modifying the original dict - exportable_params = {**{"chemistry": self.chemistry}, **self.params.copy()} + exportable_params = { + **{"chemistry": self.chemistry}, + **self.parameter_values.copy(), + } # Update parameter set if fit_params is not None: @@ -295,7 +260,7 @@ def is_json_serializable(self, value): return False @classmethod - def pybamm(cls, name, formation_concentrations=False): + def pybamm(cls, name): """ Retrieves a PyBaMM parameter set by name. @@ -303,8 +268,6 @@ def pybamm(cls, name, formation_concentrations=False): ---------- name : str The name of the PyBaMM parameter set to retrieve. - set_formation_concentrations : bool, optional - If True, re-calculates the initial concentrations of lithium in the active material (default: False). Returns ------- @@ -317,12 +280,7 @@ def pybamm(cls, name, formation_concentrations=False): if name not in list(parameter_sets): raise ValueError(msg) - parameter_set = ParameterValues(name).copy() - - if formation_concentrations: - set_formation_concentrations(parameter_set) - - return parameter_set + return ParameterValues(name).copy() def set_formation_concentrations(parameter_set): diff --git a/tests/integration/test_classification.py b/tests/integration/test_classification.py index f6fc3ab4a..937e57695 100644 --- a/tests/integration/test_classification.py +++ b/tests/integration/test_classification.py @@ -39,13 +39,12 @@ def parameter_set(self): parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - parameter_set.import_parameters() - parameter_set.params.update({"C1 [F]": 1000}) + parameter_set.update({"C1 [F]": 1000}) return parameter_set @pytest.fixture def model(self, parameter_set, parameters): - parameter_set.params.update(parameters.as_dict(parameters.true_value())) + parameter_set.update(parameters.as_dict(parameters.true_value())) return pybop.empirical.Thevenin(parameter_set=parameter_set) @pytest.fixture @@ -119,11 +118,11 @@ def test_insensitive_classify_using_hessian(self, parameter_set): bounds=[-1e-4, 1e-4], true_value=0, ) - parameter_set.params.update( + parameter_set.update( {"R0_a [Ohm]": 0.001, "R0_b [Ohm]": 0}, check_already_exists=False, ) - parameter_set.params.update( + parameter_set.update( {"R0 [Ohm]": Parameter("R0_a [Ohm]") + Parameter("R0_b [Ohm]")}, ) model = pybop.empirical.Thevenin(parameter_set=parameter_set) diff --git a/tests/integration/test_monte_carlo_thevenin.py b/tests/integration/test_monte_carlo_thevenin.py index a6c9738cf..0445e1ce9 100644 --- a/tests/integration/test_monte_carlo_thevenin.py +++ b/tests/integration/test_monte_carlo_thevenin.py @@ -42,8 +42,7 @@ def model(self): parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - parameter_set.import_parameters() - parameter_set.params.update( + parameter_set.update( { "C1 [F]": 1000, "R0 [Ohm]": self.ground_truth[0], diff --git a/tests/integration/test_thevenin_parameterisation.py b/tests/integration/test_thevenin_parameterisation.py index ec0f83890..9b9b86475 100644 --- a/tests/integration/test_thevenin_parameterisation.py +++ b/tests/integration/test_thevenin_parameterisation.py @@ -23,8 +23,7 @@ def model(self): parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - parameter_set.import_parameters() - parameter_set.params.update( + parameter_set.update( { "C1 [F]": 1000, "R0 [Ohm]": self.ground_truth[0], diff --git a/tests/integration/test_transformation.py b/tests/integration/test_transformation.py index 35a05c525..8886587b6 100644 --- a/tests/integration/test_transformation.py +++ b/tests/integration/test_transformation.py @@ -37,8 +37,7 @@ def model(self): parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - parameter_set.import_parameters() - parameter_set.params.update( + parameter_set.update( { "C1 [F]": 1000, "R0 [Ohm]": self.ground_truth[0], diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index 8b4f78a97..802a57d65 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -376,7 +376,6 @@ def test_thevenin_model(self): parameter_set = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - parameter_set.import_parameters() model = pybop.empirical.Thevenin( parameter_set=parameter_set, options={"number of rc elements": 2} ) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 12d44f7d7..1603045e6 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -71,8 +71,6 @@ def test_ecm_parameter_sets(self, params_dict): json_params = pybop.ParameterSet( json_path="examples/parameters/initial_ecm_parameters.json" ) - json_params.import_parameters() - with pytest.raises( ValueError, match="Parameter set already constructed.", @@ -85,9 +83,7 @@ def test_ecm_parameter_sets(self, params_dict): ) params = pybop.ParameterSet(params_dict) - - assert json_params.params == params.params - assert params_dict == params.params + assert json_params.parameter_values == params.parameter_values with pytest.raises( ValueError, @@ -126,42 +122,17 @@ def test_ecm_parameter_sets(self, params_dict): @pytest.mark.unit def test_bpx_parameter_sets(self): # Test importing a BPX json file - bpx_parameters = pybop.ParameterSet() - with pytest.raises( - ValueError, - match="No path was provided.", - ): - bpx_parameters.import_from_bpx() - - bpx_parameters = pybop.ParameterSet( + bpx_params = pybop.ParameterSet( json_path="examples/parameters/example_BPX.json" ) - bpx_parameters.import_from_bpx() - with pytest.raises( - ValueError, - match="Parameter set already constructed.", - ): - bpx_parameters.import_from_bpx() - - bpx_parameters = pybop.ParameterSet() - bpx_parameters.import_from_bpx(json_path="examples/parameters/example_BPX.json") + params = pybop.ParameterSet() + params.import_parameters(json_path="examples/parameters/example_BPX.json") + assert bpx_params.parameter_values == params.parameter_values @pytest.mark.unit def test_set_formation_concentrations(self): - parameter_set = pybop.ParameterSet.pybamm( - "Chen2020", formation_concentrations=True - ) - - assert ( - parameter_set["Initial concentration in negative electrode [mol.m-3]"] == 0 - ) - assert ( - parameter_set["Initial concentration in positive electrode [mol.m-3]"] > 0 - ) - - parameter_set = pybop.ParameterSet(parameter_set) - parameter_set = parameter_set(formation_concentrations=True) + parameter_set = pybop.ParameterSet("Chen2020", formation_concentrations=True) assert ( parameter_set["Initial concentration in negative electrode [mol.m-3]"] == 0 From 8d41f1cf9b7a312d917a0d55e986114875753210 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:36:54 +0000 Subject: [PATCH 09/14] Deprecate ParameterSet.pybamm --- .../equivalent_circuit_identification_hppc.ipynb | 2 +- .../equivalent_circuit_identification_multipulse.ipynb | 2 +- .../monte_carlo_ecm_identification.ipynb | 2 +- .../battery_parameterisation/multi_model_identification.ipynb | 2 +- .../battery_parameterisation/pouch_cell_identification.ipynb | 2 +- .../comparison_examples/comparing_cost_functions.ipynb | 2 +- .../comparison_examples/multi_optimiser_identification.ipynb | 2 +- .../notebooks/comparison_examples/optimiser_calibration.ipynb | 2 +- examples/notebooks/comparison_examples/solver_selection.ipynb | 2 +- .../design_optimisation/energy_based_electrode_design.ipynb | 2 +- examples/notebooks/getting_started/adamw_identification.ipynb | 2 +- examples/notebooks/getting_started/cost_compute_methods.ipynb | 2 +- examples/notebooks/getting_started/creating_a_model.ipynb | 2 +- examples/notebooks/getting_started/maximum_a_posteriori.ipynb | 2 +- .../scripts/battery_parameterisation/ecm_tau_constraints.py | 2 +- examples/scripts/battery_parameterisation/ecm_with_tau.py | 4 ++-- examples/scripts/battery_parameterisation/eis_fitting.py | 2 +- .../scripts/battery_parameterisation/full_cell_balancing.py | 4 ++-- examples/scripts/battery_parameterisation/gitt.py | 2 +- examples/scripts/comparison_examples/cuckoo.py | 2 +- examples/scripts/comparison_examples/grouped_SPMe.py | 4 ++-- .../scripts/comparison_examples/jaxified-idaklu-benchmarks.py | 2 +- examples/scripts/comparison_examples/maximum_a_posteriori.py | 2 +- examples/scripts/comparison_examples/maximum_likelihood.py | 2 +- examples/scripts/comparison_examples/random_search.py | 2 +- examples/scripts/comparison_examples/selecting_a_solver.py | 2 +- examples/scripts/comparison_examples/spm_AdamW.py | 2 +- examples/scripts/comparison_examples/spm_CMAES.py | 2 +- examples/scripts/comparison_examples/spm_IRPropMin.py | 2 +- examples/scripts/comparison_examples/spm_NelderMead.py | 2 +- examples/scripts/comparison_examples/spm_SNES.py | 2 +- examples/scripts/comparison_examples/spm_UKF.py | 2 +- examples/scripts/comparison_examples/spm_XNES.py | 2 +- examples/scripts/comparison_examples/spm_descent.py | 2 +- examples/scripts/comparison_examples/spm_pso.py | 2 +- examples/scripts/comparison_examples/spm_scipymin.py | 2 +- examples/scripts/design_optimisation/maximising_energy.py | 2 +- examples/scripts/design_optimisation/maximising_power.py | 2 +- examples/scripts/getting_started/functional_parameters.py | 2 +- examples/scripts/getting_started/jax-solver-example.py | 2 +- examples/scripts/getting_started/linked_parameters.py | 2 +- examples/scripts/getting_started/mcmc_example.py | 2 +- examples/scripts/getting_started/multi_fitting.py | 2 +- examples/scripts/getting_started/multi_start_optimisation.py | 2 +- examples/scripts/getting_started/spm_weighted_cost.py | 2 +- tests/unit/test_parameter_sets.py | 1 - 46 files changed, 48 insertions(+), 49 deletions(-) diff --git a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_hppc.ipynb b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_hppc.ipynb index 12b65dfb7..f6045f92a 100644 --- a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_hppc.ipynb +++ b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_hppc.ipynb @@ -76,7 +76,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"ECM_Example\")\n", + "parameter_set = pybop.ParameterSet(\"ECM_Example\")\n", "parameter_set.update(\n", " {\n", " \"Cell capacity [A.h]\": 3,\n", diff --git a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_multipulse.ipynb b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_multipulse.ipynb index 290e3f28b..b9be2829a 100644 --- a/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_multipulse.ipynb +++ b/examples/notebooks/battery_parameterisation/equivalent_circuit_identification_multipulse.ipynb @@ -78,7 +78,7 @@ "outputs": [], "source": [ "# Load the parameters\n", - "parameter_set = pybop.ParameterSet.pybamm(\"ECM_Example\")\n", + "parameter_set = pybop.ParameterSet(\"ECM_Example\")\n", "parameter_set.update(\n", " {\n", " \"Cell capacity [A.h]\": 3,\n", diff --git a/examples/notebooks/battery_parameterisation/monte_carlo_ecm_identification.ipynb b/examples/notebooks/battery_parameterisation/monte_carlo_ecm_identification.ipynb index 4648ff4fc..189c043b1 100644 --- a/examples/notebooks/battery_parameterisation/monte_carlo_ecm_identification.ipynb +++ b/examples/notebooks/battery_parameterisation/monte_carlo_ecm_identification.ipynb @@ -194,7 +194,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"ECM_Example\")\n", + "parameter_set = pybop.ParameterSet(\"ECM_Example\")\n", "parameter_set.update(\n", " {\n", " \"Cell capacity [A.h]\": 22.651, # 083/828 - C/20\n", diff --git a/examples/notebooks/battery_parameterisation/multi_model_identification.ipynb b/examples/notebooks/battery_parameterisation/multi_model_identification.ipynb index b97eb06d0..528bb3f2e 100644 --- a/examples/notebooks/battery_parameterisation/multi_model_identification.ipynb +++ b/examples/notebooks/battery_parameterisation/multi_model_identification.ipynb @@ -128,7 +128,7 @@ }, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "parameter_set = pybamm.get_size_distribution_parameters(parameter_set)\n", "synth_model = pybop.lithium_ion.DFN(\n", " parameter_set=parameter_set, options={\"particle size\": \"distribution\"}\n", diff --git a/examples/notebooks/battery_parameterisation/pouch_cell_identification.ipynb b/examples/notebooks/battery_parameterisation/pouch_cell_identification.ipynb index 162e01c92..15535f4ed 100644 --- a/examples/notebooks/battery_parameterisation/pouch_cell_identification.ipynb +++ b/examples/notebooks/battery_parameterisation/pouch_cell_identification.ipynb @@ -108,7 +108,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Marquis2019\")\n", + "parameter_set = pybop.ParameterSet(\"Marquis2019\")\n", "parameter_set.update(\n", " {\n", " \"Negative electrode active material volume fraction\": 0.495,\n", diff --git a/examples/notebooks/comparison_examples/comparing_cost_functions.ipynb b/examples/notebooks/comparison_examples/comparing_cost_functions.ipynb index 3b74e74db..495bc9d63 100644 --- a/examples/notebooks/comparison_examples/comparing_cost_functions.ipynb +++ b/examples/notebooks/comparison_examples/comparing_cost_functions.ipynb @@ -113,7 +113,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)" ] }, diff --git a/examples/notebooks/comparison_examples/multi_optimiser_identification.ipynb b/examples/notebooks/comparison_examples/multi_optimiser_identification.ipynb index 4ea782b04..f349554ed 100644 --- a/examples/notebooks/comparison_examples/multi_optimiser_identification.ipynb +++ b/examples/notebooks/comparison_examples/multi_optimiser_identification.ipynb @@ -123,7 +123,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "synth_model = pybop.lithium_ion.DFN(parameter_set=parameter_set)\n", "model = pybop.lithium_ion.SPMe(parameter_set=parameter_set)" ] diff --git a/examples/notebooks/comparison_examples/optimiser_calibration.ipynb b/examples/notebooks/comparison_examples/optimiser_calibration.ipynb index ee39cacc5..91af6cb19 100644 --- a/examples/notebooks/comparison_examples/optimiser_calibration.ipynb +++ b/examples/notebooks/comparison_examples/optimiser_calibration.ipynb @@ -123,7 +123,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "parameter_set.update(\n", " {\n", " \"Negative electrode active material volume fraction\": 0.65,\n", diff --git a/examples/notebooks/comparison_examples/solver_selection.ipynb b/examples/notebooks/comparison_examples/solver_selection.ipynb index 3faa51d76..0dfd6bba8 100644 --- a/examples/notebooks/comparison_examples/solver_selection.ipynb +++ b/examples/notebooks/comparison_examples/solver_selection.ipynb @@ -105,7 +105,7 @@ "outputs": [], "source": [ "# Model\n", - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)\n", "\n", "# Synthetic data\n", diff --git a/examples/notebooks/design_optimisation/energy_based_electrode_design.ipynb b/examples/notebooks/design_optimisation/energy_based_electrode_design.ipynb index cd5d05341..f6be57063 100644 --- a/examples/notebooks/design_optimisation/energy_based_electrode_design.ipynb +++ b/examples/notebooks/design_optimisation/energy_based_electrode_design.ipynb @@ -131,7 +131,7 @@ }, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "parameter_set.update(\n", " {\n", " \"Electrolyte density [kg.m-3]\": Parameter(\"Separator density [kg.m-3]\"),\n", diff --git a/examples/notebooks/getting_started/adamw_identification.ipynb b/examples/notebooks/getting_started/adamw_identification.ipynb index b8273eb07..0cf8c8dc2 100644 --- a/examples/notebooks/getting_started/adamw_identification.ipynb +++ b/examples/notebooks/getting_started/adamw_identification.ipynb @@ -127,7 +127,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)" ] }, diff --git a/examples/notebooks/getting_started/cost_compute_methods.ipynb b/examples/notebooks/getting_started/cost_compute_methods.ipynb index da541a365..6657d7877 100644 --- a/examples/notebooks/getting_started/cost_compute_methods.ipynb +++ b/examples/notebooks/getting_started/cost_compute_methods.ipynb @@ -98,7 +98,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)" ] }, diff --git a/examples/notebooks/getting_started/creating_a_model.ipynb b/examples/notebooks/getting_started/creating_a_model.ipynb index 398929831..122b17797 100644 --- a/examples/notebooks/getting_started/creating_a_model.ipynb +++ b/examples/notebooks/getting_started/creating_a_model.ipynb @@ -81,7 +81,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Marquis2019\")\n", + "parameter_set = pybop.ParameterSet(\"Marquis2019\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)" ] }, diff --git a/examples/notebooks/getting_started/maximum_a_posteriori.ipynb b/examples/notebooks/getting_started/maximum_a_posteriori.ipynb index 18a5fbea2..8706a0715 100644 --- a/examples/notebooks/getting_started/maximum_a_posteriori.ipynb +++ b/examples/notebooks/getting_started/maximum_a_posteriori.ipynb @@ -97,7 +97,7 @@ "metadata": {}, "outputs": [], "source": [ - "parameter_set = pybop.ParameterSet.pybamm(\"Chen2020\")\n", + "parameter_set = pybop.ParameterSet(\"Chen2020\")\n", "model = pybop.lithium_ion.SPM(parameter_set=parameter_set)" ] }, diff --git a/examples/scripts/battery_parameterisation/ecm_tau_constraints.py b/examples/scripts/battery_parameterisation/ecm_tau_constraints.py index 6d2bf85e7..2849b76d5 100644 --- a/examples/scripts/battery_parameterisation/ecm_tau_constraints.py +++ b/examples/scripts/battery_parameterisation/ecm_tau_constraints.py @@ -22,7 +22,7 @@ """ # Define the initial parameter set -parameter_set = pybop.ParameterSet.pybamm("ECM_Example") +parameter_set = pybop.ParameterSet("ECM_Example") parameter_set.update( { "Initial SoC": 0.75, diff --git a/examples/scripts/battery_parameterisation/ecm_with_tau.py b/examples/scripts/battery_parameterisation/ecm_with_tau.py index a1942efbe..3444edaa2 100644 --- a/examples/scripts/battery_parameterisation/ecm_with_tau.py +++ b/examples/scripts/battery_parameterisation/ecm_with_tau.py @@ -11,7 +11,7 @@ """ # Define the initial parameter set -parameter_set = pybop.ParameterSet.pybamm("ECM_Example") +parameter_set = pybop.ParameterSet("ECM_Example") parameter_set.update( { "Initial SoC": 0.75, @@ -109,7 +109,7 @@ parameter_set["R0 [Ohm]"], parameter_set["R1 [Ohm]"], parameter_set["tau1 [s]"], - parameter_set.evaluate(pybamm.Parameter("C1 [F]")), + parameter_set.parameter_values.evaluate(pybamm.Parameter("C1 [F]")), ], ) print("Estimated parameters:", results.x.tolist() + [results.x[2] / results.x[1]]) diff --git a/examples/scripts/battery_parameterisation/eis_fitting.py b/examples/scripts/battery_parameterisation/eis_fitting.py index b93f1c47e..a06fd02d9 100644 --- a/examples/scripts/battery_parameterisation/eis_fitting.py +++ b/examples/scripts/battery_parameterisation/eis_fitting.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set["Contact resistance [Ohm]"] = 0.0 initial_state = {"Initial SoC": 0.5} n_frequency = 20 diff --git a/examples/scripts/battery_parameterisation/full_cell_balancing.py b/examples/scripts/battery_parameterisation/full_cell_balancing.py index 69c65d089..902e849ad 100644 --- a/examples/scripts/battery_parameterisation/full_cell_balancing.py +++ b/examples/scripts/battery_parameterisation/full_cell_balancing.py @@ -3,12 +3,12 @@ import pybop # Parameter set definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set["Lower voltage cut-off [V]"] = 2.3 parameter_set["Upper voltage cut-off [V]"] = 4.4 # Set initial state and unpack true values -parameter_set.set_initial_stoichiometries(initial_value=1.0) +parameter_set.parameter_values.set_initial_stoichiometries(initial_value=1.0) cs_n_max = parameter_set["Maximum concentration in negative electrode [mol.m-3]"] cs_p_max = parameter_set["Maximum concentration in positive electrode [mol.m-3]"] cs_n_init = parameter_set["Initial concentration in negative electrode [mol.m-3]"] diff --git a/examples/scripts/battery_parameterisation/gitt.py b/examples/scripts/battery_parameterisation/gitt.py index 059aac861..1d8fbfd2c 100644 --- a/examples/scripts/battery_parameterisation/gitt.py +++ b/examples/scripts/battery_parameterisation/gitt.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Xu2019") +parameter_set = pybop.ParameterSet("Xu2019") model = pybop.lithium_ion.SPM( parameter_set=parameter_set, options={"working electrode": "positive"} ) diff --git a/examples/scripts/comparison_examples/cuckoo.py b/examples/scripts/comparison_examples/cuckoo.py index 0ad7b22e9..0c8ea0f65 100644 --- a/examples/scripts/comparison_examples/cuckoo.py +++ b/examples/scripts/comparison_examples/cuckoo.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set.update( { "Negative electrode active material volume fraction": 0.7, diff --git a/examples/scripts/comparison_examples/grouped_SPMe.py b/examples/scripts/comparison_examples/grouped_SPMe.py index 75e757cef..ca509e0be 100644 --- a/examples/scripts/comparison_examples/grouped_SPMe.py +++ b/examples/scripts/comparison_examples/grouped_SPMe.py @@ -12,7 +12,7 @@ plot_dict = pybop.plot.StandardPlot(layout_options=layout_options) # Unpack parameter values from Chen2020 -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") # Fix the electrolyte diffusivity and conductivity ce0 = parameter_set["Initial concentration in electrolyte [mol.m-3]"] @@ -54,7 +54,7 @@ plot_dict.add_traces(dataset["Time [s]"], dataset["Voltage [V]"]) # Test model in the time domain -grouped_parameter_set = convert_physical_to_grouped_parameters(parameter_set) +grouped_parameter_set = convert_physical_to_grouped_parameters(parameter_set()) time_domain_grouped = pybop.lithium_ion.GroupedSPMe( parameter_set=grouped_parameter_set, options=model_options, diff --git a/examples/scripts/comparison_examples/jaxified-idaklu-benchmarks.py b/examples/scripts/comparison_examples/jaxified-idaklu-benchmarks.py index ed17b24f2..1729f875c 100644 --- a/examples/scripts/comparison_examples/jaxified-idaklu-benchmarks.py +++ b/examples/scripts/comparison_examples/jaxified-idaklu-benchmarks.py @@ -16,7 +16,7 @@ ] # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.DFN(parameter_set=parameter_set, solver=solvers[0]) # Fitting parameters diff --git a/examples/scripts/comparison_examples/maximum_a_posteriori.py b/examples/scripts/comparison_examples/maximum_a_posteriori.py index b04fa8fbb..7f83e2eba 100644 --- a/examples/scripts/comparison_examples/maximum_a_posteriori.py +++ b/examples/scripts/comparison_examples/maximum_a_posteriori.py @@ -6,7 +6,7 @@ sigma = 0.002 # Construct and update initial parameter values -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set.update( { "Negative electrode active material volume fraction": 0.43, diff --git a/examples/scripts/comparison_examples/maximum_likelihood.py b/examples/scripts/comparison_examples/maximum_likelihood.py index a6298886e..104526825 100644 --- a/examples/scripts/comparison_examples/maximum_likelihood.py +++ b/examples/scripts/comparison_examples/maximum_likelihood.py @@ -4,7 +4,7 @@ import pybop # Define model and set initial parameter values -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set.update( { "Negative electrode active material volume fraction": 0.63, diff --git a/examples/scripts/comparison_examples/random_search.py b/examples/scripts/comparison_examples/random_search.py index ce1e50dac..c881da5a4 100644 --- a/examples/scripts/comparison_examples/random_search.py +++ b/examples/scripts/comparison_examples/random_search.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set.update( { "Negative electrode active material volume fraction": 0.7, diff --git a/examples/scripts/comparison_examples/selecting_a_solver.py b/examples/scripts/comparison_examples/selecting_a_solver.py index 248d943f5..922463678 100644 --- a/examples/scripts/comparison_examples/selecting_a_solver.py +++ b/examples/scripts/comparison_examples/selecting_a_solver.py @@ -6,7 +6,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) solvers = [ diff --git a/examples/scripts/comparison_examples/spm_AdamW.py b/examples/scripts/comparison_examples/spm_AdamW.py index 5937ed726..5533af925 100644 --- a/examples/scripts/comparison_examples/spm_AdamW.py +++ b/examples/scripts/comparison_examples/spm_AdamW.py @@ -5,7 +5,7 @@ # Define model and use high-performant solver for sensitivities solver = pybamm.IDAKLUSolver() -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set, solver=solver) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_CMAES.py b/examples/scripts/comparison_examples/spm_CMAES.py index bd125710c..dd01dea77 100644 --- a/examples/scripts/comparison_examples/spm_CMAES.py +++ b/examples/scripts/comparison_examples/spm_CMAES.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_IRPropMin.py b/examples/scripts/comparison_examples/spm_IRPropMin.py index bd3f9c50b..403643e4d 100644 --- a/examples/scripts/comparison_examples/spm_IRPropMin.py +++ b/examples/scripts/comparison_examples/spm_IRPropMin.py @@ -5,7 +5,7 @@ # Define model and use high-performant solver for sensitivities solver = pybamm.IDAKLUSolver() -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set, solver=solver) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_NelderMead.py b/examples/scripts/comparison_examples/spm_NelderMead.py index 08be57421..c2516c4d9 100644 --- a/examples/scripts/comparison_examples/spm_NelderMead.py +++ b/examples/scripts/comparison_examples/spm_NelderMead.py @@ -3,7 +3,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_SNES.py b/examples/scripts/comparison_examples/spm_SNES.py index 20183bc98..4269d310e 100644 --- a/examples/scripts/comparison_examples/spm_SNES.py +++ b/examples/scripts/comparison_examples/spm_SNES.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_UKF.py b/examples/scripts/comparison_examples/spm_UKF.py index 33b38de1e..5dc0d0dc6 100644 --- a/examples/scripts/comparison_examples/spm_UKF.py +++ b/examples/scripts/comparison_examples/spm_UKF.py @@ -3,7 +3,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_XNES.py b/examples/scripts/comparison_examples/spm_XNES.py index 90d5aa1d0..2f3c26567 100644 --- a/examples/scripts/comparison_examples/spm_XNES.py +++ b/examples/scripts/comparison_examples/spm_XNES.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_descent.py b/examples/scripts/comparison_examples/spm_descent.py index f2b2c9adb..f423553cf 100644 --- a/examples/scripts/comparison_examples/spm_descent.py +++ b/examples/scripts/comparison_examples/spm_descent.py @@ -5,7 +5,7 @@ # Define model and use high-performant solver for sensitivities solver = pybamm.IDAKLUSolver() -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set, solver=solver) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_pso.py b/examples/scripts/comparison_examples/spm_pso.py index e5c305bd1..9f2e1be9d 100644 --- a/examples/scripts/comparison_examples/spm_pso.py +++ b/examples/scripts/comparison_examples/spm_pso.py @@ -3,7 +3,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/examples/scripts/comparison_examples/spm_scipymin.py b/examples/scripts/comparison_examples/spm_scipymin.py index 13a482aff..78037f101 100644 --- a/examples/scripts/comparison_examples/spm_scipymin.py +++ b/examples/scripts/comparison_examples/spm_scipymin.py @@ -4,7 +4,7 @@ import pybop # Define model -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") solver = pybamm.IDAKLUSolver() model = pybop.lithium_ion.SPM(parameter_set=parameter_set, solver=solver) diff --git a/examples/scripts/design_optimisation/maximising_energy.py b/examples/scripts/design_optimisation/maximising_energy.py index 23364664c..8fe9108d7 100644 --- a/examples/scripts/design_optimisation/maximising_energy.py +++ b/examples/scripts/design_optimisation/maximising_energy.py @@ -12,7 +12,7 @@ # separator width. # Define parameter set and additional parameters needed for the cost function -parameter_set = pybop.ParameterSet.pybamm("Chen2020", formation_concentrations=True) +parameter_set = pybop.ParameterSet("Chen2020", formation_concentrations=True) parameter_set.update( { "Electrolyte density [kg.m-3]": Parameter("Separator density [kg.m-3]"), diff --git a/examples/scripts/design_optimisation/maximising_power.py b/examples/scripts/design_optimisation/maximising_power.py index edfe998c0..1db1dbbb5 100644 --- a/examples/scripts/design_optimisation/maximising_power.py +++ b/examples/scripts/design_optimisation/maximising_power.py @@ -3,7 +3,7 @@ import pybop # Define parameter set and additional parameters needed for the cost function -parameter_set = pybop.ParameterSet.pybamm("Chen2020", formation_concentrations=True) +parameter_set = pybop.ParameterSet("Chen2020", formation_concentrations=True) parameter_set.update( { "Electrolyte density [kg.m-3]": Parameter("Separator density [kg.m-3]"), diff --git a/examples/scripts/getting_started/functional_parameters.py b/examples/scripts/getting_started/functional_parameters.py index a8ff75b6e..e9237454f 100644 --- a/examples/scripts/getting_started/functional_parameters.py +++ b/examples/scripts/getting_started/functional_parameters.py @@ -11,7 +11,7 @@ # Load parameter set -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") # Define a new function using pybamm parameters diff --git a/examples/scripts/getting_started/jax-solver-example.py b/examples/scripts/getting_started/jax-solver-example.py index b9d64273f..9a6e310b6 100644 --- a/examples/scripts/getting_started/jax-solver-example.py +++ b/examples/scripts/getting_started/jax-solver-example.py @@ -4,7 +4,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") # The Jaxified IDAKLU performs very well on high iteration # identification tasks, due to the just-in-time compilation diff --git a/examples/scripts/getting_started/linked_parameters.py b/examples/scripts/getting_started/linked_parameters.py index 9d4797bd0..6392de837 100644 --- a/examples/scripts/getting_started/linked_parameters.py +++ b/examples/scripts/getting_started/linked_parameters.py @@ -6,7 +6,7 @@ # design parameters which depend on the optimisation parameters. # Define parameter set and additional parameters needed for the cost function -parameter_set = pybop.ParameterSet.pybamm("Chen2020", formation_concentrations=True) +parameter_set = pybop.ParameterSet("Chen2020", formation_concentrations=True) parameter_set.update( { "Electrolyte density [kg.m-3]": Parameter("Separator density [kg.m-3]"), diff --git a/examples/scripts/getting_started/mcmc_example.py b/examples/scripts/getting_started/mcmc_example.py index 1b25a2d0d..f466de88e 100644 --- a/examples/scripts/getting_started/mcmc_example.py +++ b/examples/scripts/getting_started/mcmc_example.py @@ -5,7 +5,7 @@ # Parameter set and model definition solver = pybamm.IDAKLUSolver() -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") parameter_set.update( { "Negative electrode active material volume fraction": 0.63, diff --git a/examples/scripts/getting_started/multi_fitting.py b/examples/scripts/getting_started/multi_fitting.py index 9380974ab..b908bec37 100644 --- a/examples/scripts/getting_started/multi_fitting.py +++ b/examples/scripts/getting_started/multi_fitting.py @@ -3,7 +3,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Create initial SOC, experiment objects diff --git a/examples/scripts/getting_started/multi_start_optimisation.py b/examples/scripts/getting_started/multi_start_optimisation.py index 5e3f40596..85a07247d 100644 --- a/examples/scripts/getting_started/multi_start_optimisation.py +++ b/examples/scripts/getting_started/multi_start_optimisation.py @@ -5,7 +5,7 @@ # Define model and use the high-performant IDAKLU solver for sensitivities solver = pybamm.IDAKLUSolver(atol=1e-5, rtol=1e-5) -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set, solver=solver) # Fitting parameters diff --git a/examples/scripts/getting_started/spm_weighted_cost.py b/examples/scripts/getting_started/spm_weighted_cost.py index 6aa71d20d..3f77ce5b0 100644 --- a/examples/scripts/getting_started/spm_weighted_cost.py +++ b/examples/scripts/getting_started/spm_weighted_cost.py @@ -3,7 +3,7 @@ import pybop # Parameter set and model definition -parameter_set = pybop.ParameterSet.pybamm("Chen2020") +parameter_set = pybop.ParameterSet("Chen2020") model = pybop.lithium_ion.SPM(parameter_set=parameter_set) # Fitting parameters diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 1603045e6..b43ebfe42 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -128,7 +128,6 @@ def test_bpx_parameter_sets(self): params = pybop.ParameterSet() params.import_parameters(json_path="examples/parameters/example_BPX.json") - assert bpx_params.parameter_values == params.parameter_values @pytest.mark.unit def test_set_formation_concentrations(self): From 42da90a649272fe08c4bd2ec6b98fcfb7aa0c56b Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:42:41 +0000 Subject: [PATCH 10/14] Update test_parameter_sets.py --- tests/unit/test_parameter_sets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index b43ebfe42..9d2a029e0 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -129,6 +129,8 @@ def test_bpx_parameter_sets(self): params = pybop.ParameterSet() params.import_parameters(json_path="examples/parameters/example_BPX.json") + assert bpx_params.keys() == params.keys() + @pytest.mark.unit def test_set_formation_concentrations(self): parameter_set = pybop.ParameterSet("Chen2020", formation_concentrations=True) From a7e1e0d3a2d75a0f3d3481b015f78748a7510f0c Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:18:20 +0000 Subject: [PATCH 11/14] Add ParameterSet.to_pybamm --- pybop/models/base_model.py | 13 ++++++------ pybop/parameters/parameter_set.py | 35 ++++++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 8206d3bbe..938312aec 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -109,11 +109,7 @@ def __init__( self.eis = eis self._calculate_sensitivities = False - self._parameter_set = None - if parameter_set is not None: - if not isinstance(parameter_set, ParameterSet): - parameter_set = ParameterSet(parameter_set) - self._parameter_set = parameter_set().copy() + self._parameter_set = ParameterSet.to_pybamm(parameter_set) self.param_checker = check_params self.pybamm_model = None @@ -702,7 +698,10 @@ def predict( self._unprocessed_model.build_model() no_parameter_set = parameter_set is None - parameter_set = parameter_set or self._unprocessed_parameter_set.copy() + parameter_set = ( + ParameterSet.to_pybamm(parameter_set) + or self._unprocessed_parameter_set.copy() + ) if inputs is not None: inputs = self.parameters.verify(inputs) parameter_set.update(inputs) @@ -790,7 +789,7 @@ def check_params( """ inputs = self.parameters.verify(inputs) or {} - parameter_set = parameter_set or self._parameter_set + parameter_set = ParameterSet.to_pybamm(parameter_set) or self._parameter_set return self._check_params( inputs=inputs, diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index a8896b043..5bd47d1b8 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -52,7 +52,7 @@ def __init__( if json_path is not None: self.import_parameters(json_path) else: - self.parameter_values = self.convert_to_parameter_values(parameter_set) + self.parameter_values = self.to_pybamm(parameter_set) if self.parameter_values is not None: self.chemistry = self.parameter_values.get("chemistry", None) @@ -60,22 +60,6 @@ def __init__( if self.formation_concentrations: set_formation_concentrations(self.parameter_values) - def convert_to_parameter_values(self, parameter_set): - """ - Converts a parameter set to a PyBaMM ParameterValues object. - """ - if parameter_set is None: - return None - elif isinstance(parameter_set, str): - # Use class method - return self.pybamm(parameter_set) - elif isinstance(parameter_set, dict): - return ParameterValues(parameter_set) - elif isinstance(parameter_set, ParameterValues): - return parameter_set - else: - return parameter_set.parameter_values - def __call__(self): """ Return the parameter set as a pybamm.ParameterValues object. @@ -282,6 +266,23 @@ def pybamm(cls, name): return ParameterValues(name).copy() + @classmethod + def to_pybamm(cls, parameter_set): + """ + Converts a parameter set to a new PyBaMM ParameterValues object. + """ + if parameter_set is None: + return None + elif isinstance(parameter_set, str): + # Use class method + return cls.pybamm(parameter_set) + elif isinstance(parameter_set, dict): + return ParameterValues(parameter_set) + elif isinstance(parameter_set, ParameterValues): + return parameter_set.copy() + else: + return parameter_set.parameter_values.copy() + def set_formation_concentrations(parameter_set): """ From 6bfdaabf74c4ef0c04970ee872c7ca8be14f2732 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:53:21 +0000 Subject: [PATCH 12/14] Remove ParameterSet call --- .../scripts/comparison_examples/grouped_SPMe.py | 2 +- pybop/models/lithium_ion/basic_SPMe.py | 4 ++++ pybop/parameters/parameter_set.py | 14 -------------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/examples/scripts/comparison_examples/grouped_SPMe.py b/examples/scripts/comparison_examples/grouped_SPMe.py index ca509e0be..d67aeff0d 100644 --- a/examples/scripts/comparison_examples/grouped_SPMe.py +++ b/examples/scripts/comparison_examples/grouped_SPMe.py @@ -54,7 +54,7 @@ plot_dict.add_traces(dataset["Time [s]"], dataset["Voltage [V]"]) # Test model in the time domain -grouped_parameter_set = convert_physical_to_grouped_parameters(parameter_set()) +grouped_parameter_set = convert_physical_to_grouped_parameters(parameter_set) time_domain_grouped = pybop.lithium_ion.GroupedSPMe( parameter_set=grouped_parameter_set, options=model_options, diff --git a/pybop/models/lithium_ion/basic_SPMe.py b/pybop/models/lithium_ion/basic_SPMe.py index 33bfaf223..0bf8d119c 100644 --- a/pybop/models/lithium_ion/basic_SPMe.py +++ b/pybop/models/lithium_ion/basic_SPMe.py @@ -21,6 +21,8 @@ get_min_max_stoichiometries, ) +from pybop import ParameterSet + class BaseGroupedSPMe(pybamm_lithium_ion.BaseModel): """ @@ -491,6 +493,8 @@ def convert_physical_to_grouped_parameters(parameter_set): dict A dictionary of the grouped parameters. """ + parameter_set = ParameterSet.to_pybamm(parameter_set) + # Unpack physical parameters F = parameter_set["Faraday constant [C.mol-1]"] alpha_p = parameter_set["Positive electrode active material volume fraction"] diff --git a/pybop/parameters/parameter_set.py b/pybop/parameters/parameter_set.py index 5bd47d1b8..ecf9bf2c6 100644 --- a/pybop/parameters/parameter_set.py +++ b/pybop/parameters/parameter_set.py @@ -60,20 +60,6 @@ def __init__( if self.formation_concentrations: set_formation_concentrations(self.parameter_values) - def __call__(self): - """ - Return the parameter set as a pybamm.ParameterValues object. - - Returns - ------- - pybamm.ParameterValues - The parameter set for a PyBaMM model. - """ - if self.formation_concentrations: - set_formation_concentrations(self.parameter_values) - - return self.parameter_values - def __setitem__(self, key, value): self.parameter_values[key] = value From d0154d40f3b9a0360ae4c403d738ecea04582c01 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:53:36 +0000 Subject: [PATCH 13/14] Increase coverage --- tests/unit/test_parameter_sets.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_parameter_sets.py b/tests/unit/test_parameter_sets.py index 9d2a029e0..3d9465024 100644 --- a/tests/unit/test_parameter_sets.py +++ b/tests/unit/test_parameter_sets.py @@ -40,14 +40,14 @@ def params_dict(self): def test_parameter_set(self): # Tests parameter set creation and validation with pytest.raises(ValueError): - pybop.ParameterSet.pybamm("sChen2010s") + pybop.ParameterSet("sChen2010s") parameter_test = pybop.ParameterSet("Chen2020") np.testing.assert_allclose( parameter_test["Negative electrode active material volume fraction"], 0.75 ) - parameter_test = pybop.ParameterSet.pybamm("Chen2020") + parameter_test = pybop.ParameterSet("Chen2020") np.testing.assert_allclose( parameter_test["Negative electrode active material volume fraction"], 0.75 ) @@ -123,11 +123,14 @@ def test_ecm_parameter_sets(self, params_dict): def test_bpx_parameter_sets(self): # Test importing a BPX json file bpx_params = pybop.ParameterSet( - json_path="examples/parameters/example_BPX.json" + json_path="examples/parameters/example_BPX.json", + formation_concentrations=True, ) - params = pybop.ParameterSet() - params.import_parameters(json_path="examples/parameters/example_BPX.json") + params = pybop.ParameterSet(formation_concentrations=True) + params.import_parameters( + json_path="examples/parameters/example_BPX.json", + ) assert bpx_params.keys() == params.keys() @@ -144,7 +147,7 @@ def test_set_formation_concentrations(self): @pytest.mark.unit def test_evaluate_symbol(self): - parameter_set = pybop.ParameterSet.pybamm("Chen2020") + parameter_set = pybop.ParameterSet("Chen2020") porosity = parameter_set["Positive electrode porosity"] assert isinstance(porosity, float) From 68f9ddc6feb6c8a043b852e9c211a4f4729505a6 Mon Sep 17 00:00:00 2001 From: NicolaCourtier <45851982+NicolaCourtier@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:00:41 +0000 Subject: [PATCH 14/14] Undo one change --- pybop/models/base_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybop/models/base_model.py b/pybop/models/base_model.py index 938312aec..57b4cd506 100644 --- a/pybop/models/base_model.py +++ b/pybop/models/base_model.py @@ -789,7 +789,7 @@ def check_params( """ inputs = self.parameters.verify(inputs) or {} - parameter_set = ParameterSet.to_pybamm(parameter_set) or self._parameter_set + parameter_set = parameter_set or self._parameter_set return self._check_params( inputs=inputs,