Source code for pybamm.models.submodels.active_material.loss_active_material
#
# Class for varying active material volume fraction
#
import pybamm
from .base_active_material import BaseModel
[docs]
class LossActiveMaterial(BaseModel):
"""Submodel for varying active material volume fraction from :footcite:t:`Ai2019`
and :footcite:t:`Reniers2019`.
Parameters
----------
param : parameter class
The parameters to use for this submodel
domain : str
The domain of the model either 'Negative' or 'Positive'
options : dict
Additional options to pass to the model
x_average : bool
Whether to use x-averaged variables (SPM, SPMe, etc) or full variables (DFN)
"""
def __init__(self, param, domain, options, x_average, phase):
super().__init__(param, domain, options=options, phase=phase)
pybamm.citations.register("Reniers2019")
self.x_average = x_average
[docs]
def get_fundamental_variables(self):
domain, Domain = self.domain_Domain
phase = self.phase_name
if self.x_average is True:
eps_solid_xav = pybamm.Variable(
f"X-averaged {domain} electrode {phase}active material volume fraction",
domain="current collector",
)
eps_solid = pybamm.PrimaryBroadcast(eps_solid_xav, f"{domain} electrode")
else:
eps_solid = pybamm.Variable(
f"{Domain} electrode {phase}active material volume fraction",
domain=f"{domain} electrode",
auxiliary_domains={"secondary": "current collector"},
)
variables = self._get_standard_active_material_variables(eps_solid)
lli_due_to_lam = pybamm.Variable(
f"Loss of lithium due to loss of {phase}active material "
f"in {domain} electrode [mol]"
)
variables.update(
{
f"Loss of lithium due to loss of {phase}active material "
f"in {domain} electrode [mol]": lli_due_to_lam
}
)
return variables
[docs]
def get_coupled_variables(self, variables):
domain, Domain = self.domain_Domain
phase_name = self.phase_name
deps_solid_dt = 0
lam_option = getattr(getattr(self.options, domain), self.phase)[
"loss of active material"
]
if "stress" in lam_option:
# obtain the rate of loss of active materials (LAM) by stress
# This is loss of active material model by mechanical effects
stress_critical = self.phase_param.stress_critical
m_LAM = self.phase_param.m_LAM
if self.x_average is True:
stress_t_surf = variables[
f"X-averaged {domain} {phase_name}particle surface tangential stress [Pa]"
]
stress_r_surf = variables[
f"X-averaged {domain} {phase_name}particle surface radial stress [Pa]"
]
T = variables[f"X-averaged {domain} electrode temperature [K]"]
else:
stress_t_surf = variables[
f"{Domain} {phase_name}particle surface tangential stress [Pa]"
]
stress_r_surf = variables[
f"{Domain} {phase_name}particle surface radial stress [Pa]"
]
T = variables[f"{Domain} electrode temperature [K]"]
# compute hydrostatic stress
stress_h_surf = (stress_r_surf + 2 * stress_t_surf) / 3
# separate compressive and tensile stresses
stress_h_surf_compressive = stress_h_surf * (stress_h_surf < 0)
stress_h_surf_tensile = stress_h_surf * (stress_h_surf > 0)
if "asymmetric stress" in lam_option:
pybamm.citations.register("Pannala2024")
# semi-empirical model for stress-driven LAM that includes both
# compressive and tensile stresses
beta_LAM_compressive = self.phase_param.beta_LAM(
T, direction="compressive"
)
beta_LAM_tensile = self.phase_param.beta_LAM(T, direction="tensile")
j_stress_LAM = (
-beta_LAM_compressive
* (abs(stress_h_surf_compressive) / stress_critical) ** m_LAM
- beta_LAM_tensile
* (abs(stress_h_surf_tensile) / stress_critical) ** m_LAM
)
else:
beta_LAM = self.phase_param.beta_LAM(T)
# assuming that only tensile stress contributes and that the minimum
# (tensile) hydrostatic stress is zero for full cycles
stress_h_surf_min = stress_h_surf * 0
j_stress_LAM = (
-beta_LAM
* ((stress_h_surf_tensile - stress_h_surf_min) / stress_critical)
** m_LAM
)
deps_solid_dt += j_stress_LAM
if "reaction" in lam_option:
beta_LAM_sei = self.phase_param.beta_LAM_sei
if self.x_average is True:
a_j_sei = variables[
f"X-averaged {domain} electrode {phase_name}SEI "
"volumetric interfacial current density [A.m-3]"
]
else:
a_j_sei = variables[
f"{Domain} electrode {phase_name}SEI volumetric "
"interfacial current density [A.m-3]"
]
j_stress_reaction = beta_LAM_sei * a_j_sei / self.param.F
deps_solid_dt += j_stress_reaction
if "current" in lam_option:
# obtain the rate of loss of active materials (LAM) driven by current
if self.x_average is True:
T = variables[f"X-averaged {domain} electrode temperature [K]"]
else:
T = variables[f"{Domain} electrode temperature [K]"]
j_current_LAM = self.domain_param.LAM_rate_current(
self.param.current_density_with_time, T
)
deps_solid_dt += j_current_LAM
variables.update(
self._get_standard_active_material_change_variables(deps_solid_dt)
)
return variables
[docs]
def set_rhs(self, variables):
domain, Domain = self.domain_Domain
phase_name = self.phase_name
if self.x_average is True:
eps_solid = variables[
f"X-averaged {domain} electrode {phase_name}active material volume fraction"
]
deps_solid_dt = variables[
f"X-averaged {domain} electrode {phase_name}active material "
"volume fraction change [s-1]"
]
else:
eps_solid = variables[
f"{Domain} electrode {phase_name}active material volume fraction"
]
deps_solid_dt = variables[
f"{Domain} electrode {phase_name}active material volume fraction change [s-1]"
]
# Loss of lithium due to loss of active material
# See eq 37 in "Sulzer, Valentin, et al. "Accelerated battery lifetime
# simulations using adaptive inter-cycle extrapolation algorithm."
# Journal of The Electrochemical Society 168.12 (2021): 120531.
lli_due_to_lam = variables[
f"Loss of lithium due to loss of {phase_name}active material "
f"in {domain} electrode [mol]"
]
# Multiply by mol.m-3 * m3 to get mol
c_s_rav = variables[
f"R-averaged {domain} {phase_name}particle concentration [mol.m-3]"
]
V = self.domain_param.L * self.param.A_cc
self.rhs = {
# minus sign because eps_solid is decreasing and LLI measures positive
lli_due_to_lam: -V * pybamm.x_average(c_s_rav * deps_solid_dt),
eps_solid: deps_solid_dt,
}
[docs]
def set_initial_conditions(self, variables):
domain, Domain = self.domain_Domain
phase_name = self.phase_name
eps_solid_init = self.phase_param.epsilon_s
if self.x_average is True:
eps_solid_xav = variables[
f"X-averaged {domain} electrode {phase_name}active material volume fraction"
]
self.initial_conditions = {eps_solid_xav: pybamm.x_average(eps_solid_init)}
else:
eps_solid = variables[
f"{Domain} electrode {phase_name}active material volume fraction"
]
self.initial_conditions = {eps_solid: eps_solid_init}
lli_due_to_lam = variables[
f"Loss of lithium due to loss of {phase_name}active material "
f"in {domain} electrode [mol]"
]
self.initial_conditions[lli_due_to_lam] = pybamm.Scalar(0)