From ac6c45021a9560ac5b5b4053fb497ba7e476987d Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Tue, 27 Aug 2024 16:37:28 -0700 Subject: [PATCH] Surface temperature model (#4203) * add surface temperature equal to ambient temperature * #4022 surface model works * update temperature comparison script * #4022 update tests and example, rename parameters * fix plot_thermal_components * fix unit tests * #4022 fix lead acid thermal tests * #4022 fix example * coverage * fix test * style * Moving missed files * Rob's suggestion --------- Co-authored-by: Eric G. Kratz Co-authored-by: kratman --- .../scripts/compare_surface_temperature.py | 61 +++++++++++++++++++ src/pybamm/CITATIONS.bib | 10 +++ .../full_battery_models/base_battery_model.py | 30 +++++---- .../full_battery_models/lead_acid/full.py | 1 + .../full_battery_models/lead_acid/loqs.py | 1 + .../lithium_ion/base_lithium_ion_model.py | 1 + .../models/submodels/thermal/__init__.py | 3 +- .../models/submodels/thermal/isothermal.py | 4 +- src/pybamm/models/submodels/thermal/lumped.py | 10 +-- .../pouch_cell_1D_current_collectors.py | 16 ++--- .../pouch_cell_2D_current_collectors.py | 14 ++--- .../submodels/thermal/pouch_cell/x_full.py | 12 ++-- .../submodels/thermal/surface/__init__.py | 2 + .../submodels/thermal/surface/ambient.py | 33 ++++++++++ .../submodels/thermal/surface/lumped.py | 51 ++++++++++++++++ .../plotting/plot_thermal_components.py | 6 +- .../test_lithium_ion/test_thermal_models.py | 29 +++++++++ .../test_base_battery_model.py | 15 ++--- .../base_lithium_ion_tests.py | 4 ++ 19 files changed, 253 insertions(+), 50 deletions(-) create mode 100644 examples/scripts/compare_surface_temperature.py create mode 100644 src/pybamm/models/submodels/thermal/surface/__init__.py create mode 100644 src/pybamm/models/submodels/thermal/surface/ambient.py create mode 100644 src/pybamm/models/submodels/thermal/surface/lumped.py diff --git a/examples/scripts/compare_surface_temperature.py b/examples/scripts/compare_surface_temperature.py new file mode 100644 index 0000000000..24ccfc5dfc --- /dev/null +++ b/examples/scripts/compare_surface_temperature.py @@ -0,0 +1,61 @@ +# +# Compare lithium-ion battery models +# +import pybamm + +pybamm.set_logging_level("INFO") + +# load models +models = [ + pybamm.lithium_ion.SPMe( + {"thermal": "lumped", "surface temperature": "ambient"}, + name="ambient surface temperature", + ), + pybamm.lithium_ion.SPMe( + {"thermal": "lumped", "surface temperature": "lumped"}, + name="lumped surface temperature", + ), +] + +experiment = pybamm.Experiment( + [ + "Discharge at 1C until 2.5V", + "Rest for 1 hour", + ] +) + +parameter_values = pybamm.ParameterValues("Chen2020") +parameter_values.update( + { + "Casing heat capacity [J.K-1]": 30, + "Environment thermal resistance [K.W-1]": 10, + }, + check_already_exists=False, +) + +# create and run simulations +sols = [] +for model in models: + model.variables["Bulk temperature [°C]"] = ( + model.variables["Volume-averaged cell temperature [K]"] - 273.15 + ) + model.variables["Surface temperature [°C]"] = ( + model.variables["Surface temperature [K]"] - 273.15 + ) + sim = pybamm.Simulation( + model, parameter_values=parameter_values, experiment=experiment + ) + sol = sim.solve([0, 3600]) + sols.append(sol) + +# plot +pybamm.dynamic_plot( + sols, + [ + "Voltage [V]", + "Bulk temperature [°C]", + "Surface temperature [°C]", + "Surface total cooling [W]", + "Environment total cooling [W]", + ], +) diff --git a/src/pybamm/CITATIONS.bib b/src/pybamm/CITATIONS.bib index 8fb9c6dc98..3d853738b4 100644 --- a/src/pybamm/CITATIONS.bib +++ b/src/pybamm/CITATIONS.bib @@ -252,6 +252,16 @@ @article{Lain2019 doi = {10.3390/batteries5040064}, } +@article{lin2014lumped, + title={A lumped-parameter electro-thermal model for cylindrical batteries}, + author={Lin, Xinfan and Perez, Hector E and Mohan, Shankar and Siegel, Jason B and Stefanopoulou, Anna G and Ding, Yi and Castanier, Matthew P}, + journal={Journal of Power Sources}, + volume={257}, + pages={1--11}, + year={2014}, + publisher={Elsevier} +} + @article{Marquis2019, title = {{An asymptotic derivation of a single particle model with electrolyte}}, author = {Marquis, Scott G. and Sulzer, Valentin and Timms, Robert and Please, Colin P. and Chapman, S. Jon}, diff --git a/src/pybamm/models/full_battery_models/base_battery_model.py b/src/pybamm/models/full_battery_models/base_battery_model.py index 8a2e443338..ccda594b14 100644 --- a/src/pybamm/models/full_battery_models/base_battery_model.py +++ b/src/pybamm/models/full_battery_models/base_battery_model.py @@ -194,6 +194,11 @@ class BatteryModelOptions(pybamm.FuzzyDict): * "surface form" : str Whether to use the surface formulation of the problem. Can be "false" (default), "differential" or "algebraic". + * "surface temperature" : str + Sets the surface temperature model to use. Can be "ambient" (default), + which sets the surface temperature equal to the ambient temperature, or + "lumped", which adds an ODE for the surface temperature (e.g. to model + internal heating of a thermal chamber). * "thermal" : str Sets the thermal model to use. Can be "isothermal" (default), "lumped", "x-lumped", or "x-full". The 'cell geometry' option must be set to @@ -278,7 +283,6 @@ def __init__(self, extra_options): ], "particle": [ "Fickian diffusion", - "fast diffusion", "uniform profile", "quadratic profile", "quartic profile", @@ -304,6 +308,7 @@ def __init__(self, extra_options): "SEI porosity change": ["false", "true"], "stress-induced diffusion": ["false", "true"], "surface form": ["false", "differential", "algebraic"], + "surface temperature": ["ambient", "lumped"], "thermal": ["isothermal", "lumped", "x-lumped", "x-full"], "total interfacial current density as a state": ["false", "true"], "transport efficiency": [ @@ -554,16 +559,6 @@ def __init__(self, extra_options): ) # Renamed options - if options["particle"] == "fast diffusion": - raise pybamm.OptionError( - "The 'fast diffusion' option has been renamed. " - "Use 'uniform profile' instead." - ) - if options["SEI porosity change"] in [True, False]: - raise pybamm.OptionError( - "SEI porosity change must now be given in string format " - "('true' or 'false')" - ) if options["working electrode"] == "negative": raise pybamm.OptionError( "The 'negative' working electrode option has been removed because " @@ -633,6 +628,12 @@ def __init__(self, extra_options): "be 'none': 'particle mechanics', 'loss of active material'" ) + if options["surface temperature"] == "lumped": + if options["thermal"] not in ["isothermal", "lumped"]: + raise pybamm.OptionError( + "lumped surface temperature model only compatible with isothermal " + "or lumped thermal model" + ) if "true" in options["SEI on cracks"]: sei_on_cr = options["SEI on cracks"] p_mechanics = options["particle mechanics"] @@ -1265,6 +1266,13 @@ def set_thermal_submodel(self): self.param, self.options, x_average ) + def set_surface_temperature_submodel(self): + if self.options["surface temperature"] == "ambient": + submodel = pybamm.thermal.surface.Ambient + elif self.options["surface temperature"] == "lumped": + submodel = pybamm.thermal.surface.Lumped + self.submodels["surface temperature"] = submodel(self.param, self.options) + def set_current_collector_submodel(self): if self.options["current collector"] in ["uniform"]: submodel = pybamm.current_collector.Uniform(self.param) diff --git a/src/pybamm/models/full_battery_models/lead_acid/full.py b/src/pybamm/models/full_battery_models/lead_acid/full.py index b5b561e6dd..f873c779b6 100644 --- a/src/pybamm/models/full_battery_models/lead_acid/full.py +++ b/src/pybamm/models/full_battery_models/lead_acid/full.py @@ -27,6 +27,7 @@ def __init__(self, options=None, name="Full model", build=True): self.set_electrolyte_submodel() self.set_solid_submodel() self.set_thermal_submodel() + self.set_surface_temperature_submodel() self.set_side_reaction_submodels() self.set_current_collector_submodel() self.set_sei_submodel() diff --git a/src/pybamm/models/full_battery_models/lead_acid/loqs.py b/src/pybamm/models/full_battery_models/lead_acid/loqs.py index c63c9cd11b..76a4142a08 100644 --- a/src/pybamm/models/full_battery_models/lead_acid/loqs.py +++ b/src/pybamm/models/full_battery_models/lead_acid/loqs.py @@ -27,6 +27,7 @@ def __init__(self, options=None, name="LOQS model", build=True): self.set_electrolyte_submodel() self.set_electrode_submodels() self.set_thermal_submodel() + self.set_surface_temperature_submodel() self.set_side_reaction_submodels() self.set_current_collector_submodel() self.set_sei_submodel() diff --git a/src/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py b/src/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py index 6db56b74c4..dfe2512f6e 100644 --- a/src/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py +++ b/src/pybamm/models/full_battery_models/lithium_ion/base_lithium_ion_model.py @@ -48,6 +48,7 @@ def set_submodels(self, build): self.set_electrolyte_concentration_submodel() self.set_electrolyte_potential_submodel() self.set_thermal_submodel() + self.set_surface_temperature_submodel() self.set_current_collector_submodel() self.set_sei_submodel() self.set_sei_on_cracks_submodel() diff --git a/src/pybamm/models/submodels/thermal/__init__.py b/src/pybamm/models/submodels/thermal/__init__.py index cc8f769f36..90bd14bc39 100644 --- a/src/pybamm/models/submodels/thermal/__init__.py +++ b/src/pybamm/models/submodels/thermal/__init__.py @@ -2,5 +2,6 @@ from .isothermal import Isothermal from .lumped import Lumped from . import pouch_cell +from . import surface -__all__ = ['base_thermal', 'isothermal', 'lumped', 'pouch_cell'] +__all__ = ["base_thermal", "isothermal", "lumped", "pouch_cell"] diff --git a/src/pybamm/models/submodels/thermal/isothermal.py b/src/pybamm/models/submodels/thermal/isothermal.py index edcd47bbdf..4b729f1294 100644 --- a/src/pybamm/models/submodels/thermal/isothermal.py +++ b/src/pybamm/models/submodels/thermal/isothermal.py @@ -73,8 +73,8 @@ def get_coupled_variables(self, variables): "Total heating [W]", "Negative current collector Ohmic heating [W.m-3]", "Positive current collector Ohmic heating [W.m-3]", - "Lumped total cooling [W.m-3]", - "Lumped total cooling [W]", + "Surface total cooling [W.m-3]", + "Surface total cooling [W]", ]: # All variables are zero variables.update({var: zero}) diff --git a/src/pybamm/models/submodels/thermal/lumped.py b/src/pybamm/models/submodels/thermal/lumped.py index 76af2904bc..6915a3b180 100644 --- a/src/pybamm/models/submodels/thermal/lumped.py +++ b/src/pybamm/models/submodels/thermal/lumped.py @@ -49,9 +49,9 @@ def get_coupled_variables(self, variables): # Newton cooling, accounting for surface area to volume ratio T_vol_av = variables["Volume-averaged cell temperature [K]"] - T_amb = variables["Volume-averaged ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] V = variables["Cell thermal volume [m3]"] - Q_cool_W = -self.param.h_total * (T_vol_av - T_amb) * self.param.A_cooling + Q_cool_W = -self.param.h_total * (T_vol_av - T_surf) * self.param.A_cooling Q_cool_vol_av = Q_cool_W / V # Contact resistance heating Q_cr @@ -67,8 +67,8 @@ def get_coupled_variables(self, variables): variables.update( { # Lumped cooling - "Lumped total cooling [W.m-3]": Q_cool_vol_av, - "Lumped total cooling [W]": Q_cool_W, + "Surface total cooling [W.m-3]": Q_cool_vol_av, + "Surface total cooling [W]": Q_cool_W, # Contact resistance "Lumped contact resistance heating [W.m-3]": Q_cr_vol_av, "Lumped contact resistance heating [W]": Q_cr_W, @@ -79,7 +79,7 @@ def get_coupled_variables(self, variables): def set_rhs(self, variables): T_vol_av = variables["Volume-averaged cell temperature [K]"] Q_vol_av = variables["Volume-averaged total heating [W.m-3]"] - Q_cool_vol_av = variables["Lumped total cooling [W.m-3]"] + Q_cool_vol_av = variables["Surface total cooling [W.m-3]"] Q_cr_vol_av = variables["Lumped contact resistance heating [W.m-3]"] rho_c_p_eff_av = variables[ "Volume-averaged effective heat capacity [J.K-1.m-3]" diff --git a/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py b/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py index a4908c6f5d..fb026a9a0a 100644 --- a/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py +++ b/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py @@ -54,7 +54,7 @@ def get_coupled_variables(self, variables): def set_rhs(self, variables): T_av = variables["X-averaged cell temperature [K]"] Q_av = variables["X-averaged total heating [W.m-3]"] - T_amb = variables["Ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] y = pybamm.standard_spatial_vars.y z = pybamm.standard_spatial_vars.z @@ -64,13 +64,13 @@ def set_rhs(self, variables): cell_volume = self.param.L * self.param.L_y * self.param.L_z Q_yz_surface = ( -(self.param.n.h_cc(y, z) + self.param.p.h_cc(y, z)) - * (T_av - T_amb) + * (T_av - T_surf) * yz_surface_area / cell_volume ) Q_edge = ( -(self.param.h_edge(0, z) + self.param.h_edge(self.param.L_y, z)) - * (T_av - T_amb) + * (T_av - T_surf) * edge_area / cell_volume ) @@ -87,7 +87,7 @@ def set_rhs(self, variables): def set_boundary_conditions(self, variables): param = self.param - T_amb = variables["Ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] T_av = variables["X-averaged cell temperature [K]"] # Find tab locations (top vs bottom) @@ -118,10 +118,10 @@ def set_boundary_conditions(self, variables): # Calculate heat fluxes weighted by area # Note: can't do y-average of h_edge here since y isn't meshed. Evaluate at # midpoint. - q_tab_n = -param.n.h_tab * (T_av - T_amb) - q_tab_p = -param.p.h_tab * (T_av - T_amb) - q_edge_top = -param.h_edge(L_y / 2, L_z) * (T_av - T_amb) - q_edge_bottom = -param.h_edge(L_y / 2, 0) * (T_av - T_amb) + q_tab_n = -param.n.h_tab * (T_av - T_surf) + q_tab_p = -param.p.h_tab * (T_av - T_surf) + q_edge_top = -param.h_edge(L_y / 2, L_z) * (T_av - T_surf) + q_edge_bottom = -param.h_edge(L_y / 2, 0) * (T_av - T_surf) q_top = ( q_tab_n * neg_tab_area * neg_tab_top_bool + q_tab_p * pos_tab_area * pos_tab_top_bool diff --git a/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py b/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py index 7955ee4c38..b2d69ff1bb 100644 --- a/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py +++ b/src/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py @@ -54,15 +54,15 @@ def get_coupled_variables(self, variables): def set_rhs(self, variables): T_av = variables["X-averaged cell temperature [K]"] Q_av = variables["X-averaged total heating [W.m-3]"] - T_amb = variables["Ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] y = pybamm.standard_spatial_vars.y z = pybamm.standard_spatial_vars.z # Calculate cooling Q_yz_surface_W_per_m2 = -(self.param.n.h_cc(y, z) + self.param.p.h_cc(y, z)) * ( - T_av - T_amb + T_av - T_surf ) - Q_edge_W_per_m2 = -self.param.h_edge(y, z) * (T_av - T_amb) + Q_edge_W_per_m2 = -self.param.h_edge(y, z) * (T_av - T_surf) # Account for surface area to volume ratio of pouch cell in surface cooling # term @@ -98,14 +98,14 @@ def set_rhs(self, variables): def set_boundary_conditions(self, variables): T_av = variables["X-averaged cell temperature [K]"] - T_amb = variables["Ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] y = pybamm.standard_spatial_vars.y z = pybamm.standard_spatial_vars.z # Calculate heat fluxes - q_tab_n = -self.param.n.h_tab * (T_av - T_amb) - q_tab_p = -self.param.p.h_tab * (T_av - T_amb) - q_edge = -self.param.h_edge(y, z) * (T_av - T_amb) + q_tab_n = -self.param.n.h_tab * (T_av - T_surf) + q_tab_p = -self.param.p.h_tab * (T_av - T_surf) + q_edge = -self.param.h_edge(y, z) * (T_av - T_surf) # Subtract the edge cooling from the tab portion so as to not double count # Note: tab cooling is also only applied on the current collector hence diff --git a/src/pybamm/models/submodels/thermal/pouch_cell/x_full.py b/src/pybamm/models/submodels/thermal/pouch_cell/x_full.py index f4aa07c563..630ce94b01 100644 --- a/src/pybamm/models/submodels/thermal/pouch_cell/x_full.py +++ b/src/pybamm/models/submodels/thermal/pouch_cell/x_full.py @@ -79,7 +79,7 @@ def set_rhs(self, variables): Q = variables["Total heating [W.m-3]"] Q_cn = variables["Negative current collector Ohmic heating [W.m-3]"] Q_cp = variables["Positive current collector Ohmic heating [W.m-3]"] - T_amb = variables["Ambient temperature [K]"] + T_surf = variables["Surface temperature [K]"] y = pybamm.standard_spatial_vars.y z = pybamm.standard_spatial_vars.z @@ -140,28 +140,28 @@ def set_rhs(self, variables): ( pybamm.boundary_value(lambda_n, "left") * pybamm.boundary_gradient(T_n, "left") - - h_cn * (T_cn - T_amb) + - h_cn * (T_cn - T_surf) ) / L_cn + Q_cn - + cooling_coefficient_cn * (T_cn - T_amb) + + cooling_coefficient_cn * (T_cn - T_surf) ) / self.param.n.rho_c_p_cc(T_cn), T: ( pybamm.div(lambda_ * pybamm.grad(T)) + Q - + cooling_coefficient * (T - T_amb) + + cooling_coefficient * (T - T_surf) ) / rho_c_p, T_cp: ( ( -pybamm.boundary_value(lambda_p, "right") * pybamm.boundary_gradient(T_p, "right") - - h_cp * (T_cp - T_amb) + - h_cp * (T_cp - T_surf) ) / L_cp + Q_cp - + cooling_coefficient_cp * (T_cp - T_amb) + + cooling_coefficient_cp * (T_cp - T_surf) ) / self.param.p.rho_c_p_cc(T_cp), } diff --git a/src/pybamm/models/submodels/thermal/surface/__init__.py b/src/pybamm/models/submodels/thermal/surface/__init__.py new file mode 100644 index 0000000000..dece4b44ae --- /dev/null +++ b/src/pybamm/models/submodels/thermal/surface/__init__.py @@ -0,0 +1,2 @@ +from .ambient import Ambient +from .lumped import Lumped diff --git a/src/pybamm/models/submodels/thermal/surface/ambient.py b/src/pybamm/models/submodels/thermal/surface/ambient.py new file mode 100644 index 0000000000..a28591af30 --- /dev/null +++ b/src/pybamm/models/submodels/thermal/surface/ambient.py @@ -0,0 +1,33 @@ +# +# Class for ambient surface temperature submodel +import pybamm + + +class Ambient(pybamm.BaseSubModel): + """ + Class for setting surface temperature equal to ambient temperature. + + Parameters + ---------- + param : parameter class + The parameters to use for this submodel + options : dict, optional + A dictionary of options to be passed to the model. + + """ + + def __init__(self, param, options=None): + super().__init__(param, options=options) + + def get_coupled_variables(self, variables): + T_amb = variables["Ambient temperature [K]"] + T_amb_av = variables["Volume-averaged ambient temperature [K]"] + + variables.update( + { + "Surface temperature [K]": T_amb, + "Volume-averaged surface temperature [K]": T_amb_av, + "Environment total cooling [W]": pybamm.Scalar(0), + } + ) + return variables diff --git a/src/pybamm/models/submodels/thermal/surface/lumped.py b/src/pybamm/models/submodels/thermal/surface/lumped.py new file mode 100644 index 0000000000..dc481947e8 --- /dev/null +++ b/src/pybamm/models/submodels/thermal/surface/lumped.py @@ -0,0 +1,51 @@ +# +# Class for ambient surface temperature submodel +import pybamm + + +class Lumped(pybamm.BaseSubModel): + """ + Class for the lumped surface temperature submodel, which adds an ODE for the + surface temperature. + + Parameters + ---------- + param : parameter class + The parameters to use for this submodel + options : dict, optional + A dictionary of options to be passed to the model. + + """ + + def __init__(self, param, options=None): + super().__init__(param, options=options) + pybamm.citations.register("lin2014lumped") + + def get_fundamental_variables(self): + T_surf = pybamm.Variable("Surface temperature [K]") + variables = {"Surface temperature [K]": T_surf} + + return variables + + def get_coupled_variables(self, variables): + T_surf = variables["Surface temperature [K]"] + T_amb = variables["Ambient temperature [K]"] + R_env = pybamm.Parameter("Environment thermal resistance [K.W-1]") + Q_cool_env = -(T_surf - T_amb) / R_env + variables["Environment total cooling [W]"] = Q_cool_env + return variables + + def set_rhs(self, variables): + T_surf = variables["Surface temperature [K]"] + + Q_cool_bulk = variables["Surface total cooling [W]"] + Q_heat_bulk = -Q_cool_bulk + + Q_cool_env = variables["Environment total cooling [W]"] + rho_c_p_case = pybamm.Parameter("Casing heat capacity [J.K-1]") + + self.rhs[T_surf] = (Q_heat_bulk + Q_cool_env) / rho_c_p_case + + def set_initial_conditions(self, variables): + T_surf = variables["Surface temperature [K]"] + self.initial_conditions = {T_surf: self.param.T_init} diff --git a/src/pybamm/plotting/plot_thermal_components.py b/src/pybamm/plotting/plot_thermal_components.py index 8cb99a454d..e45a08112c 100644 --- a/src/pybamm/plotting/plot_thermal_components.py +++ b/src/pybamm/plotting/plot_thermal_components.py @@ -55,7 +55,7 @@ def plot_thermal_components( volume = solution["Cell thermal volume [m3]"].entries heating_sources = [ - "Lumped total cooling", + "Surface total cooling", "Ohmic heating", "Irreversible electrochemical heating", "Reversible heating", @@ -77,9 +77,9 @@ def plot_thermal_components( # Plot # Initialise total_heat = 0 - bottom_heat = heats["Lumped total cooling"] + bottom_heat = heats["Surface total cooling"] total_cumul_heat = 0 - bottom_cumul_heat = cumul_heats["Lumped total cooling"] + bottom_cumul_heat = cumul_heats["Surface total cooling"] # Plot components for name in heating_sources: top_heat = bottom_heat + abs(heats[name]) diff --git a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_thermal_models.py b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_thermal_models.py index 603f64d716..ac58f40bb4 100644 --- a/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_thermal_models.py +++ b/tests/integration/test_models/test_full_battery_models/test_lithium_ion/test_thermal_models.py @@ -101,6 +101,35 @@ def err(a, b): assert 1e-5 > err(solutions["SPMe 1+1D"], solutions["SPMe 2+1D"]) + def test_surface_temperature_models(self): + models = { + option: pybamm.lithium_ion.SPM( + {"thermal": "lumped", "surface temperature": option} + ) + for option in ["lumped", "ambient"] + } + + parameter_values = pybamm.ParameterValues("Chen2020") + parameter_values.update( + { + "Casing heat capacity [J.K-1]": 30, + "Environment thermal resistance [K.W-1]": 10, + }, + check_already_exists=False, + ) + + sols = {} + for name, model in models.items(): + sim = pybamm.Simulation(model, parameter_values=parameter_values) + sol = sim.solve([0, 3600]) + sols[name] = sol + + for var in ["Volume-averaged cell temperature [K]", "Surface temperature [K]"]: + # ignore first entry as it is the initial condition + T_ambient_model = sols["ambient"][var].entries[1:] + T_lumped_model = sols["lumped"][var].entries[1:] + np.testing.assert_array_less(T_ambient_model, T_lumped_model) + def test_lumped_contact_resistance(self): # Test that the heating with contact resistance is greater than without diff --git a/tests/unit/test_models/test_full_battery_models/test_base_battery_model.py b/tests/unit/test_models/test_full_battery_models/test_base_battery_model.py index 6ee38faf9a..033dcf5345 100644 --- a/tests/unit/test_models/test_full_battery_models/test_base_battery_model.py +++ b/tests/unit/test_models/test_full_battery_models/test_base_battery_model.py @@ -36,7 +36,7 @@ 'number of MSMR reactions': 'none' (possible: ['none']) 'open-circuit potential': 'single' (possible: ['single', 'current sigmoid', 'MSMR', 'Wycisk']) 'operating mode': 'current' (possible: ['current', 'voltage', 'power', 'differential power', 'explicit power', 'resistance', 'differential resistance', 'explicit resistance', 'CCCV']) -'particle': 'Fickian diffusion' (possible: ['Fickian diffusion', 'fast diffusion', 'uniform profile', 'quadratic profile', 'quartic profile', 'MSMR']) +'particle': 'Fickian diffusion' (possible: ['Fickian diffusion', 'uniform profile', 'quadratic profile', 'quartic profile', 'MSMR']) 'particle mechanics': 'swelling only' (possible: ['none', 'swelling only', 'swelling and cracking']) 'particle phases': '1' (possible: ['1', '2']) 'particle shape': 'spherical' (possible: ['spherical', 'no particles']) @@ -47,6 +47,7 @@ 'SEI porosity change': 'false' (possible: ['false', 'true']) 'stress-induced diffusion': 'true' (possible: ['false', 'true']) 'surface form': 'differential' (possible: ['false', 'differential', 'algebraic']) +'surface temperature': 'ambient' (possible: ['ambient', 'lumped']) 'thermal': 'x-full' (possible: ['isothermal', 'lumped', 'x-lumped', 'x-full']) 'total interfacial current density as a state': 'false' (possible: ['false', 'true']) 'transport efficiency': 'Bruggeman' (possible: ['Bruggeman', 'ordered packing', 'hyperbola of revolution', 'overlapping spheres', 'tortuosity factor', 'random overlapping cylinders', 'heterogeneous catalyst', 'cation-exchange membrane']) @@ -211,8 +212,6 @@ def test_options(self): pybamm.BaseBatteryModel({"convection": "full transverse"}) with self.assertRaisesRegex(pybamm.OptionError, "particle"): pybamm.BaseBatteryModel({"particle": "bad particle"}) - with self.assertRaisesRegex(pybamm.OptionError, "The 'fast diffusion'"): - pybamm.BaseBatteryModel({"particle": "fast diffusion"}) with self.assertRaisesRegex(pybamm.OptionError, "working electrode"): pybamm.BaseBatteryModel({"working electrode": "bad working electrode"}) with self.assertRaisesRegex(pybamm.OptionError, "The 'negative' working"): @@ -233,10 +232,6 @@ def test_options(self): pybamm.BaseBatteryModel({"SEI film resistance": "bad SEI film resistance"}) with self.assertRaisesRegex(pybamm.OptionError, "SEI porosity change"): pybamm.BaseBatteryModel({"SEI porosity change": "bad SEI porosity change"}) - with self.assertRaisesRegex( - pybamm.OptionError, "SEI porosity change must now be given in string format" - ): - pybamm.BaseBatteryModel({"SEI porosity change": True}) # changing defaults based on other options model = pybamm.BaseBatteryModel() self.assertEqual(model.options["SEI film resistance"], "none") @@ -387,6 +382,12 @@ def test_options(self): } ) + # surface thermal model + with self.assertRaisesRegex(pybamm.OptionError, "surface temperature"): + pybamm.BaseBatteryModel( + {"surface temperature": "lumped", "thermal": "x-full"} + ) + # phases with self.assertRaisesRegex(pybamm.OptionError, "multiple particle phases"): pybamm.BaseBatteryModel({"particle phases": "2", "surface form": "false"}) diff --git a/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py b/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py index c8a3f6b509..9c093c0c65 100644 --- a/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py +++ b/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_tests.py @@ -31,6 +31,10 @@ def test_well_posed_lumped_thermal_model_1D(self): options = {"thermal": "lumped"} self.check_well_posedness(options) + def test_well_posed_lumped_thermal_model_surface_temperature(self): + options = {"thermal": "lumped", "surface temperature": "lumped"} + self.check_well_posedness(options) + def test_well_posed_x_full_thermal_model(self): options = {"thermal": "x-full"} self.check_well_posedness(options)