Source code for pybamm.models.submodels.particle_mechanics.crack_propagation

#
# Class for cracking
#
import numpy as np

import pybamm

from .base_mechanics import BaseMechanics


[docs] class CrackPropagation(BaseMechanics): """ Cracking behaviour in electrode particles. See :footcite:t:`Ai2019` for mechanical model (thickness change) and :footcite:t:`Deshpande2012` for cracking model. Parameters ---------- param : parameter class The parameters to use for this submodel domain : str The domain of the model either 'Negative' or 'Positive' x_average : bool Whether to use x-averaged variables (SPM, SPMe, etc) or full variables (DFN) options: dict A dictionary of options to be passed to the model. See :class:`pybamm.BaseBatteryModel` phase : str, optional Phase of the particle (default is "primary") """ def __init__(self, param, domain, x_average, options, phase="primary"): super().__init__(param, domain, options, phase) self.x_average = x_average pybamm.citations.register("Ai2019") pybamm.citations.register("Deshpande2012")
[docs] def get_fundamental_variables(self): domain, Domain = self.domain_Domain phase_name = self.phase_param.phase_name if self.x_average: if self.size_distribution: l_cr_av_dist = pybamm.Variable( f"X-averaged {domain} {phase_name}particle crack length distribution [m]", domains={ "primary": f"{domain} particle size", "secondary": "current collector", }, scale=self.phase_param.l_cr_0, ) l_cr_dist = pybamm.SecondaryBroadcast( l_cr_av_dist, f"{domain} electrode" ) l_cr_av = pybamm.size_average(l_cr_av_dist) else: l_cr_av = pybamm.Variable( f"X-averaged {domain} {phase_name}particle crack length [m]", domain="current collector", scale=self.phase_param.l_cr_0, ) l_cr = pybamm.PrimaryBroadcast(l_cr_av, f"{domain} electrode") else: if self.size_distribution: l_cr_dist = pybamm.Variable( f"{Domain} {phase_name}particle crack length distribution [m]", domains={ "primary": f"{domain} particle size", "secondary": f"{domain} electrode", "tertiary": "current collector", }, scale=self.phase_param.l_cr_0, ) l_cr = pybamm.size_average(l_cr_dist) else: l_cr = pybamm.Variable( f"{Domain} {phase_name}particle crack length [m]", domain=f"{domain} electrode", auxiliary_domains={"secondary": "current collector"}, scale=self.phase_param.l_cr_0, ) variables = self._get_standard_variables(l_cr) if self.size_distribution: variables.update(self._get_standard_size_distribution_variables(l_cr_dist)) return variables
[docs] def get_coupled_variables(self, variables): domain, Domain = self.domain_Domain phase_name = self.phase_param.phase_name variables.update(self._get_standard_surface_variables(variables)) variables.update(self._get_mechanical_results(variables)) if self.size_distribution: variables.update(self._get_mechanical_size_distribution_results(variables)) T = variables[f"{Domain} electrode temperature [K]"] k_cr = self.phase_param.k_cr(T) m_cr = self.phase_param.m_cr b_cr = self.phase_param.b_cr if self.size_distribution: stress_t_surf = variables[ f"{Domain} {phase_name}particle surface tangential stress distribution [Pa]" ] else: stress_t_surf = variables[ f"{Domain} {phase_name}particle surface tangential stress [Pa]" ] if self.size_distribution: l_cr = variables[ f"{Domain} {phase_name}particle crack length distribution [m]" ] else: l_cr = variables[f"{Domain} {phase_name}particle crack length [m]"] # # compressive stress will not lead to crack propagation dK_SIF = stress_t_surf * b_cr * pybamm.sqrt(np.pi * l_cr) * (stress_t_surf >= 0) dl_cr = k_cr * (dK_SIF**m_cr) / 3600 # divide by 3600 to replace t0_cr variables.update( { f"{Domain} {phase_name}particle cracking rate [m.s-1]": dl_cr, f"X-averaged {domain} {phase_name}particle cracking rate [m.s-1]": pybamm.x_average( dl_cr ), } ) return variables
[docs] def set_rhs(self, variables): domain, Domain = self.domain_Domain phase_name = self.phase_param.phase_name if self.x_average is True: if self.size_distribution: l_cr = variables[ f"X-averaged {domain} {phase_name}particle crack length distribution [m]" ] else: l_cr = variables[ f"X-averaged {domain} {phase_name}particle crack length [m]" ] dl_cr = variables[ f"X-averaged {domain} {phase_name}particle cracking rate [m.s-1]" ] else: if self.size_distribution: l_cr = variables[ f"{Domain} {phase_name}particle crack length distribution [m]" ] else: l_cr = variables[f"{Domain} {phase_name}particle crack length [m]"] dl_cr = variables[f"{Domain} {phase_name}particle cracking rate [m.s-1]"] self.rhs = {l_cr: dl_cr}
[docs] def set_initial_conditions(self, variables): domain, Domain = self.domain_Domain phase_name = self.phase_param.phase_name l_cr_0 = self.phase_param.l_cr_0 if self.x_average is True: if self.size_distribution: l_cr = variables[ f"X-averaged {domain} {phase_name}particle crack length distribution [m]" ] l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} particle size") else: l_cr = variables[ f"X-averaged {domain} {phase_name}particle crack length [m]" ] else: if self.size_distribution: l_cr = variables[ f"{Domain} {phase_name}particle crack length distribution [m]" ] l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} electrode") l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} particle size") else: l_cr = variables[f"{Domain} {phase_name}particle crack length [m]"] l_cr_0 = pybamm.PrimaryBroadcast(l_cr_0, f"{domain} electrode") self.initial_conditions = {l_cr: l_cr_0}
[docs] def add_events_from(self, variables): domain, Domain = self.domain_Domain phase_name = self.phase_param.phase_name if self.x_average is True: l_cr = variables[ f"X-averaged {domain} {phase_name}particle crack length [m]" ] else: l_cr = variables[f"{Domain} {phase_name}particle crack length [m]"] self.events.append( pybamm.Event( f"{domain} {phase_name} particle crack length larger than particle radius", 1 - pybamm.max(l_cr) / self.phase_param.R_typ, ) )