Source code for mtnlion.models.lithium_plating

"""
Isothermal model extended with lithium plating
"""
import dolfin as fem
import ufl  # type: ignore

from mtnlion.formula import Formula
from mtnlion.formulas.dfn import CapacityLoss, FilmResistance, FilmThickness
from mtnlion.models.isothermal import Isothermal
from mtnlion.variable import Variable

# pylint: disable=invalid-name


[docs]class LithiumPlating(Isothermal): """ Lithium plating often occurs when the manufacturer-specified upper voltage on the cell is not observed, which can cause a cell to become inoperable within a few overcharge events. """ def __init__(self, Ns): super(LithiumPlating, self).__init__(Ns) self.variables += [Variable("j_s", ["anode"]), Variable("delta_film", ["anode"]), Variable("Q", ["anode"])] self.formulas += [ self.SideReactionFlux(), self.SideReactionExchangeCurrentDensity(), self.SideReactionOverpotential(), FilmThickness(), FilmResistance(), CapacityLoss(), ]
[docs] class Overpotential(Formula): # Override """ Voltage difference between a reduction potential and the potential of the redox event. """ def __init__(self): super(LithiumPlating.Overpotential, self).__init__(name="eta", domains=["anode", "cathode"]) self.Variables = self.typedef("Variables", "phi_s, phi_e, j") self.Parameters = self.typedef("Parameters", "F, Uocp, Rfilm")
[docs] def form(self, arguments, domain): phis, phie, j = arguments.variables (F, Uocp, Rfilm) = arguments.parameters if domain == "cathode": Rfilm = 0 return phis - phie - Uocp - F * Rfilm * j
[docs] class SideReactionFlux(Formula): """ Describes how the electrical current on an electrode depends on the electrode potential due to the side reaction. """ def __init__(self): super(LithiumPlating.SideReactionFlux, self).__init__(domains=["anode"]) self.Variables = self.typedef("Variables", "j_s") self.Parameters = self.typedef("Parameters", "alpha_s, F, R, T, eta_s, io_s")
[docs] def form(self, arguments, domain): """Flux through the boundary of the solid.""" (js,) = arguments.variables alpha_s, F, R, T, eta_s, io_s = arguments.parameters return ( js.trial(0) - ufl.min_value( 0, io_s / F * (fem.exp((1 - alpha_s) * F * eta_s / (R * T)) - fem.exp(-alpha_s * F * eta_s / (R * T))), ) ) * js.test()
[docs] class SideReactionExchangeCurrentDensity(Formula): """ The current in the absence of net electrolysis and at zero overpotential in the side reaction. """ def __init__(self): super(LithiumPlating.SideReactionExchangeCurrentDensity, self).__init__(name="io_s", domains=["anode"]) self.Variables = self.typedef("Variables", "c_e") self.Parameters = self.typedef("Parameters", "alpha_s, k_norm_ref")
[docs] def form(self, arguments, domain): (ce,) = arguments.variables alpha_s, k_norm_ref = arguments.parameters return k_norm_ref * ce ** alpha_s
[docs] class SideReactionOverpotential(Formula): """ Voltage difference between a reduction potential and the potential of the redox event in the side reaction. """ def __init__(self): super(LithiumPlating.SideReactionOverpotential, self).__init__(name="eta_s", domains=["anode"]) self.Variables = self.typedef("Variables", "phi_s, phi_e, j_s") self.Parameters = self.typedef("Parameters", "Uref_s, F, Rfilm")
[docs] def form(self, arguments, domain): phis, phie, js = arguments.variables Uref_s, F, Rfilm = arguments.parameters return phis - phie - Uref_s - F * Rfilm * js