From e06d5b95d19a0de74ade096a9133101753daa674 Mon Sep 17 00:00:00 2001 From: Alexander Bills Date: Fri, 17 Mar 2023 14:15:30 -0400 Subject: [PATCH 01/43] fix --- .../lithium_ion/electrode_soh.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py index a94b0c11eb..c08fc28c29 100644 --- a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py +++ b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py @@ -246,14 +246,19 @@ def solve(self, inputs): sol_dict = {key: sol[key].data[0] for key in sol.all_models[0].variables.keys()} # Calculate theoretical energy - x_0 = sol_dict["x_0"] - y_0 = sol_dict["y_0"] - x_100 = sol_dict["x_100"] - y_100 = sol_dict["y_100"] - energy = pybamm.lithium_ion.electrode_soh.theoretical_energy_integral( - self.parameter_values, x_100, x_0, y_100, y_0 - ) - sol_dict.update({"Maximum theoretical energy [W.h]": energy}) + try: + x_0 = sol_dict["x_0"] + y_0 = sol_dict["y_0"] + x_100 = sol_dict["x_100"] + y_100 = sol_dict["y_100"] + energy = pybamm.lithium_ion.electrode_soh.theoretical_energy_integral( + self.parameter_values, x_100, x_0, y_100, y_0 + ) + sol_dict.update({"Maximum theoretical energy [W.h]": energy}) + except pybamm.ValueError as my_err: + warnings.warn("couldn't calculate theoretical energy") + + return sol_dict def _set_up_solve(self, inputs): From 688c9a07e9f86842bc96776d6b3d60c6bbb1a057 Mon Sep 17 00:00:00 2001 From: Alexander Bills Date: Fri, 17 Mar 2023 14:38:48 -0400 Subject: [PATCH 02/43] fix exception --- pybamm/models/full_battery_models/lithium_ion/electrode_soh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py index c08fc28c29..83d0b85075 100644 --- a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py +++ b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py @@ -255,7 +255,7 @@ def solve(self, inputs): self.parameter_values, x_100, x_0, y_100, y_0 ) sol_dict.update({"Maximum theoretical energy [W.h]": energy}) - except pybamm.ValueError as my_err: + except: warnings.warn("couldn't calculate theoretical energy") From 6dbe8d622abdcfccffb043a68ba05c5526c66eb9 Mon Sep 17 00:00:00 2001 From: smitasahu2 Date: Wed, 29 Mar 2023 12:01:51 +0100 Subject: [PATCH 03/43] added a Newfile --- pybamm/models/Newfile.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pybamm/models/Newfile.py diff --git a/pybamm/models/Newfile.py b/pybamm/models/Newfile.py new file mode 100644 index 0000000000..e69de29bb2 From 69e6ba6e14bd3a9a5a123c4efcb2245be62f9c11 Mon Sep 17 00:00:00 2001 From: Alexander Bills Date: Wed, 29 Mar 2023 07:12:27 -0400 Subject: [PATCH 04/43] pseudo --- pybamm/models/submodels/thermal/base_thermal.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 54c4a1b467..124a258a2e 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -145,6 +145,14 @@ def _get_standard_coupled_variables(self, variables): Q_rev_n, pybamm.FullBroadcast(0, "separator", "current collector"), Q_rev_p ) + # Heat of mixing + if self.options.electrode_types["negative"] == "planar" or not self.options["heat of mixing"]: + # make 0 + asdfasfd + else: + # write equation + asdfasdf + # Total heating Q = Q_ohm + Q_rxn + Q_rev From beb5205d623670958f2218caa6a20417258cd0d4 Mon Sep 17 00:00:00 2001 From: Afgr1087 Date: Wed, 29 Mar 2023 12:25:42 +0100 Subject: [PATCH 05/43] #1778 add heat of mixing option --- pybamm/models/full_battery_models/base_battery_model.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index e82f3d5868..91336a64ab 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -199,6 +199,7 @@ def __init__(self, extra_options): "composite", "integrated", ], + "heat of mixing": ["false", "true"], "hydrolysis": ["false", "true"], "intercalation kinetics": [ "symmetric Butler-Volmer", @@ -414,6 +415,11 @@ def __init__(self, extra_options): # Options not yet compatible with particle-size distributions if options["particle size"] == "distribution": + if options["heat of mixing"] != "false": + raise NotImplementedError( + "Heat of mixing submodels do not yet support particle-size " + "distributions." + ) if options["lithium plating"] != "none": raise NotImplementedError( "Lithium plating submodels do not yet support particle-size " From 161dc82efd634208deb335d7e461d26c0a1b42e9 Mon Sep 17 00:00:00 2001 From: Afgr1087 Date: Wed, 29 Mar 2023 12:38:33 +0100 Subject: [PATCH 06/43] #1778 fixed indentation --- pybamm/models/full_battery_models/base_battery_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index 91336a64ab..03246b4478 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -199,7 +199,7 @@ def __init__(self, extra_options): "composite", "integrated", ], - "heat of mixing": ["false", "true"], + "heat of mixing": ["false", "true"], "hydrolysis": ["false", "true"], "intercalation kinetics": [ "symmetric Butler-Volmer", @@ -415,7 +415,7 @@ def __init__(self, extra_options): # Options not yet compatible with particle-size distributions if options["particle size"] == "distribution": - if options["heat of mixing"] != "false": + if options["heat of mixing"] != "false": raise NotImplementedError( "Heat of mixing submodels do not yet support particle-size " "distributions." From 93777daa986bc850143bb1bdcf047191c3706da3 Mon Sep 17 00:00:00 2001 From: Afgr1087 Date: Wed, 29 Mar 2023 12:47:05 +0100 Subject: [PATCH 07/43] #1778 fixed test --- .../test_full_battery_models/test_base_battery_model.py | 1 + 1 file changed, 1 insertion(+) 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 2068167e8f..01ff43afe2 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 @@ -22,6 +22,7 @@ 'current collector': 'uniform' (possible: ['uniform', 'potential pair', 'potential pair quite conductive']) 'dimensionality': 0 (possible: [0, 1, 2]) 'electrolyte conductivity': 'default' (possible: ['default', 'full', 'leading order', 'composite', 'integrated']) +'heat of mixing': 'false' (possible: ['false', 'true']) 'hydrolysis': 'false' (possible: ['false', 'true']) 'intercalation kinetics': 'symmetric Butler-Volmer' (possible: ['symmetric Butler-Volmer', 'asymmetric Butler-Volmer', 'linear', 'Marcus', 'Marcus-Hush-Chidsey']) 'interface utilisation': 'full' (possible: ['full', 'constant', 'current-driven']) From 908632ab920b9b73e046f4f6402e0e0b00e722f0 Mon Sep 17 00:00:00 2001 From: Afgr1087 Date: Wed, 29 Mar 2023 13:04:14 +0100 Subject: [PATCH 08/43] #1778 fixed test --- .../test_lithium_ion/base_lithium_ion_tests.py | 7 +++++++ 1 file changed, 7 insertions(+) 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 99b2b10148..2e8f04a7d1 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 @@ -67,6 +67,13 @@ def test_well_posed_thermal_2plus1D(self): } self.check_well_posedness(options) + def test_well_posed_heat_of_mixing(self): + options = { + "heat of mixing": "true", + "thermal": "x-lumped", + } + self.check_well_posedness(options) + def test_well_posed_contact_resistance(self): options = {"contact resistance": "true"} self.check_well_posedness(options) From 6c9246656d9a872366abe8de60a38576f2b6c209 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 29 Mar 2023 13:32:57 +0100 Subject: [PATCH 09/43] #1788 added heat of mixing tests --- .../base_lithium_ion_tests.py | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) 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 2e8f04a7d1..5e2c084e3a 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 @@ -67,10 +67,73 @@ def test_well_posed_thermal_2plus1D(self): } self.check_well_posedness(options) - def test_well_posed_heat_of_mixing(self): + def test_well_posed_isothermal_heat_source_hom(self): options = { + "calculate heat source for isothermal models": "true", + "thermal": "isothermal", + "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_2plus1D_hom(self): + options = { + "current collector": "potential pair", + "dimensionality": 1, + "heat of mixing": "true", + } + self.check_well_posedness(options) + + options = { + "current collector": "potential pair", + "dimensionality": 2, + "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_lumped_thermal_model_1D_hom(self): + options = {"thermal": "x-lumped", "heat of mixing": "true"} + self.check_well_posedness(options) + + def test_well_posed_x_full_thermal_model_hom(self): + options = { + "thermal": "x-full", + "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_lumped_thermal_1plus1D_hom(self): + options = { + "current collector": "potential pair", + "dimensionality": 1, + "thermal": "lumped", + "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_lumped_thermal_2plus1D_hom(self): + options = { + "current collector": "potential pair", + "dimensionality": 2, + "thermal": "lumped", "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_thermal_1plus1D_hom(self): + options = { + "current collector": "potential pair", + "dimensionality": 1, "thermal": "x-lumped", + "heat of mixing": "true", + } + self.check_well_posedness(options) + + def test_well_posed_thermal_2plus1D_hom(self): + options = { + "current collector": "potential pair", + "dimensionality": 2, + "thermal": "x-lumped", + "heat of mixing": "true", } self.check_well_posedness(options) From 35f96e3e9fb104281552d48c0de2c56c01acadee Mon Sep 17 00:00:00 2001 From: Afgr1087 Date: Wed, 29 Mar 2023 14:19:15 +0100 Subject: [PATCH 10/43] #1778 fixed test --- .../compare_lithium_ion_heat_of_mixing.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 examples/scripts/compare_lithium_ion_heat_of_mixing.py diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py new file mode 100644 index 0000000000..0c65ad640d --- /dev/null +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -0,0 +1,43 @@ +# +# Compare lithium-ion battery models +# +import pybamm + +pybamm.set_logging_level("INFO") +# load models +models = [ + pybamm.lithium_ion.DFN({"heat of mixing": "true","thermal": "x-lumped"},name="hom"), + pybamm.lithium_ion.DFN({"thermal": "x-lumped"},name="nhom") +] + +parameter_values = pybamm.ParameterValues("Chen2020_composite") + +# create and run simulations +sims = [] +for model in models: + sim = pybamm.Simulation(model, parameter_values=parameter_values) + sim.solve([0, 4500]) + sims.append(sim) + +# plot +pybamm.dynamic_plot( + sims, + [ + [ + "Average negative primary particle concentration", + "Average negative secondary particle concentration", + ], + [ + "X-averaged negative electrode primary volumetric " + "interfacial current density [A.m-3]", + "X-averaged negative electrode secondary volumetric " + "interfacial current density [A.m-3]", + "X-averaged negative electrode volumetric " + "interfacial current density [A.m-3]", + ], + "X-averaged negative electrode primary open-circuit potential [V]", + "X-averaged negative electrode secondary open-circuit potential [V]", + "Average positive particle concentration [mol.m-3]", + "Voltage [V]", + ], +) From 0da6f2e7f94e1d66394db702bf8497735e53c94d Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 13:58:23 +0100 Subject: [PATCH 11/43] First commit --- .../models/submodels/thermal/base_thermal.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 124a258a2e..e82140b90e 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -2,6 +2,7 @@ # Base class for thermal effects # import pybamm +import numpy as np class BaseThermal(pybamm.BaseSubModel): @@ -146,15 +147,24 @@ def _get_standard_coupled_variables(self, variables): ) # Heat of mixing - if self.options.electrode_types["negative"] == "planar" or not self.options["heat of mixing"]: - # make 0 - asdfasfd + if self.options["heat of mixing"] == "true": + F = pybamm.constants.F.value + pi = np.pi + a_n = variables["Negative electrode surface area to volume ratio [m-1]"] + a_p = variables["Positive electrode surface area to volume ratio [m-1]"] + R_n = variables["Negative particle radius [m]"] + R_p = variables["Positive particle radius [m]"] + c_n = variables["Negative particle concentration [mol.m-3]"] + c_p = variables["Positive particle concentration [mol.m-3]"] + dc_ndr = pybamm.grad_squared(c_n) + dc_pdr = pybamm.grad_squared(c_p) + D_n = variables["Negative particle effective diffusivity [m2.s-1]"] + D_p = variables["Positive particle effective diffusivity [m2.s-1]"] else: - # write equation - asdfasdf + Q_mix = 0 # Total heating - Q = Q_ohm + Q_rxn + Q_rev + Q = Q_ohm + Q_rxn + Q_rev + Q_mix # Compute the X-average over the entire cell, including current collectors Q_ohm_av = self._x_average(Q_ohm, Q_ohm_s_cn, Q_ohm_s_cp) From f6fc9d11c6e224a8881d58390f3eb3cd2d088168 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 14:50:00 +0100 Subject: [PATCH 12/43] First iteration --- .../models/submodels/thermal/base_thermal.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index e82140b90e..b11261276b 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -154,12 +154,28 @@ def _get_standard_coupled_variables(self, variables): a_p = variables["Positive electrode surface area to volume ratio [m-1]"] R_n = variables["Negative particle radius [m]"] R_p = variables["Positive particle radius [m]"] + N_n = a_n / (4 * pi * R_n**2) + N_p = a_p / (4 * pi * R_p**2) c_n = variables["Negative particle concentration [mol.m-3]"] c_p = variables["Positive particle concentration [mol.m-3]"] - dc_ndr = pybamm.grad_squared(c_n) - dc_pdr = pybamm.grad_squared(c_p) + dc_n_dr = pybamm.grad_squared(c_n) + dc_p_dr = pybamm.grad_squared(c_p) D_n = variables["Negative particle effective diffusivity [m2.s-1]"] D_p = variables["Positive particle effective diffusivity [m2.s-1]"] + Ueq_n = variables["Negative electrode open-circuit potential [V]"] + Ueq_p = variables["Positive electrode open-circuit potential [V]"] + dUeq_n = Ueq_n.diff(c_n) + dUeq_p = Ueq_p.diff(c_p) + integrand_r_n = D_n * dc_n_dr**2 * dUeq_n + integrand_r_p = D_p * dc_p_dr**2 * dUeq_p + integration_variable_r_n = [pybamm.SpatialVariable("r", integrand_r_n)] + integration_variable_r_p = [pybamm.SpatialVariable("r", integrand_r_p)] + integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) + integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) + Q_mix_s_n = F * N_n * integral_r_n + Q_mix_s_p = F * N_p * integral_r_p + Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") + Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) else: Q_mix = 0 @@ -171,18 +187,23 @@ def _get_standard_coupled_variables(self, variables): Q_rxn_av = self._x_average(Q_rxn, 0, 0) Q_rev_av = self._x_average(Q_rev, 0, 0) Q_av = self._x_average(Q, Q_ohm_s_cn, Q_ohm_s_cp) + Q_mix_av = self._x_average(Q_mix, 0, 0) # Compute volume-averaged heat source terms Q_ohm_vol_av = self._yz_average(Q_ohm_av) Q_rxn_vol_av = self._yz_average(Q_rxn_av) Q_rev_vol_av = self._yz_average(Q_rev_av) Q_vol_av = self._yz_average(Q_av) + Q_mix_vol_av = self._yz_average(Q_mix_av) variables.update( { "Ohmic heating [W.m-3]": Q_ohm, "X-averaged Ohmic heating [W.m-3]": Q_ohm_av, "Volume-averaged Ohmic heating [W.m-3]": Q_ohm_vol_av, + "Heat of mixing [W.m-3]": Q_mix, + "X-averaged heat of mixing [W.m-3]": Q_mix_av, + "Volume-averaged heat of mixing [W.m-3]": Q_mix_vol_av, "Irreversible electrochemical heating [W.m-3]": Q_rxn, "X-averaged irreversible electrochemical heating [W.m-3]": Q_rxn_av, "Volume-averaged irreversible electrochemical heating " From 2463a0bb928f445d29768f29bacf97f45d4977d9 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 29 Mar 2023 14:27:43 +0100 Subject: [PATCH 13/43] #1788 try to fix diff of U --- pybamm/models/submodels/thermal/base_thermal.py | 5 +++-- pybamm/parameters/lithium_ion_parameters.py | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index b11261276b..38ce80eb14 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -164,8 +164,9 @@ def _get_standard_coupled_variables(self, variables): D_p = variables["Positive particle effective diffusivity [m2.s-1]"] Ueq_n = variables["Negative electrode open-circuit potential [V]"] Ueq_p = variables["Positive electrode open-circuit potential [V]"] - dUeq_n = Ueq_n.diff(c_n) - dUeq_p = Ueq_p.diff(c_p) + # Drop the blow-up term as it has spatial operators and diff doesn't work + dUeq_n = Ueq_n.children[0].diff(c_n) + dUeq_p = Ueq_p.children[0].diff(c_p) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integrand_r_p = D_p * dc_p_dr**2 * dUeq_p integration_variable_r_n = [pybamm.SpatialVariable("r", integrand_r_n)] diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index 43901eff2b..4c5935ec6b 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -578,12 +578,14 @@ def U(self, sto, T, lithiation=None): u_ref = pybamm.FunctionParameter( f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", inputs ) + + dudt_func = self.dUdT(sto) + u_ref = u_ref + (T - self.main_param.T_ref) * dudt_func + # add a term to ensure that the OCP goes to infinity at 0 and -infinity at 1 # this will not affect the OCP for most values of sto - # see #1435 - u_ref = u_ref + 1e-6 * (1 / sto + 1 / (sto - 1)) - dudt_func = self.dUdT(sto) - out = u_ref + (T - self.main_param.T_ref) * dudt_func + # see #1435 + out = u_ref + 1e-6 * (1 / sto + 1 / (sto - 1)) if self.domain == "negative": out.print_name = r"U_\mathrm{n}(c^\mathrm{surf}_\mathrm{s,n}, T)" From dda5340e3d7eb26216e18051681e09dbc90b8147 Mon Sep 17 00:00:00 2001 From: smitasahu2 Date: Wed, 29 Mar 2023 15:51:24 +0100 Subject: [PATCH 14/43] first push from mac --- pybamm/models/submodels/thermal/base_thermal.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 38ce80eb14..568b901b93 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -178,7 +178,10 @@ def _get_standard_coupled_variables(self, variables): Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) else: - Q_mix = 0 + Q_mix_s_n = pybamm.FullBroadcast(0, ["negative"], "current collector") + Q_mix_s_p = pybamm.FullBroadcast(0, ["positive"], "current collector") + Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") + Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) # Total heating Q = Q_ohm + Q_rxn + Q_rev + Q_mix From 549e1e27ff85b33663f15c3d61611795b66cb2b3 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 16:02:22 +0100 Subject: [PATCH 15/43] Fixed full broadcast --- pybamm/models/submodels/thermal/base_thermal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 568b901b93..e42a755b09 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -178,8 +178,8 @@ def _get_standard_coupled_variables(self, variables): Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) else: - Q_mix_s_n = pybamm.FullBroadcast(0, ["negative"], "current collector") - Q_mix_s_p = pybamm.FullBroadcast(0, ["positive"], "current collector") + Q_mix_s_n = pybamm.FullBroadcast(0, ["negative electrode"], "current collector") + Q_mix_s_p = pybamm.FullBroadcast(0, ["positive electrode"], "current collector") Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) From 67a2e3436f3c67c4ae1ce8a0258c78195c4e2917 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 16:06:30 +0100 Subject: [PATCH 16/43] Fixed domain in the integral --- pybamm/models/submodels/thermal/base_thermal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index e42a755b09..dea05ab791 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -169,8 +169,8 @@ def _get_standard_coupled_variables(self, variables): dUeq_p = Ueq_p.children[0].diff(c_p) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integrand_r_p = D_p * dc_p_dr**2 * dUeq_p - integration_variable_r_n = [pybamm.SpatialVariable("r", integrand_r_n)] - integration_variable_r_p = [pybamm.SpatialVariable("r", integrand_r_p)] + integration_variable_r_n = [pybamm.SpatialVariable("r", domain=integrand_r_n.domain)] + integration_variable_r_p = [pybamm.SpatialVariable("r", domain=integrand_r_p.domain)] integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) Q_mix_s_n = F * N_n * integral_r_n From 33e87265805b44bb955dd0cad369a713ee4e8967 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 29 Mar 2023 14:55:12 +0100 Subject: [PATCH 17/43] #1778 fix parameter values example --- .../compare_lithium_ion_heat_of_mixing.py | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index 0c65ad640d..c550767fb8 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -10,7 +10,7 @@ pybamm.lithium_ion.DFN({"thermal": "x-lumped"},name="nhom") ] -parameter_values = pybamm.ParameterValues("Chen2020_composite") +parameter_values = pybamm.ParameterValues("Chen2020") # create and run simulations sims = [] @@ -20,24 +20,4 @@ sims.append(sim) # plot -pybamm.dynamic_plot( - sims, - [ - [ - "Average negative primary particle concentration", - "Average negative secondary particle concentration", - ], - [ - "X-averaged negative electrode primary volumetric " - "interfacial current density [A.m-3]", - "X-averaged negative electrode secondary volumetric " - "interfacial current density [A.m-3]", - "X-averaged negative electrode volumetric " - "interfacial current density [A.m-3]", - ], - "X-averaged negative electrode primary open-circuit potential [V]", - "X-averaged negative electrode secondary open-circuit potential [V]", - "Average positive particle concentration [mol.m-3]", - "Voltage [V]", - ], -) +pybamm.dynamic_plot(sims) From c60d6eb47cb0fac8b6fdd3deee6323ec9c76d3e8 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 16:21:12 +0100 Subject: [PATCH 18/43] Added children[0].children[0] --- pybamm/models/submodels/thermal/base_thermal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index dea05ab791..0c0fe16caa 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -164,9 +164,9 @@ def _get_standard_coupled_variables(self, variables): D_p = variables["Positive particle effective diffusivity [m2.s-1]"] Ueq_n = variables["Negative electrode open-circuit potential [V]"] Ueq_p = variables["Positive electrode open-circuit potential [V]"] - # Drop the blow-up term as it has spatial operators and diff doesn't work - dUeq_n = Ueq_n.children[0].diff(c_n) - dUeq_p = Ueq_p.children[0].diff(c_p) + # TODO: Drop terms as it has spatial operators and diff doesn't work + dUeq_n = Ueq_n.children[0].children[0].diff(c_n) + dUeq_p = Ueq_p.children[0].children[0].diff(c_p) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integrand_r_p = D_p * dc_p_dr**2 * dUeq_p integration_variable_r_n = [pybamm.SpatialVariable("r", domain=integrand_r_n.domain)] From cd1f8687af6e3e7a23e6e5e60ed7cb5a2cf2d01d Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Wed, 29 Mar 2023 16:39:05 +0100 Subject: [PATCH 19/43] Added half cell --- .../models/submodels/thermal/base_thermal.py | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 0c0fe16caa..5b16758ba2 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -150,30 +150,35 @@ def _get_standard_coupled_variables(self, variables): if self.options["heat of mixing"] == "true": F = pybamm.constants.F.value pi = np.pi - a_n = variables["Negative electrode surface area to volume ratio [m-1]"] + if self.options.electrode_types["negative"] == "planar": + Q_mix_s_n = pybamm.FullBroadcast( + 0, ["negative electrode"], "current collector" + ) + else: + a_n = variables["Negative electrode surface area to volume ratio [m-1]"] + R_n = variables["Negative particle radius [m]"] + N_n = a_n / (4 * pi * R_n**2) + c_n = variables["Negative particle concentration [mol.m-3]"] + dc_n_dr = pybamm.grad_squared(c_n) + D_n = variables["Negative particle effective diffusivity [m2.s-1]"] + Ueq_n = variables["Negative electrode open-circuit potential [V]"] + # TODO: Drop terms as it has spatial operators and diff doesn't work + dUeq_n = Ueq_n.children[0].children[0].diff(c_n) + integrand_r_n = D_n * dc_n_dr**2 * dUeq_n + integration_variable_r_n = [pybamm.SpatialVariable("r", domain=integrand_r_n.domain)] + integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) + Q_mix_s_n = F * N_n * integral_r_n a_p = variables["Positive electrode surface area to volume ratio [m-1]"] - R_n = variables["Negative particle radius [m]"] R_p = variables["Positive particle radius [m]"] - N_n = a_n / (4 * pi * R_n**2) N_p = a_p / (4 * pi * R_p**2) - c_n = variables["Negative particle concentration [mol.m-3]"] c_p = variables["Positive particle concentration [mol.m-3]"] - dc_n_dr = pybamm.grad_squared(c_n) dc_p_dr = pybamm.grad_squared(c_p) - D_n = variables["Negative particle effective diffusivity [m2.s-1]"] D_p = variables["Positive particle effective diffusivity [m2.s-1]"] - Ueq_n = variables["Negative electrode open-circuit potential [V]"] Ueq_p = variables["Positive electrode open-circuit potential [V]"] - # TODO: Drop terms as it has spatial operators and diff doesn't work - dUeq_n = Ueq_n.children[0].children[0].diff(c_n) dUeq_p = Ueq_p.children[0].children[0].diff(c_p) - integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integrand_r_p = D_p * dc_p_dr**2 * dUeq_p - integration_variable_r_n = [pybamm.SpatialVariable("r", domain=integrand_r_n.domain)] integration_variable_r_p = [pybamm.SpatialVariable("r", domain=integrand_r_p.domain)] - integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) - Q_mix_s_n = F * N_n * integral_r_n Q_mix_s_p = F * N_p * integral_r_p Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) From 4bc354eb6162c157238b8db8f5e435d644cd68ec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 15:46:56 +0000 Subject: [PATCH 20/43] style: pre-commit fixes --- .../compare_lithium_ion_heat_of_mixing.py | 6 ++++-- .../lithium_ion/electrode_soh.py | 3 +-- pybamm/models/submodels/thermal/base_thermal.py | 16 ++++++++++++---- pybamm/parameters/lithium_ion_parameters.py | 4 ++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index c550767fb8..3afc13d665 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -6,8 +6,10 @@ pybamm.set_logging_level("INFO") # load models models = [ - pybamm.lithium_ion.DFN({"heat of mixing": "true","thermal": "x-lumped"},name="hom"), - pybamm.lithium_ion.DFN({"thermal": "x-lumped"},name="nhom") + pybamm.lithium_ion.DFN( + {"heat of mixing": "true", "thermal": "x-lumped"}, name="hom" + ), + pybamm.lithium_ion.DFN({"thermal": "x-lumped"}, name="nhom"), ] parameter_values = pybamm.ParameterValues("Chen2020") diff --git a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py index 0a675ddab9..8f92c9f1b2 100644 --- a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py +++ b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py @@ -278,8 +278,7 @@ def solve(self, inputs): sol_dict.update({"Maximum theoretical energy [W.h]": energy}) except: warnings.warn("couldn't calculate theoretical energy") - - + return sol_dict def _set_up_solve(self, inputs): diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 5b16758ba2..fc8fd8da40 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -165,7 +165,9 @@ def _get_standard_coupled_variables(self, variables): # TODO: Drop terms as it has spatial operators and diff doesn't work dUeq_n = Ueq_n.children[0].children[0].diff(c_n) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n - integration_variable_r_n = [pybamm.SpatialVariable("r", domain=integrand_r_n.domain)] + integration_variable_r_n = [ + pybamm.SpatialVariable("r", domain=integrand_r_n.domain) + ] integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) Q_mix_s_n = F * N_n * integral_r_n a_p = variables["Positive electrode surface area to volume ratio [m-1]"] @@ -177,14 +179,20 @@ def _get_standard_coupled_variables(self, variables): Ueq_p = variables["Positive electrode open-circuit potential [V]"] dUeq_p = Ueq_p.children[0].children[0].diff(c_p) integrand_r_p = D_p * dc_p_dr**2 * dUeq_p - integration_variable_r_p = [pybamm.SpatialVariable("r", domain=integrand_r_p.domain)] + integration_variable_r_p = [ + pybamm.SpatialVariable("r", domain=integrand_r_p.domain) + ] integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) Q_mix_s_p = F * N_p * integral_r_p Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) else: - Q_mix_s_n = pybamm.FullBroadcast(0, ["negative electrode"], "current collector") - Q_mix_s_p = pybamm.FullBroadcast(0, ["positive electrode"], "current collector") + Q_mix_s_n = pybamm.FullBroadcast( + 0, ["negative electrode"], "current collector" + ) + Q_mix_s_p = pybamm.FullBroadcast( + 0, ["positive electrode"], "current collector" + ) Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index 4c5935ec6b..2e1ed515fb 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -578,13 +578,13 @@ def U(self, sto, T, lithiation=None): u_ref = pybamm.FunctionParameter( f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", inputs ) - + dudt_func = self.dUdT(sto) u_ref = u_ref + (T - self.main_param.T_ref) * dudt_func # add a term to ensure that the OCP goes to infinity at 0 and -infinity at 1 # this will not affect the OCP for most values of sto - # see #1435 + # see #1435 out = u_ref + 1e-6 * (1 / sto + 1 / (sto - 1)) if self.domain == "negative": From d2e6274fd81d93510719f517c6d285eff9639810 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 29 Mar 2023 15:48:04 +0100 Subject: [PATCH 21/43] #1788 revert some unrelated changes --- pybamm/models/Newfile.py | 0 .../lithium_ion/electrode_soh.py | 20 ++++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 pybamm/models/Newfile.py diff --git a/pybamm/models/Newfile.py b/pybamm/models/Newfile.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py index 8f92c9f1b2..7bcc3c7e09 100644 --- a/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py +++ b/pybamm/models/full_battery_models/lithium_ion/electrode_soh.py @@ -267,18 +267,14 @@ def solve(self, inputs): sol_dict = {key: sol[key].data[0] for key in sol.all_models[0].variables.keys()} # Calculate theoretical energy - try: - x_0 = sol_dict["x_0"] - y_0 = sol_dict["y_0"] - x_100 = sol_dict["x_100"] - y_100 = sol_dict["y_100"] - energy = pybamm.lithium_ion.electrode_soh.theoretical_energy_integral( - self.parameter_values, x_100, x_0, y_100, y_0 - ) - sol_dict.update({"Maximum theoretical energy [W.h]": energy}) - except: - warnings.warn("couldn't calculate theoretical energy") - + x_0 = sol_dict["x_0"] + y_0 = sol_dict["y_0"] + x_100 = sol_dict["x_100"] + y_100 = sol_dict["y_100"] + energy = pybamm.lithium_ion.electrode_soh.theoretical_energy_integral( + self.parameter_values, x_100, x_0, y_100, y_0 + ) + sol_dict.update({"Maximum theoretical energy [W.h]": energy}) return sol_dict def _set_up_solve(self, inputs): From 3ad0c75b855b3f1d81fc8d812733d766f5200b59 Mon Sep 17 00:00:00 2001 From: Alexander Bills Date: Thu, 30 Mar 2023 20:47:55 -0400 Subject: [PATCH 22/43] change ocv hack --- pybamm/models/submodels/thermal/base_thermal.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index fc8fd8da40..ec073e812a 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -157,13 +157,13 @@ def _get_standard_coupled_variables(self, variables): else: a_n = variables["Negative electrode surface area to volume ratio [m-1]"] R_n = variables["Negative particle radius [m]"] + T_n = variables["Negative electrode temperature [K]"] N_n = a_n / (4 * pi * R_n**2) c_n = variables["Negative particle concentration [mol.m-3]"] dc_n_dr = pybamm.grad_squared(c_n) D_n = variables["Negative particle effective diffusivity [m2.s-1]"] - Ueq_n = variables["Negative electrode open-circuit potential [V]"] - # TODO: Drop terms as it has spatial operators and diff doesn't work - dUeq_n = Ueq_n.children[0].children[0].diff(c_n) + Ueq_n = param.n.prim.U(c_n, T_n) + dUeq_n = Ueq_n.diff(c_n) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integration_variable_r_n = [ pybamm.SpatialVariable("r", domain=integrand_r_n.domain) @@ -172,12 +172,13 @@ def _get_standard_coupled_variables(self, variables): Q_mix_s_n = F * N_n * integral_r_n a_p = variables["Positive electrode surface area to volume ratio [m-1]"] R_p = variables["Positive particle radius [m]"] + T_p = variables["Positive electrode temperature [K]"] N_p = a_p / (4 * pi * R_p**2) c_p = variables["Positive particle concentration [mol.m-3]"] dc_p_dr = pybamm.grad_squared(c_p) D_p = variables["Positive particle effective diffusivity [m2.s-1]"] - Ueq_p = variables["Positive electrode open-circuit potential [V]"] - dUeq_p = Ueq_p.children[0].children[0].diff(c_p) + Ueq_p = param.p.prim.U(c_p, T_p) + dUeq_p = Ueq_p.diff(c_p) integrand_r_p = D_p * dc_p_dr**2 * dUeq_p integration_variable_r_p = [ pybamm.SpatialVariable("r", domain=integrand_r_p.domain) From 537b2bfad89dd634f73259f9304fdf6ea44ab2b9 Mon Sep 17 00:00:00 2001 From: Alexander Bills Date: Thu, 30 Mar 2023 21:02:51 -0400 Subject: [PATCH 23/43] Revert "change ocv hack" This reverts commit 3ad0c75b855b3f1d81fc8d812733d766f5200b59. --- pybamm/models/submodels/thermal/base_thermal.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index ec073e812a..fc8fd8da40 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -157,13 +157,13 @@ def _get_standard_coupled_variables(self, variables): else: a_n = variables["Negative electrode surface area to volume ratio [m-1]"] R_n = variables["Negative particle radius [m]"] - T_n = variables["Negative electrode temperature [K]"] N_n = a_n / (4 * pi * R_n**2) c_n = variables["Negative particle concentration [mol.m-3]"] dc_n_dr = pybamm.grad_squared(c_n) D_n = variables["Negative particle effective diffusivity [m2.s-1]"] - Ueq_n = param.n.prim.U(c_n, T_n) - dUeq_n = Ueq_n.diff(c_n) + Ueq_n = variables["Negative electrode open-circuit potential [V]"] + # TODO: Drop terms as it has spatial operators and diff doesn't work + dUeq_n = Ueq_n.children[0].children[0].diff(c_n) integrand_r_n = D_n * dc_n_dr**2 * dUeq_n integration_variable_r_n = [ pybamm.SpatialVariable("r", domain=integrand_r_n.domain) @@ -172,13 +172,12 @@ def _get_standard_coupled_variables(self, variables): Q_mix_s_n = F * N_n * integral_r_n a_p = variables["Positive electrode surface area to volume ratio [m-1]"] R_p = variables["Positive particle radius [m]"] - T_p = variables["Positive electrode temperature [K]"] N_p = a_p / (4 * pi * R_p**2) c_p = variables["Positive particle concentration [mol.m-3]"] dc_p_dr = pybamm.grad_squared(c_p) D_p = variables["Positive particle effective diffusivity [m2.s-1]"] - Ueq_p = param.p.prim.U(c_p, T_p) - dUeq_p = Ueq_p.diff(c_p) + Ueq_p = variables["Positive electrode open-circuit potential [V]"] + dUeq_p = Ueq_p.children[0].children[0].diff(c_p) integrand_r_p = D_p * dc_p_dr**2 * dUeq_p integration_variable_r_p = [ pybamm.SpatialVariable("r", domain=integrand_r_p.domain) From 9817dfc31b3b7d152ad7083107ead61de6436e9f Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Tue, 23 May 2023 12:40:04 +0100 Subject: [PATCH 24/43] #1778 fix heat of mixing --- .../models/submodels/thermal/base_thermal.py | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index fc8fd8da40..2edd5bf6b7 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -17,8 +17,9 @@ class BaseThermal(pybamm.BaseSubModel): A dictionary of options to be passed to the model. """ - def __init__(self, param, options=None): + def __init__(self, param, options=None, x_average=False): super().__init__(param, options=options) + self.x_average = x_average def _get_standard_fundamental_variables(self, T_dict): """ @@ -158,13 +159,18 @@ def _get_standard_coupled_variables(self, variables): a_n = variables["Negative electrode surface area to volume ratio [m-1]"] R_n = variables["Negative particle radius [m]"] N_n = a_n / (4 * pi * R_n**2) - c_n = variables["Negative particle concentration [mol.m-3]"] - dc_n_dr = pybamm.grad_squared(c_n) - D_n = variables["Negative particle effective diffusivity [m2.s-1]"] - Ueq_n = variables["Negative electrode open-circuit potential [V]"] - # TODO: Drop terms as it has spatial operators and diff doesn't work - dUeq_n = Ueq_n.children[0].children[0].diff(c_n) - integrand_r_n = D_n * dc_n_dr**2 * dUeq_n + if self.x_average: + c_n = variables["X-averaged negative particle concentration [mol.m-3]" ] + else: + c_n = variables["Negative particle concentration [mol.m-3]"] + T_n_part = pybamm.PrimaryBroadcast( + variables["Negative electrode temperature [K]"], + ["negative particle"], + ) + dc_n_dr2 = pybamm.inner(pybamm.grad(c_n), pybamm.grad(c_n)) + D_n = param.n.prim.D(c_n, T_n_part) + dUeq_n = param.n.prim.dUdsto(c_n / param.n.prim.c_max, T_n_part) + integrand_r_n = D_n * dc_n_dr2 * dUeq_n / param.n.prim.c_max integration_variable_r_n = [ pybamm.SpatialVariable("r", domain=integrand_r_n.domain) ] @@ -173,12 +179,18 @@ def _get_standard_coupled_variables(self, variables): a_p = variables["Positive electrode surface area to volume ratio [m-1]"] R_p = variables["Positive particle radius [m]"] N_p = a_p / (4 * pi * R_p**2) - c_p = variables["Positive particle concentration [mol.m-3]"] - dc_p_dr = pybamm.grad_squared(c_p) - D_p = variables["Positive particle effective diffusivity [m2.s-1]"] - Ueq_p = variables["Positive electrode open-circuit potential [V]"] - dUeq_p = Ueq_p.children[0].children[0].diff(c_p) - integrand_r_p = D_p * dc_p_dr**2 * dUeq_p + if self.x_average: + c_p = variables["X-averaged positive particle concentration [mol.m-3]"] + else: + c_p = variables["Positive particle concentration [mol.m-3]"] + T_p_part = pybamm.PrimaryBroadcast( + variables["Positive electrode temperature [K]"], + ["positive particle"], + ) + dc_p_dr2 = pybamm.inner(pybamm.grad(c_p), pybamm.grad(c_p)) + D_p = param.p.prim.D(c_p, T_p_part) + dUeq_p = param.p.prim.dUdsto(c_p / param.p.prim.c_max, T_p_part) + integrand_r_p = D_p * dc_p_dr2 * dUeq_p / param.p.prim.c_max integration_variable_r_p = [ pybamm.SpatialVariable("r", domain=integrand_r_p.domain) ] From 7881045a403f22afb47b4a72b024792dba535b2b Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Tue, 23 May 2023 12:40:29 +0100 Subject: [PATCH 25/43] #1839 fix thermal submodels to take x_average --- .../full_battery_models/base_battery_model.py | 2 +- pybamm/models/submodels/thermal/isothermal.py | 4 +-- pybamm/models/submodels/thermal/lumped.py | 4 +-- .../pouch_cell_1D_current_collectors.py | 4 +-- .../pouch_cell_2D_current_collectors.py | 4 +-- pybamm/models/submodels/thermal/x_full.py | 4 +-- pybamm/parameters/lithium_ion_parameters.py | 35 +++++++++++++++++++ 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index e575bd263b..3eabe39284 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -1046,7 +1046,7 @@ def set_thermal_submodel(self): if self.options["dimensionality"] == 0: thermal_submodel = pybamm.thermal.OneDimensionalX - self.submodels["thermal"] = thermal_submodel(self.param, self.options) + self.submodels["thermal"] = thermal_submodel(self.param, self.options, self.x_average) def set_current_collector_submodel(self): if self.options["current collector"] in ["uniform"]: diff --git a/pybamm/models/submodels/thermal/isothermal.py b/pybamm/models/submodels/thermal/isothermal.py index 3573c1634a..e0f7454fa2 100644 --- a/pybamm/models/submodels/thermal/isothermal.py +++ b/pybamm/models/submodels/thermal/isothermal.py @@ -18,8 +18,8 @@ class Isothermal(BaseThermal): A dictionary of options to be passed to the model. """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=False): + super().__init__(param, options=options, x_average=x_average) def get_fundamental_variables(self): T_amb = self.param.T_amb(pybamm.t) diff --git a/pybamm/models/submodels/thermal/lumped.py b/pybamm/models/submodels/thermal/lumped.py index 9fdc3ac403..a68b399259 100644 --- a/pybamm/models/submodels/thermal/lumped.py +++ b/pybamm/models/submodels/thermal/lumped.py @@ -27,8 +27,8 @@ class Lumped(BaseThermal): of The Electrochemical Society, 167(14):140513, 2020 """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=False): + super().__init__(param, options=options, x_average=x_average) pybamm.citations.register("Timms2021") def get_fundamental_variables(self): diff --git a/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py b/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py index 18fd9b21e0..ca319244be 100644 --- a/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py +++ b/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_1D_current_collectors.py @@ -29,8 +29,8 @@ class CurrentCollector1D(BaseThermal): of The Electrochemical Society, 167(14):140513, 2020 """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=True): + super().__init__(param, options=options, x_average=x_average) pybamm.citations.register("Timms2021") def get_fundamental_variables(self): diff --git a/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py b/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py index b64f171608..9c5495c08b 100644 --- a/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py +++ b/pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py @@ -29,8 +29,8 @@ class CurrentCollector2D(BaseThermal): of The Electrochemical Society, 167(14):140513, 2020 """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=True): + super().__init__(param, options=options, x_average=x_average) pybamm.citations.register("Timms2021") def get_fundamental_variables(self): diff --git a/pybamm/models/submodels/thermal/x_full.py b/pybamm/models/submodels/thermal/x_full.py index 9c6bd15441..0e11bdfa40 100644 --- a/pybamm/models/submodels/thermal/x_full.py +++ b/pybamm/models/submodels/thermal/x_full.py @@ -32,8 +32,8 @@ class OneDimensionalX(BaseThermal): of The Electrochemical Society, 167(14):140513, 2020 """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=False): + super().__init__(param, options=options, x_average=x_average) pybamm.citations.register("Timms2021") def get_fundamental_variables(self): diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index 2e1ed515fb..98e9d9db04 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -592,7 +592,42 @@ def U(self, sto, T, lithiation=None): elif self.domain == "positive": out.print_name = r"U_\mathrm{p}(c^\mathrm{surf}_\mathrm{s,p}, T)" return out + + def dUdsto(self, sto, T, lithiation=None): + """ + Dimensional derivative of the open-circuit potential with respect to the + stoichiometry [V] + """ + domain, Domain = self.domain_Domain + tol = pybamm.settings.tolerances["U__c_s"] + sto = pybamm.maximum(pybamm.minimum(sto, 1 - tol), tol) + if lithiation is None: + lithiation = "" + else: + lithiation = lithiation + " " + + u_ref = pybamm.FunctionParameter( + f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", + {f"{self.phase_prefactor}{Domain} particle stoichiometry": sto}, + diff_variable=sto + ) + + dudt = pybamm.FunctionParameter( + f"{self.phase_prefactor}{Domain} electrode OCP entropic change [V.K-1]", + { + f"{Domain} particle stoichiometry": sto, + f"{self.phase_prefactor}Maximum {domain} particle " + "surface concentration [mol.m-3]": self.c_max, + }, + diff_variable=sto, + ) + return u_ref + (T - self.main_param.T_ref) * dudt + # Drop the regularisation term when computing the derivative + # sto_dv = pybamm.InputParameter("sto_dv") + # T_dv = pybamm.InputParameter("T_dv") + # return self.U(sto_dv, T_dv).children[0].diff(sto_dv).evaluate({sto_dv: sto, T_dv: T}) + def dUdT(self, sto): """ Dimensional entropic change of the open-circuit potential [V.K-1] From 969b464e8c0fc6f67126fc892d80a7ce7044cdcf Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Tue, 23 May 2023 12:40:42 +0100 Subject: [PATCH 26/43] #1778 add example heat of mixing --- .../compare_lithium_ion_heat_of_mixing.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index 3afc13d665..78ec7c588b 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -1,15 +1,15 @@ # -# Compare lithium-ion battery models +# Compare DFN model with and without heat of mixing # import pybamm pybamm.set_logging_level("INFO") # load models models = [ - pybamm.lithium_ion.DFN( - {"heat of mixing": "true", "thermal": "x-lumped"}, name="hom" + pybamm.lithium_ion.SPMe( + {"heat of mixing": "true", "thermal": "lumped"}, name="with heat of mixing" ), - pybamm.lithium_ion.DFN({"thermal": "x-lumped"}, name="nhom"), + pybamm.lithium_ion.DFN({"thermal": "lumped"}, name="without heat of mixing"), ] parameter_values = pybamm.ParameterValues("Chen2020") @@ -18,8 +18,17 @@ sims = [] for model in models: sim = pybamm.Simulation(model, parameter_values=parameter_values) - sim.solve([0, 4500]) + sim.solve([0, 3600]) sims.append(sim) # plot -pybamm.dynamic_plot(sims) +pybamm.dynamic_plot( + sims, + output_variables=[ + "X-averaged cell temperature [K]", + "X-averaged heat of mixing [W.m-3]", + "X-averaged total heating [W.m-3]", + "Voltage [V]", + "Current [A]", + ] +) From e910e77c24f461707f5b57876bda53f99393a094 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 14:03:52 +0000 Subject: [PATCH 27/43] style: pre-commit fixes --- .../scripts/compare_lithium_ion_heat_of_mixing.py | 2 +- .../models/full_battery_models/base_battery_model.py | 4 +++- pybamm/models/submodels/thermal/base_thermal.py | 4 +++- pybamm/parameters/lithium_ion_parameters.py | 12 ++++++------ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index 78ec7c588b..9eab53c0a6 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -30,5 +30,5 @@ "X-averaged total heating [W.m-3]", "Voltage [V]", "Current [A]", - ] + ], ) diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index 3eabe39284..d1a4945471 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -1046,7 +1046,9 @@ def set_thermal_submodel(self): if self.options["dimensionality"] == 0: thermal_submodel = pybamm.thermal.OneDimensionalX - self.submodels["thermal"] = thermal_submodel(self.param, self.options, self.x_average) + self.submodels["thermal"] = thermal_submodel( + self.param, self.options, self.x_average + ) def set_current_collector_submodel(self): if self.options["current collector"] in ["uniform"]: diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 2edd5bf6b7..78a19f6863 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -160,7 +160,9 @@ def _get_standard_coupled_variables(self, variables): R_n = variables["Negative particle radius [m]"] N_n = a_n / (4 * pi * R_n**2) if self.x_average: - c_n = variables["X-averaged negative particle concentration [mol.m-3]" ] + c_n = variables[ + "X-averaged negative particle concentration [mol.m-3]" + ] else: c_n = variables["Negative particle concentration [mol.m-3]"] T_n_part = pybamm.PrimaryBroadcast( diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index 98e9d9db04..f683f38622 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -592,7 +592,7 @@ def U(self, sto, T, lithiation=None): elif self.domain == "positive": out.print_name = r"U_\mathrm{p}(c^\mathrm{surf}_\mathrm{s,p}, T)" return out - + def dUdsto(self, sto, T, lithiation=None): """ Dimensional derivative of the open-circuit potential with respect to the @@ -609,15 +609,15 @@ def dUdsto(self, sto, T, lithiation=None): u_ref = pybamm.FunctionParameter( f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", {f"{self.phase_prefactor}{Domain} particle stoichiometry": sto}, - diff_variable=sto + diff_variable=sto, ) dudt = pybamm.FunctionParameter( f"{self.phase_prefactor}{Domain} electrode OCP entropic change [V.K-1]", { - f"{Domain} particle stoichiometry": sto, - f"{self.phase_prefactor}Maximum {domain} particle " - "surface concentration [mol.m-3]": self.c_max, + f"{Domain} particle stoichiometry": sto, + f"{self.phase_prefactor}Maximum {domain} particle " + "surface concentration [mol.m-3]": self.c_max, }, diff_variable=sto, ) @@ -627,7 +627,7 @@ def dUdsto(self, sto, T, lithiation=None): # sto_dv = pybamm.InputParameter("sto_dv") # T_dv = pybamm.InputParameter("T_dv") # return self.U(sto_dv, T_dv).children[0].diff(sto_dv).evaluate({sto_dv: sto, T_dv: T}) - + def dUdT(self, sto): """ Dimensional entropic change of the open-circuit potential [V.K-1] From 6402448e25f6402e112d92d0e942a12b0ec1f254 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Tue, 23 May 2023 12:55:36 +0100 Subject: [PATCH 28/43] #1778 fix lead acid models --- pybamm/models/full_battery_models/base_battery_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pybamm/models/full_battery_models/base_battery_model.py b/pybamm/models/full_battery_models/base_battery_model.py index d1a4945471..47589c6e47 100644 --- a/pybamm/models/full_battery_models/base_battery_model.py +++ b/pybamm/models/full_battery_models/base_battery_model.py @@ -1046,8 +1046,9 @@ def set_thermal_submodel(self): if self.options["dimensionality"] == 0: thermal_submodel = pybamm.thermal.OneDimensionalX + x_average = getattr(self, "x_average", False) self.submodels["thermal"] = thermal_submodel( - self.param, self.options, self.x_average + self.param, self.options, x_average ) def set_current_collector_submodel(self): From c07899d9d486a432576db6a5893844f40c96dc41 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Tue, 23 May 2023 12:57:12 +0100 Subject: [PATCH 29/43] ruff --- pybamm/parameters/lithium_ion_parameters.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index f683f38622..e639a93253 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -623,10 +623,6 @@ def dUdsto(self, sto, T, lithiation=None): ) return u_ref + (T - self.main_param.T_ref) * dudt - # Drop the regularisation term when computing the derivative - # sto_dv = pybamm.InputParameter("sto_dv") - # T_dv = pybamm.InputParameter("T_dv") - # return self.U(sto_dv, T_dv).children[0].diff(sto_dv).evaluate({sto_dv: sto, T_dv: T}) def dUdT(self, sto): """ From 00cee211ae4c50b9b5861b9a268b593889d57400 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 24 May 2023 14:27:25 +0100 Subject: [PATCH 30/43] fix SPM with the right broadcast of temperature --- pybamm/models/submodels/thermal/base_thermal.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 78a19f6863..f090c4a7b2 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -163,12 +163,11 @@ def _get_standard_coupled_variables(self, variables): c_n = variables[ "X-averaged negative particle concentration [mol.m-3]" ] + T_n = variables["X-averaged negative electrode temperature [K]"] else: c_n = variables["Negative particle concentration [mol.m-3]"] - T_n_part = pybamm.PrimaryBroadcast( - variables["Negative electrode temperature [K]"], - ["negative particle"], - ) + T_n = variables["Negative electrode temperature [K]"] + T_n_part = pybamm.PrimaryBroadcast(T_n, ["negative particle"]) dc_n_dr2 = pybamm.inner(pybamm.grad(c_n), pybamm.grad(c_n)) D_n = param.n.prim.D(c_n, T_n_part) dUeq_n = param.n.prim.dUdsto(c_n / param.n.prim.c_max, T_n_part) @@ -183,12 +182,11 @@ def _get_standard_coupled_variables(self, variables): N_p = a_p / (4 * pi * R_p**2) if self.x_average: c_p = variables["X-averaged positive particle concentration [mol.m-3]"] + T_p = variables["X-averaged positive electrode temperature [K]"] else: c_p = variables["Positive particle concentration [mol.m-3]"] - T_p_part = pybamm.PrimaryBroadcast( - variables["Positive electrode temperature [K]"], - ["positive particle"], - ) + T_p = variables["Positive electrode temperature [K]"] + T_p_part = pybamm.PrimaryBroadcast(T_p, ["positive particle"]) dc_p_dr2 = pybamm.inner(pybamm.grad(c_p), pybamm.grad(c_p)) D_p = param.p.prim.D(c_p, T_p_part) dUeq_p = param.p.prim.dUdsto(c_p / param.p.prim.c_max, T_p_part) @@ -279,6 +277,9 @@ def _current_collector_heating(self, variables): Q_s_cp = self.param.p.sigma_cc * pybamm.grad_squared(phi_s_cp) return Q_s_cn, Q_s_cp + def _heat_of_mixing(self, variables): + """Compute heat of mixing source terms.""" + def _x_average(self, var, var_cn, var_cp): """ Computes the X-average over the whole cell (including current collectors) From 7d54a60f0b0afca9b3aba6b178a589d67518979f Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Wed, 24 May 2023 15:25:01 +0100 Subject: [PATCH 31/43] #1778 refactor heat of mixing --- .../models/submodels/thermal/base_thermal.py | 126 ++++++++++-------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index f090c4a7b2..96ce458947 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -148,65 +148,8 @@ def _get_standard_coupled_variables(self, variables): ) # Heat of mixing - if self.options["heat of mixing"] == "true": - F = pybamm.constants.F.value - pi = np.pi - if self.options.electrode_types["negative"] == "planar": - Q_mix_s_n = pybamm.FullBroadcast( - 0, ["negative electrode"], "current collector" - ) - else: - a_n = variables["Negative electrode surface area to volume ratio [m-1]"] - R_n = variables["Negative particle radius [m]"] - N_n = a_n / (4 * pi * R_n**2) - if self.x_average: - c_n = variables[ - "X-averaged negative particle concentration [mol.m-3]" - ] - T_n = variables["X-averaged negative electrode temperature [K]"] - else: - c_n = variables["Negative particle concentration [mol.m-3]"] - T_n = variables["Negative electrode temperature [K]"] - T_n_part = pybamm.PrimaryBroadcast(T_n, ["negative particle"]) - dc_n_dr2 = pybamm.inner(pybamm.grad(c_n), pybamm.grad(c_n)) - D_n = param.n.prim.D(c_n, T_n_part) - dUeq_n = param.n.prim.dUdsto(c_n / param.n.prim.c_max, T_n_part) - integrand_r_n = D_n * dc_n_dr2 * dUeq_n / param.n.prim.c_max - integration_variable_r_n = [ - pybamm.SpatialVariable("r", domain=integrand_r_n.domain) - ] - integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) - Q_mix_s_n = F * N_n * integral_r_n - a_p = variables["Positive electrode surface area to volume ratio [m-1]"] - R_p = variables["Positive particle radius [m]"] - N_p = a_p / (4 * pi * R_p**2) - if self.x_average: - c_p = variables["X-averaged positive particle concentration [mol.m-3]"] - T_p = variables["X-averaged positive electrode temperature [K]"] - else: - c_p = variables["Positive particle concentration [mol.m-3]"] - T_p = variables["Positive electrode temperature [K]"] - T_p_part = pybamm.PrimaryBroadcast(T_p, ["positive particle"]) - dc_p_dr2 = pybamm.inner(pybamm.grad(c_p), pybamm.grad(c_p)) - D_p = param.p.prim.D(c_p, T_p_part) - dUeq_p = param.p.prim.dUdsto(c_p / param.p.prim.c_max, T_p_part) - integrand_r_p = D_p * dc_p_dr2 * dUeq_p / param.p.prim.c_max - integration_variable_r_p = [ - pybamm.SpatialVariable("r", domain=integrand_r_p.domain) - ] - integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) - Q_mix_s_p = F * N_p * integral_r_p - Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") - Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) - else: - Q_mix_s_n = pybamm.FullBroadcast( - 0, ["negative electrode"], "current collector" - ) - Q_mix_s_p = pybamm.FullBroadcast( - 0, ["positive electrode"], "current collector" - ) - Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") - Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) + Q_mix_s_n, Q_mix_s_s, Q_mix_s_p = self._heat_of_mixing(variables) + Q_mix = pybamm.concatenation(Q_mix_s_n, Q_mix_s_s, Q_mix_s_p) # Total heating Q = Q_ohm + Q_rxn + Q_rev + Q_mix @@ -279,6 +222,71 @@ def _current_collector_heating(self, variables): def _heat_of_mixing(self, variables): """Compute heat of mixing source terms.""" + param = self.param + + if self.options["heat of mixing"] == "true": + F = pybamm.constants.F.value + pi = np.pi + + # Compute heat of mixing in negative electrode + if self.options.electrode_types["negative"] == "planar": + Q_mix_s_n = pybamm.FullBroadcast( + 0, ["negative electrode"], "current collector" + ) + else: + a_n = variables["Negative electrode surface area to volume ratio [m-1]"] + R_n = variables["Negative particle radius [m]"] + N_n = a_n / (4 * pi * R_n**2) + if self.x_average: + c_n = variables[ + "X-averaged negative particle concentration [mol.m-3]" + ] + T_n = variables["X-averaged negative electrode temperature [K]"] + else: + c_n = variables["Negative particle concentration [mol.m-3]"] + T_n = variables["Negative electrode temperature [K]"] + T_n_part = pybamm.PrimaryBroadcast(T_n, ["negative particle"]) + dc_n_dr2 = pybamm.inner(pybamm.grad(c_n), pybamm.grad(c_n)) + D_n = param.n.prim.D(c_n, T_n_part) + dUeq_n = param.n.prim.dUdsto(c_n / param.n.prim.c_max, T_n_part) + integrand_r_n = D_n * dc_n_dr2 * dUeq_n / param.n.prim.c_max + integration_variable_r_n = [ + pybamm.SpatialVariable("r", domain=integrand_r_n.domain) + ] + integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) + Q_mix_s_n = F * N_n * integral_r_n + + # Compute heat of mixing in positive electrode + a_p = variables["Positive electrode surface area to volume ratio [m-1]"] + R_p = variables["Positive particle radius [m]"] + N_p = a_p / (4 * pi * R_p**2) + if self.x_average: + c_p = variables["X-averaged positive particle concentration [mol.m-3]"] + T_p = variables["X-averaged positive electrode temperature [K]"] + else: + c_p = variables["Positive particle concentration [mol.m-3]"] + T_p = variables["Positive electrode temperature [K]"] + T_p_part = pybamm.PrimaryBroadcast(T_p, ["positive particle"]) + dc_p_dr2 = pybamm.inner(pybamm.grad(c_p), pybamm.grad(c_p)) + D_p = param.p.prim.D(c_p, T_p_part) + dUeq_p = param.p.prim.dUdsto(c_p / param.p.prim.c_max, T_p_part) + integrand_r_p = D_p * dc_p_dr2 * dUeq_p / param.p.prim.c_max + integration_variable_r_p = [ + pybamm.SpatialVariable("r", domain=integrand_r_p.domain) + ] + integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) + Q_mix_s_p = F * N_p * integral_r_p + Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") + else: + Q_mix_s_n = pybamm.FullBroadcast( + 0, ["negative electrode"], "current collector" + ) + Q_mix_s_p = pybamm.FullBroadcast( + 0, ["positive electrode"], "current collector" + ) + Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") + + return Q_mix_s_n, Q_mix_s_s, Q_mix_s_p def _x_average(self, var, var_cn, var_cp): """ From 8380ec45037148ff33522c3b7561ee649cdaa8a7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 15:29:52 +0000 Subject: [PATCH 32/43] style: pre-commit fixes --- pybamm/models/submodels/thermal/base_thermal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 96ce458947..10bf2d4729 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -255,7 +255,7 @@ def _heat_of_mixing(self, variables): ] integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) Q_mix_s_n = F * N_n * integral_r_n - + # Compute heat of mixing in positive electrode a_p = variables["Positive electrode surface area to volume ratio [m-1]"] R_p = variables["Positive particle radius [m]"] From 76bae0626d927efaff37a5cfaab6b53ddc7431ca Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Thu, 1 Jun 2023 16:20:06 +0100 Subject: [PATCH 33/43] Add Richardson2021 citation for heat of mixing --- pybamm/CITATIONS.txt | 11 +++++++++++ pybamm/models/submodels/thermal/base_thermal.py | 3 +++ 2 files changed, 14 insertions(+) diff --git a/pybamm/CITATIONS.txt b/pybamm/CITATIONS.txt index 546f91f0a1..6dbbe2b4b6 100644 --- a/pybamm/CITATIONS.txt +++ b/pybamm/CITATIONS.txt @@ -420,6 +420,17 @@ doi = {10.1016/j.electacta.2020.135862}, } +@article{Richardson2021, + title = {Heat Generation and a Conservation Law for Chemical Energy in Li-ion Batteries}, + author = {Richardson, Giles and Korotkin, Ivan}, + journal = {Electrochimica Acta}, + volume = {392}, + pages = {138909}, + year = {2021}, + publisher = {Elsevier}, + doi = {10.1016/j.electacta.2021.138909}, +} + @article{Sripad2020, title={Kinetics of lithium electrodeposition and stripping}, author={Sripad, Shashank and Korff, Daniel and DeCaluwe, Steven C and Viswanathan, Venkatasubramanian}, diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index 10bf2d4729..f8e8ed585e 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -21,6 +21,9 @@ def __init__(self, param, options=None, x_average=False): super().__init__(param, options=options) self.x_average = x_average + if self.options["heat of mixing"] == "true": + pybamm.citations.register("Richardson2021") + def _get_standard_fundamental_variables(self, T_dict): """ Note: here we explicitly pass in the averages for the temperature as computing From bb6134e30f043d9ae9b1777b84b7e1191c4db205 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Fri, 2 Jun 2023 16:16:01 +0100 Subject: [PATCH 34/43] Fixed heat of mixing sign --- pybamm/models/submodels/thermal/base_thermal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index f8e8ed585e..21255594dd 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -257,7 +257,7 @@ def _heat_of_mixing(self, variables): pybamm.SpatialVariable("r", domain=integrand_r_n.domain) ] integral_r_n = pybamm.Integral(integrand_r_n, integration_variable_r_n) - Q_mix_s_n = F * N_n * integral_r_n + Q_mix_s_n = -F * N_n * integral_r_n # Compute heat of mixing in positive electrode a_p = variables["Positive electrode surface area to volume ratio [m-1]"] @@ -278,7 +278,7 @@ def _heat_of_mixing(self, variables): pybamm.SpatialVariable("r", domain=integrand_r_p.domain) ] integral_r_p = pybamm.Integral(integrand_r_p, integration_variable_r_p) - Q_mix_s_p = F * N_p * integral_r_p + Q_mix_s_p = -F * N_p * integral_r_p Q_mix_s_s = pybamm.FullBroadcast(0, ["separator"], "current collector") else: Q_mix_s_n = pybamm.FullBroadcast( From 442f2d47f01dd30b5b14c6ab974aa79f29fa4020 Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Sat, 3 Jun 2023 15:20:16 +0100 Subject: [PATCH 35/43] Rewritten heat of mixing example, added comparison plot to compare with the paper --- .../compare_lithium_ion_heat_of_mixing.py | 89 +++++++++++++++++-- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index 9eab53c0a6..3e5b66f321 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -1,26 +1,100 @@ # -# Compare DFN model with and without heat of mixing +# Compare SPMe model with and without heat of mixing # import pybamm +import numpy as np +import matplotlib.pyplot as plt pybamm.set_logging_level("INFO") + # load models models = [ pybamm.lithium_ion.SPMe( - {"heat of mixing": "true", "thermal": "lumped"}, name="with heat of mixing" + {"heat of mixing": "true", "thermal": "lumped"}, name="SPMe with heat of mixing" ), - pybamm.lithium_ion.DFN({"thermal": "lumped"}, name="without heat of mixing"), + pybamm.lithium_ion.SPMe({"thermal": "lumped"}, name="SPMe without heat of mixing"), ] -parameter_values = pybamm.ParameterValues("Chen2020") +# set parametrisation (Ecker et al., 2015) +parameter_values = pybamm.ParameterValues("Ecker2015") + +# set mesh (increased number of points in particles to avoid oscillations for high C-rates) +var_pts = {"x_n": 16, "x_s": 8, "x_p": 16, "r_n": 128, "r_p": 128} + +# set the constant current discharge C-rate +C_rate = 5 + +# set the simulation time and increase the number of points for better integration in time +t_eval = np.linspace(0, 720, 360) + +# set up an extra plot with the heat of mixing vs time in each electrode and +# the integrated heat of mixing vs time in each electrode to compare with +# Figure 6(a) from Richardson et al. (2021) +fig, axs = plt.subplots(2, len(models), figsize=(12, 7)) + +# extract some of the parameters +L_n = parameter_values["Negative electrode thickness [m]"] +L_p = parameter_values["Positive electrode thickness [m]"] +A = parameter_values["Electrode width [m]"] * parameter_values["Electrode height [m]"] # create and run simulations sims = [] -for model in models: - sim = pybamm.Simulation(model, parameter_values=parameter_values) - sim.solve([0, 3600]) +for m, model in enumerate(models): + sim = pybamm.Simulation( + model, parameter_values=parameter_values, var_pts=var_pts, C_rate=C_rate + ) + sim.solve(t_eval) sims.append(sim) + # extract solution for plotting + sol = sim.solution + + # extract variables from the solution + time = sol["Time [h]"].entries + Q_mix = sol["Heat of mixing [W.m-3]"].entries + + # heat of mixing in negative and positive electrodes multiplied by the electrode width, + # represents the integral of heat of mixing term across the electrodes (W.m-2) + Q_mix_n = Q_mix[0, :] * L_n + Q_mix_p = Q_mix[-1, :] * L_p + + # heat of mixing integrals (J.m-2) + Q_mix_n_int = 0.0 + Q_mix_p_int = 0.0 + + # data for plotting + Q_mix_n_plt = [] + Q_mix_p_plt = [] + + # performs integration in time + for i, t in enumerate(time[1:]): + dt = (t - time[i]) * 3600 # seconds + Q_mix_n_avg = (Q_mix_n[i] + Q_mix_n[i + 1]) * 0.5 + Q_mix_p_avg = (Q_mix_p[i] + Q_mix_p[i + 1]) * 0.5 + # convert J to kJ and divide the integral by the electrode area A to compare with + # Figure 6(a) from Richardson et al. (2021) + Q_mix_n_int += Q_mix_n_avg * dt / 1000 / A + Q_mix_p_int += Q_mix_p_avg * dt / 1000 / A + Q_mix_n_plt.append(Q_mix_n_int) + Q_mix_p_plt.append(Q_mix_p_int) + + # plots heat of mixing in each electrode vs time in minutes + axs[0, m].plot(time * 60, Q_mix_n, ls="-", label="Negative electrode") + axs[0, m].plot(time * 60, Q_mix_p, ls="--", label="Positive electrode") + axs[0, m].set_title(f"{model.name}") + axs[0, m].set_xlabel("Time [min]") + axs[0, m].set_ylabel("Heat of mixing [W.m-2]") + axs[0, m].grid(True) + axs[0, m].legend() + + # plots integrated heat of mixing in each electrode vs time in minutes + axs[1, m].plot(time[1:] * 60, Q_mix_n_plt, ls="-", label=f"Negative electrode") + axs[1, m].plot(time[1:] * 60, Q_mix_p_plt, ls="--", label=f"Positive electrode") + axs[1, m].set_xlabel("Time [min]") + axs[1, m].set_ylabel("Integrated heat of mixing [kJ.m-2]") + axs[1, m].grid(True) + axs[1, m].legend() + # plot pybamm.dynamic_plot( sims, @@ -28,6 +102,7 @@ "X-averaged cell temperature [K]", "X-averaged heat of mixing [W.m-3]", "X-averaged total heating [W.m-3]", + "Heat of mixing [W.m-3]", "Voltage [V]", "Current [A]", ], From cfaf2c0bf5484ec20abc68936c7f6db38f20e65a Mon Sep 17 00:00:00 2001 From: Ivan Korotkin Date: Sat, 3 Jun 2023 16:31:32 +0100 Subject: [PATCH 36/43] Fixed ruff formatting errors in the heat of mixing example script --- .../compare_lithium_ion_heat_of_mixing.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/scripts/compare_lithium_ion_heat_of_mixing.py b/examples/scripts/compare_lithium_ion_heat_of_mixing.py index 3e5b66f321..455f5b1e8b 100644 --- a/examples/scripts/compare_lithium_ion_heat_of_mixing.py +++ b/examples/scripts/compare_lithium_ion_heat_of_mixing.py @@ -18,13 +18,15 @@ # set parametrisation (Ecker et al., 2015) parameter_values = pybamm.ParameterValues("Ecker2015") -# set mesh (increased number of points in particles to avoid oscillations for high C-rates) +# set mesh +# (increased number of points in particles to avoid oscillations for high C-rates) var_pts = {"x_n": 16, "x_s": 8, "x_p": 16, "r_n": 128, "r_p": 128} # set the constant current discharge C-rate C_rate = 5 -# set the simulation time and increase the number of points for better integration in time +# set the simulation time and increase the number of points +# for better integration in time t_eval = np.linspace(0, 720, 360) # set up an extra plot with the heat of mixing vs time in each electrode and @@ -53,8 +55,9 @@ time = sol["Time [h]"].entries Q_mix = sol["Heat of mixing [W.m-3]"].entries - # heat of mixing in negative and positive electrodes multiplied by the electrode width, - # represents the integral of heat of mixing term across the electrodes (W.m-2) + # heat of mixing in negative and positive electrodes multiplied by the electrode + # width, represents the integral of heat of mixing term across each of the + # electrodes (W.m-2) Q_mix_n = Q_mix[0, :] * L_n Q_mix_p = Q_mix[-1, :] * L_p @@ -71,8 +74,8 @@ dt = (t - time[i]) * 3600 # seconds Q_mix_n_avg = (Q_mix_n[i] + Q_mix_n[i + 1]) * 0.5 Q_mix_p_avg = (Q_mix_p[i] + Q_mix_p[i + 1]) * 0.5 - # convert J to kJ and divide the integral by the electrode area A to compare with - # Figure 6(a) from Richardson et al. (2021) + # convert J to kJ and divide the integral by the electrode area A to compare + # with Figure 6(a) from Richardson et al. (2021) Q_mix_n_int += Q_mix_n_avg * dt / 1000 / A Q_mix_p_int += Q_mix_p_avg * dt / 1000 / A Q_mix_n_plt.append(Q_mix_n_int) @@ -88,8 +91,8 @@ axs[0, m].legend() # plots integrated heat of mixing in each electrode vs time in minutes - axs[1, m].plot(time[1:] * 60, Q_mix_n_plt, ls="-", label=f"Negative electrode") - axs[1, m].plot(time[1:] * 60, Q_mix_p_plt, ls="--", label=f"Positive electrode") + axs[1, m].plot(time[1:] * 60, Q_mix_n_plt, ls="-", label="Negative electrode") + axs[1, m].plot(time[1:] * 60, Q_mix_p_plt, ls="--", label="Positive electrode") axs[1, m].set_xlabel("Time [min]") axs[1, m].set_ylabel("Integrated heat of mixing [kJ.m-2]") axs[1, m].grid(True) From 65d4a086bc3e3a9eaf76da204a45151c212a9ccd Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Fri, 15 Sep 2023 13:38:56 +0100 Subject: [PATCH 37/43] #1778 fix x-full --- pybamm/models/submodels/thermal/pouch_cell/x_full.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pybamm/models/submodels/thermal/pouch_cell/x_full.py b/pybamm/models/submodels/thermal/pouch_cell/x_full.py index 64a6e687c6..a29035139a 100644 --- a/pybamm/models/submodels/thermal/pouch_cell/x_full.py +++ b/pybamm/models/submodels/thermal/pouch_cell/x_full.py @@ -24,8 +24,8 @@ class OneDimensionalX(BaseThermal): """ - def __init__(self, param, options=None): - super().__init__(param, options=options) + def __init__(self, param, options=None, x_average=False): + super().__init__(param, options=options, x_average=x_average) pybamm.citations.register("Timms2021") def get_fundamental_variables(self): From d89429738c3dbd71d82c4609f867e261af82cf3e Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Mon, 17 Jun 2024 15:50:02 +0100 Subject: [PATCH 38/43] #1778 fix tests --- .../test_lithium_ion/base_lithium_ion_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4340c53dae..7d190875a6 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 @@ -91,7 +91,7 @@ def test_well_posed_2plus1D_hom(self): self.check_well_posedness(options) def test_well_posed_lumped_thermal_model_1D_hom(self): - options = {"thermal": "x-lumped", "heat of mixing": "true"} + options = {"thermal": "lumped", "heat of mixing": "true"} self.check_well_posedness(options) def test_well_posed_x_full_thermal_model_hom(self): From f1605bdf1b4a54056f434a3f52a46db10dec1894 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Mon, 17 Jun 2024 16:23:17 +0100 Subject: [PATCH 39/43] #1778 improve coverage --- .../test_base_battery_model.py | 11 ++++++++++- .../base_lithium_ion_half_cell_tests.py | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) 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 c587cb6aaf..e35dd2fd7c 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 @@ -373,7 +373,16 @@ def test_options(self): "working electrode": "positive", } ) - + + # thermal heat of mixing + with self.assertRaisesRegex(pybamm.OptionError, "Heat of mixing"): + pybamm.BaseBatteryModel( + { + "heat of mixing": "true", + "particle size": "distribution", + } + ) + # 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_half_cell_tests.py b/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_half_cell_tests.py index 24ccd55d79..50fac7a04e 100644 --- a/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_half_cell_tests.py +++ b/tests/unit/test_models/test_full_battery_models/test_lithium_ion/base_lithium_ion_half_cell_tests.py @@ -82,3 +82,7 @@ def test_well_posed_asymmetric_ec_reaction_limited_sei(self): def test_well_posed_lumped_thermal(self): options = {"thermal": "lumped"} self.check_well_posedness(options) + + def test_well_posed_lumped_thermal_hom(self): + options = {"thermal": "lumped", "heat of mixing": "true"} + self.check_well_posedness(options) From 58184585864632a9f7d6d2788e24295a0198e12b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 15:23:31 +0000 Subject: [PATCH 40/43] style: pre-commit fixes --- .../test_full_battery_models/test_base_battery_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e35dd2fd7c..e495d409d5 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 @@ -373,7 +373,7 @@ def test_options(self): "working electrode": "positive", } ) - + # thermal heat of mixing with self.assertRaisesRegex(pybamm.OptionError, "Heat of mixing"): pybamm.BaseBatteryModel( @@ -382,7 +382,7 @@ def test_options(self): "particle size": "distribution", } ) - + # phases with self.assertRaisesRegex(pybamm.OptionError, "multiple particle phases"): pybamm.BaseBatteryModel({"particle phases": "2", "surface form": "false"}) From 8ab206a0d593b14cefca6c64202b84a5b2207095 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Mon, 17 Jun 2024 16:47:34 +0100 Subject: [PATCH 41/43] #1778 Valentin's suggestion to remove the dUdsto function and compute the derivative in the model directly instead --- .../models/submodels/thermal/base_thermal.py | 8 ++--- pybamm/parameters/lithium_ion_parameters.py | 31 ------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/pybamm/models/submodels/thermal/base_thermal.py b/pybamm/models/submodels/thermal/base_thermal.py index dbf535765e..c5ebbc7dbd 100644 --- a/pybamm/models/submodels/thermal/base_thermal.py +++ b/pybamm/models/submodels/thermal/base_thermal.py @@ -340,8 +340,8 @@ def _heat_of_mixing(self, variables): T_n_part = pybamm.PrimaryBroadcast(T_n, ["negative particle"]) dc_n_dr2 = pybamm.inner(pybamm.grad(c_n), pybamm.grad(c_n)) D_n = param.n.prim.D(c_n, T_n_part) - dUeq_n = param.n.prim.dUdsto(c_n / param.n.prim.c_max, T_n_part) - integrand_r_n = D_n * dc_n_dr2 * dUeq_n / param.n.prim.c_max + dUeq_n = param.n.prim.U(c_n / param.n.prim.c_max, T_n_part).diff(c_n) + integrand_r_n = D_n * dc_n_dr2 * dUeq_n integration_variable_r_n = [ pybamm.SpatialVariable("r", domain=integrand_r_n.domain) ] @@ -361,8 +361,8 @@ def _heat_of_mixing(self, variables): T_p_part = pybamm.PrimaryBroadcast(T_p, ["positive particle"]) dc_p_dr2 = pybamm.inner(pybamm.grad(c_p), pybamm.grad(c_p)) D_p = param.p.prim.D(c_p, T_p_part) - dUeq_p = param.p.prim.dUdsto(c_p / param.p.prim.c_max, T_p_part) - integrand_r_p = D_p * dc_p_dr2 * dUeq_p / param.p.prim.c_max + dUeq_p = param.p.prim.U(c_p / param.p.prim.c_max, T_p_part).diff(c_p) + integrand_r_p = D_p * dc_p_dr2 * dUeq_p integration_variable_r_p = [ pybamm.SpatialVariable("r", domain=integrand_r_p.domain) ] diff --git a/pybamm/parameters/lithium_ion_parameters.py b/pybamm/parameters/lithium_ion_parameters.py index 48811d9622..f5a76c6d48 100644 --- a/pybamm/parameters/lithium_ion_parameters.py +++ b/pybamm/parameters/lithium_ion_parameters.py @@ -658,37 +658,6 @@ def U(self, sto, T, lithiation=None): out.print_name = r"U_\mathrm{p}(c^\mathrm{surf}_\mathrm{s,p}, T)" return out - def dUdsto(self, sto, T, lithiation=None): - """ - Dimensional derivative of the open-circuit potential with respect to the - stoichiometry [V] - """ - domain, Domain = self.domain_Domain - tol = pybamm.settings.tolerances["U__c_s"] - sto = pybamm.maximum(pybamm.minimum(sto, 1 - tol), tol) - if lithiation is None: - lithiation = "" - else: - lithiation = lithiation + " " - - u_ref = pybamm.FunctionParameter( - f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", - {f"{self.phase_prefactor}{Domain} particle stoichiometry": sto}, - diff_variable=sto, - ) - - dudt = pybamm.FunctionParameter( - f"{self.phase_prefactor}{Domain} electrode OCP entropic change [V.K-1]", - { - f"{Domain} particle stoichiometry": sto, - f"{self.phase_prefactor}Maximum {domain} particle " - "surface concentration [mol.m-3]": self.c_max, - }, - diff_variable=sto, - ) - - return u_ref + (T - self.main_param.T_ref) * dudt - def dUdT(self, sto): """ Dimensional entropic change of the open-circuit potential [V.K-1]. From accde29a6dc14c60e87378b79f361aa6d4ad0e5d Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Mon, 17 Jun 2024 16:54:20 +0100 Subject: [PATCH 42/43] #1778 fix failing test --- .../test_full_battery_models/test_base_battery_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e35dd2fd7c..d2ec0b4472 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 @@ -375,7 +375,7 @@ def test_options(self): ) # thermal heat of mixing - with self.assertRaisesRegex(pybamm.OptionError, "Heat of mixing"): + with self.assertRaisesRegex(NotImplementedError, "Heat of mixing"): pybamm.BaseBatteryModel( { "heat of mixing": "true", From a1b05bde31983d3c7494910f21472897819136a2 Mon Sep 17 00:00:00 2001 From: Ferran Brosa Planella Date: Mon, 17 Jun 2024 16:56:34 +0100 Subject: [PATCH 43/43] #1778 add heat of mixing to CHANGELOG --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae4616a2d4..1faf9a8ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - Added new parameters `"f{pref]Initial inner SEI on cracks thickness [m]"` and `"f{pref]Initial outer SEI on cracks thickness [m]"`, instead of hardcoding these to `L_inner_0 / 10000` and `L_outer_0 / 10000`. ([#4168](https://github.com/pybamm-team/PyBaMM/pull/4168)) - Added `pybamm.DataLoader` class to fetch data files from [pybamm-data](https://github.com/pybamm-team/pybamm-data/releases/tag/v1.0.0) and store it under local cache. ([#4098](https://github.com/pybamm-team/PyBaMM/pull/4098)) -- Transport efficiency submodel has new options from the literature relating to different tortuosity factor models and also a new option called "tortuosity factor" for specifying the value or function directly as parameters ([#3437](https://github.com/pybamm-team/PyBaMM/pull/3437)) +- Added `time` as an option for `Experiment.termination`. Now allows solving up to a user-specified time while also allowing different cycles and steps in an experiment to be handled normally. ([#4073](https://github.com/pybamm-team/PyBaMM/pull/4073)) - Added `plot_thermal_components` to plot the contributions to the total heat generation in a battery ([#4021](https://github.com/pybamm-team/PyBaMM/pull/4021)) - Added functions for normal probability density function (`pybamm.normal_pdf`) and cumulative distribution function (`pybamm.normal_cdf`) ([#3999](https://github.com/pybamm-team/PyBaMM/pull/3999)) - "Basic" models are now compatible with experiments ([#3995](https://github.com/pybamm-team/PyBaMM/pull/3995)) @@ -20,7 +20,8 @@ - Add support for BPX version 0.4.0 which allows for blended electrodes and user-defined parameters in BPX([#3414](https://github.com/pybamm-team/PyBaMM/pull/3414)) - Added `by_submodel` feature in `print_parameter_info` method to allow users to print parameters and types of submodels in a tabular and readable format ([#3628](https://github.com/pybamm-team/PyBaMM/pull/3628)) - Added `WyciskOpenCircuitPotential` for differential capacity hysteresis state open-circuit potential submodel ([#3593](https://github.com/pybamm-team/PyBaMM/pull/3593)) -- Added `time` as an option for `Experiment.termination`. Now allows solving up to a user-specified time while also allowing different cycles and steps in an experiment to be handled normally. ([#4073](https://github.com/pybamm-team/PyBaMM/pull/4073)) +- Transport efficiency submodel has new options from the literature relating to different tortuosity factor models and also a new option called "tortuosity factor" for specifying the value or function directly as parameters ([#3437](https://github.com/pybamm-team/PyBaMM/pull/3437)) +- Heat of mixing source term can now be included into thermal models ([#2837](https://github.com/pybamm-team/PyBaMM/pull/2837)) ## Bug Fixes