#
# Standard parameters for lithium-ion battery models
#
import pybamm
from .base_parameters import BaseParameters, NullParameters
[docs]
class LithiumIonParameters(BaseParameters):
"""
Standard parameters for lithium-ion battery models
Parameters
----------
options : dict, optional
A dictionary of options to be passed to the parameters, see
:class:`pybamm.BatteryModelOptions`.
"""
def __init__(self, options=None):
self.options = options
# Get geometric, electrical and thermal parameters
self.geo = pybamm.GeometricParameters(options)
self.elec = pybamm.electrical_parameters
self.therm = pybamm.thermal_parameters
# Initialize domain parameters
self.n = DomainLithiumIonParameters("negative", self)
self.s = DomainLithiumIonParameters("separator", self)
self.p = DomainLithiumIonParameters("positive", self)
self.domain_params = {
"negative": self.n,
"separator": self.s,
"positive": self.p,
}
# Set parameters
self._set_parameters()
def _set_parameters(self):
"""Defines the dimensional parameters"""
# Physical constants
self.R = pybamm.Parameter("Ideal gas constant [J.K-1.mol-1]")
self.F = pybamm.Parameter("Faraday constant [C.mol-1]")
self.k_b = pybamm.Parameter("Boltzmann constant [J.K-1]")
self.q_e = pybamm.Parameter("Elementary charge [C]")
# Thermal parameters
self.T_ref = self.therm.T_ref
self.T_init = self.therm.T_init
self.T_amb = self.therm.T_amb
self.T_amb_av = self.therm.T_amb_av
self.h_edge = self.therm.h_edge
self.h_total = self.therm.h_total
self.rho_c_p_eff = self.therm.rho_c_p_eff
self.lambda_eff = self.therm.lambda_eff
# Macroscale geometry
self.L_x = self.geo.L_x
self.L = self.geo.L
self.L_y = self.geo.L_y
self.L_z = self.geo.L_z
self.r_inner = self.geo.r_inner
self.r_outer = self.geo.r_outer
self.A_cc = self.geo.A_cc
self.A_cooling = self.geo.A_cooling
self.V_cell = self.geo.V_cell
# Electrical
self.current_with_time = self.elec.current_with_time
self.current_density_with_time = self.elec.current_density_with_time
self.Q = self.elec.Q
self.R_contact = self.elec.R_contact
self.n_electrodes_parallel = self.elec.n_electrodes_parallel
self.n_cells = self.elec.n_cells
self.voltage_low_cut = self.elec.voltage_low_cut
self.voltage_high_cut = self.elec.voltage_high_cut
self.ocp_soc_0 = self.elec.ocp_soc_0
self.ocp_soc_100 = self.elec.ocp_soc_100
# Domain parameters
for domain in self.domain_params.values():
domain._set_parameters()
# Electrolyte properties
self.epsilon_init = pybamm.concatenation(
*[
self.domain_params[domain.split()[0]].epsilon_init
for domain in self.options.whole_cell_domains
]
)
# Lithium plating parameters
self.V_bar_Li = pybamm.Parameter(
"Lithium metal partial molar volume [m3.mol-1]"
)
self.c_Li_typ = pybamm.Parameter(
"Typical plated lithium concentration [mol.m-3]"
)
self.c_plated_Li_0 = pybamm.Parameter(
"Initial plated lithium concentration [mol.m-3]"
)
self.alpha_plating = pybamm.Parameter("Lithium plating transfer coefficient")
self.alpha_stripping = 1 - self.alpha_plating
# Initial conditions
# Note: the initial concentration in the electrodes can be set as a function
# of through-cell position, so is defined later as a function
self.c_e_init = pybamm.Parameter(
"Initial concentration in electrolyte [mol.m-3]"
)
self.c_e_init_av = pybamm.xyz_average(self.c_e_init)
self.c_e_init_av.print_name = "c_e_init"
self.alpha_T_cell = pybamm.Parameter(
"Cell thermal expansion coefficient [m.K-1]"
)
# Total lithium
# Electrolyte
c_e_av_init = pybamm.xyz_average(self.epsilon_init) * self.c_e_init
self.n_Li_e_init = c_e_av_init * self.L_x * self.A_cc
self.n_Li_particles_init = self.n.n_Li_init + self.p.n_Li_init
self.n_Li_init = self.n_Li_particles_init + self.n_Li_e_init
self.Q_Li_particles_init = self.n_Li_particles_init * self.F / 3600
self.Q_Li_init = self.n_Li_init * self.F / 3600
# Reference OCP based on initial concentration
self.ocv_init = self.p.prim.U_init - self.n.prim.U_init
# Some scales
self.thermal_voltage = self.R * self.T_ref / self.F
self.I_typ = self.Q / (self.A_cc * self.n_electrodes_parallel)
self.a_j_scale = self.I_typ / self.L_x
def chi(self, c_e, T):
"""
Thermodynamic factor:
(1-2*t_plus) is for Nernst-Planck,
2*(1-t_plus) for Stefan-Maxwell,
see Bizeray et al (2016) "Resolving a discrepancy ...".
"""
return (2 * (1 - self.t_plus(c_e, T))) * (self.thermodynamic_factor(c_e, T))
def chiRT_over_Fc(self, c_e, T):
"""
chi * (1 + Theta * T) / c,
as it appears in the electrolyte potential equation
"""
tol = pybamm.settings.tolerances["chi__c_e"]
c_e = pybamm.maximum(c_e, tol)
return (self.R * T / self.F) * self.chi(c_e, T) / c_e
def t_plus(self, c_e, T):
"""Cation transference number"""
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Cation transference number", inputs)
def thermodynamic_factor(self, c_e, T):
"""Thermodynamic factor"""
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Thermodynamic factor", inputs)
def D_e(self, c_e, T):
"""Dimensional diffusivity in electrolyte"""
tol = pybamm.settings.tolerances["D_e__c_e"]
c_e = pybamm.maximum(c_e, tol)
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Electrolyte diffusivity [m2.s-1]", inputs)
def kappa_e(self, c_e, T):
"""Dimensional electrolyte conductivity"""
tol = pybamm.settings.tolerances["kappa_e__c_e"]
c_e = pybamm.maximum(c_e, tol)
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Electrolyte conductivity [S.m-1]", inputs)
def j0_Li_metal(self, c_e, c_Li, T):
"""Dimensional exchange-current density for lithium metal electrode [A.m-2]"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
"Lithium metal concentration [mol.m-3]": c_Li,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
"Exchange-current density for lithium metal electrode [A.m-2]", inputs
)
def j0_stripping(self, c_e, c_Li, T):
"""Dimensional exchange-current density for stripping [A.m-2]"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
"Plated lithium concentration [mol.m-3]": c_Li,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
"Exchange-current density for stripping [A.m-2]", inputs
)
def j0_plating(self, c_e, c_Li, T):
"""Dimensional exchange-current density for plating [A.m-2]"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
"Plated lithium concentration [mol.m-3]": c_Li,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
"Exchange-current density for plating [A.m-2]", inputs
)
def dead_lithium_decay_rate(self, L_sei):
"""Dimensional dead lithium decay rate [s-1]"""
inputs = {"Total SEI thickness [m]": L_sei}
return pybamm.FunctionParameter("Dead lithium decay rate [s-1]", inputs)
class DomainLithiumIonParameters(BaseParameters):
def __init__(self, domain, main_param):
self.domain = domain
self.main_param = main_param
self.geo = getattr(main_param.geo, domain[0])
self.therm = getattr(main_param.therm, domain[0])
if domain != "separator":
self.prim = ParticleLithiumIonParameters("primary", self)
phases_option = int(getattr(main_param.options, domain)["particle phases"])
if phases_option >= 2:
self.sec = ParticleLithiumIonParameters("secondary", self)
else:
self.sec = NullParameters()
else:
self.prim = NullParameters()
self.sec = NullParameters()
self.phase_params = {"primary": self.prim, "secondary": self.sec}
def _set_parameters(self):
main = self.main_param
domain, Domain = self.domain_Domain
# Parameters that appear in the separator
self.b_e = self.geo.b_e
self.L = self.geo.L
# Thermal
self.rho_c_p = self.therm.rho_c_p
self.lambda_ = self.therm.lambda_
self.h_cc = self.therm.h_cc
self.h_tab = self.therm.h_tab
if domain == "separator":
x = pybamm.standard_spatial_vars.x_s
self.epsilon_init = pybamm.FunctionParameter(
"Separator porosity", {"Through-cell distance (x) [m]": x}
)
self.epsilon_inactive = 1 - self.epsilon_init
return
self.rho_c_p_cc = self.therm.rho_c_p_cc
self.lambda_cc = self.therm.lambda_cc
x = pybamm.SpatialVariable(
f"x_{domain[0]}",
domain=[f"{domain} electrode"],
auxiliary_domains={"secondary": "current collector"},
coord_sys="cartesian",
)
# Macroscale geometry
self.L_cc = self.geo.L_cc
for phase in self.phase_params.values():
phase._set_parameters()
# Tab geometry (for pouch cells)
self.L_tab = self.geo.L_tab
self.centre_y_tab = self.geo.centre_y_tab
self.centre_z_tab = self.geo.centre_z_tab
self.A_tab = self.geo.A_tab
# Particle properties
self.sigma_cc = pybamm.Parameter(
f"{Domain} current collector conductivity [S.m-1]"
)
if main.options.electrode_types[domain] == "porous":
self.epsilon_init = pybamm.FunctionParameter(
f"{Domain} electrode porosity", {"Through-cell distance (x) [m]": x}
)
epsilon_s_tot = sum(phase.epsilon_s for phase in self.phase_params.values())
self.epsilon_inactive = 1 - self.epsilon_init - epsilon_s_tot
self.Q_init = sum(phase.Q_init for phase in self.phase_params.values())
# Use primary phase to set the reference potential
self.n_Li_init = sum(phase.n_Li_init for phase in self.phase_params.values())
self.Q_Li_init = sum(phase.Q_Li_init for phase in self.phase_params.values())
# Tortuosity parameters
self.b_s = self.geo.b_s
# Mechanical parameters
self.nu = pybamm.Parameter(f"{Domain} electrode Poisson's ratio")
self.c_0 = pybamm.Parameter(
f"{Domain} electrode reference concentration for free of deformation "
"[mol.m-3]"
)
self.l_cr_0 = pybamm.Parameter(f"{Domain} electrode initial crack length [m]")
self.w_cr = pybamm.Parameter(f"{Domain} electrode initial crack width [m]")
self.rho_cr = pybamm.Parameter(
f"{Domain} electrode number of cracks per unit area [m-2]"
)
self.b_cr = pybamm.Parameter(f"{Domain} electrode Paris' law constant b")
self.m_cr = pybamm.Parameter(f"{Domain} electrode Paris' law constant m")
# Loss of active material parameters
self.m_LAM = pybamm.Parameter(
f"{Domain} electrode LAM constant exponential term"
)
self.beta_LAM = pybamm.Parameter(
f"{Domain} electrode LAM constant proportional term [s-1]"
)
self.stress_critical = pybamm.Parameter(
f"{Domain} electrode critical stress [Pa]"
)
self.beta_LAM_sei = pybamm.Parameter(
f"{Domain} electrode reaction-driven LAM factor [m3.mol-1]"
)
# Utilisation parameters
self.u_init = pybamm.Parameter(
f"Initial {domain} electrode interface utilisation"
)
self.beta_utilisation = pybamm.Parameter(
f"{Domain} electrode current-driven interface utilisation factor [m3.mol-1]"
)
def C_dl(self, T):
"""Dimensional double-layer capacity [F.m-2]"""
inputs = {"Temperature [K]": T}
Domain = self.domain.capitalize()
return pybamm.FunctionParameter(
f"{Domain} electrode double-layer capacity [F.m-2]", inputs
)
def Omega(self, sto, T):
"""Dimensional partial molar volume of Li in solid solution [m3.mol-1]"""
Domain = self.domain.capitalize()
inputs = {f"{Domain} particle stoichiometry": sto, "Temperature [K]": T}
return pybamm.FunctionParameter(
f"{Domain} electrode partial molar volume [m3.mol-1]", inputs
)
def E(self, sto, T):
"""Dimensional Young's modulus"""
Domain = self.domain.capitalize()
inputs = {f"{Domain} particle stoichiometry": sto, "Temperature [K]": T}
return pybamm.FunctionParameter(
f"{Domain} electrode Young's modulus [Pa]", inputs
)
def sigma(self, T):
"""Dimensional electrical conductivity in electrode"""
inputs = {"Temperature [K]": T}
Domain = self.domain.capitalize()
return pybamm.FunctionParameter(
f"{Domain} electrode conductivity [S.m-1]", inputs
)
def k_cr(self, T):
"""
Cracking rate for the electrode;
"""
Domain = self.domain.capitalize()
return pybamm.FunctionParameter(
f"{Domain} electrode cracking rate", {"Temperature [K]": T}
)
def LAM_rate_current(self, i, T):
"""
Dimensional rate of loss of active material as a function of applied current
density
"""
Domain = self.domain.capitalize()
inputs = {"Total current density [A.m-2]": i, "Temperature [K]": T}
return pybamm.FunctionParameter(
f"{Domain} electrode current-driven LAM rate", inputs
)
class ParticleLithiumIonParameters(BaseParameters):
def __init__(self, phase, domain_param):
self.domain_param = domain_param
self.domain = domain_param.domain
self.main_param = domain_param.main_param
self.phase = phase
self.set_phase_name()
if self.phase == "primary":
self.geo = domain_param.geo.prim
elif self.phase == "secondary":
self.geo = domain_param.geo.sec
self.options = getattr(self.main_param.options, self.domain)
def _set_parameters(self):
main = self.main_param
domain, Domain = self.domain_Domain
phase_name = self.phase_name
pref = self.phase_prefactor
# Electrochemical reactions
self.ne = pybamm.Scalar(1)
# Intercalation kinetics
self.mhc_lambda = pybamm.Parameter(
f"{pref}{Domain} electrode reorganization energy [eV]"
)
self.alpha_bv = pybamm.Parameter(
f"{pref}{Domain} electrode Butler-Volmer transfer coefficient"
)
# SEI parameters
self.V_bar_inner = pybamm.Parameter(
f"{pref}Inner SEI partial molar volume [m3.mol-1]"
)
self.V_bar_outer = pybamm.Parameter(
f"{pref}Outer SEI partial molar volume [m3.mol-1]"
)
self.j0_sei = pybamm.Parameter(
f"{pref}SEI reaction exchange current density [A.m-2]"
)
self.R_sei = pybamm.Parameter(f"{pref}SEI resistivity [Ohm.m]")
self.D_sol = pybamm.Parameter(f"{pref}Outer SEI solvent diffusivity [m2.s-1]")
self.c_sol = pybamm.Parameter(f"{pref}Bulk solvent concentration [mol.m-3]")
self.U_inner = pybamm.Parameter(f"{pref}Inner SEI open-circuit potential [V]")
self.U_outer = pybamm.Parameter(f"{pref}Outer SEI open-circuit potential [V]")
self.kappa_inner = pybamm.Parameter(
f"{pref}Inner SEI electron conductivity [S.m-1]"
)
self.D_li = pybamm.Parameter(
f"{pref}Inner SEI lithium interstitial diffusivity [m2.s-1]"
)
self.c_li_0 = pybamm.Parameter(
f"{pref}Lithium interstitial reference concentration [mol.m-3]"
)
self.L_inner_0 = pybamm.Parameter(f"{pref}Initial inner SEI thickness [m]")
self.L_outer_0 = pybamm.Parameter(f"{pref}Initial outer SEI thickness [m]")
# Dividing by 10000 makes initial condition effectively zero
# without triggering division by zero errors
self.L_inner_crack_0 = self.L_inner_0 / 10000
self.L_outer_crack_0 = self.L_outer_0 / 10000
self.L_sei_0 = self.L_inner_0 + self.L_outer_0
self.E_sei = pybamm.Parameter(f"{pref}SEI growth activation energy [J.mol-1]")
self.alpha_SEI = pybamm.Parameter(f"{pref}SEI growth transfer coefficient")
self.inner_sei_proportion = pybamm.Parameter(
f"{pref}Inner SEI reaction proportion"
)
self.z_sei = pybamm.Parameter(f"{pref}Ratio of lithium moles to SEI moles")
# EC reaction
self.c_ec_0 = pybamm.Parameter(
f"{pref}EC initial concentration in electrolyte [mol.m-3]"
)
self.D_ec = pybamm.Parameter(f"{pref}EC diffusivity [m2.s-1]")
self.k_sei = pybamm.Parameter(f"{pref}SEI kinetic rate constant [m.s-1]")
self.U_sei = pybamm.Parameter(f"{pref}SEI open-circuit potential [V]")
if main.options.electrode_types[domain] == "planar":
self.n_Li_init = pybamm.Scalar(0)
self.Q_Li_init = pybamm.Scalar(0)
self.U_init = pybamm.Scalar(0)
return
# Spatial variables for parameters that depend on position within the cell
# and/or particle
x = pybamm.SpatialVariable(
f"x_{domain[0]}",
domain=[f"{domain} electrode"],
auxiliary_domains={"secondary": "current collector"},
coord_sys="cartesian",
)
r = pybamm.SpatialVariable(
f"r_{domain[0]}",
domain=[f"{domain} {self.phase_name}particle"],
auxiliary_domains={
"secondary": f"{domain} electrode",
"tertiary": "current collector",
},
coord_sys="spherical polar",
)
# Microscale geometry
# Note: the surface area to volume ratio is defined later with the function
# parameters. The particle size as a function of through-cell position is
# already defined in geometric_parameters.py
self.R = self.geo.R
self.R_typ = self.geo.R_typ
# Particle-size distribution parameters
self.R_min = self.geo.R_min
self.R_max = self.geo.R_max
self.f_a_dist = self.geo.f_a_dist
# Particle properties
self.epsilon_s = pybamm.FunctionParameter(
f"{pref}{Domain} electrode active material volume fraction",
{"Through-cell distance (x) [m]": x},
)
self.epsilon_s_av = pybamm.xyz_average(self.epsilon_s)
self.c_max = pybamm.Parameter(
f"{pref}Maximum concentration in {domain} electrode [mol.m-3]"
)
if self.options["open-circuit potential"] == "MSMR":
self.U_init = pybamm.Parameter(
f"{pref}Initial voltage in {domain} electrode [V]",
)
self.c_init = self.x(self.U_init) * self.c_max
else:
self.c_init = pybamm.FunctionParameter(
f"{pref}Initial concentration in {domain} electrode [mol.m-3]",
{
"Radial distance (r) [m]": r,
"Through-cell distance (x) [m]": pybamm.PrimaryBroadcast(
x, f"{domain} {phase_name}particle"
),
},
)
self.c_init_av = pybamm.xyz_average(pybamm.r_average(self.c_init))
self.sto_init_av = self.c_init_av / self.c_max
eps_c_init_av = pybamm.xyz_average(
self.epsilon_s * pybamm.r_average(self.c_init)
)
if self.options["open-circuit potential"] != "MSMR":
self.U_init = self.U(self.sto_init_av, main.T_init)
# Electrode loading and capacity
self.elec_loading = (
self.epsilon_s_av * self.domain_param.L * self.c_max * main.F / 3600
)
self.n_Li_init = eps_c_init_av * self.domain_param.L * main.A_cc
self.Q_Li_init = self.n_Li_init * main.F / 3600
self.Q_init = self.elec_loading * main.A_cc
if self.options["particle shape"] == "spherical":
self.a_typ = 3 * pybamm.xyz_average(self.epsilon_s) / self.R_typ
def D(self, c_s, T, lithiation=None):
"""
Dimensional diffusivity in particle. In the parameter sets this is defined as
a function of stoichiometry (dimensionless), but in the models we use it as a
function of concentration (mol/m3). We convert from concentration to
stoichiometry by dividing by the maximum concentration.
"""
Domain = self.domain.capitalize()
sto = c_s / self.c_max
tol = pybamm.settings.tolerances["D__c_s"]
sto = pybamm.maximum(pybamm.minimum(sto, 1 - tol), tol)
if lithiation is None:
lithiation = ""
else:
lithiation = lithiation + " "
inputs = {
f"{self.phase_prefactor}{Domain} particle stoichiometry": sto,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
f"{self.phase_prefactor}{Domain} particle {lithiation}"
"diffusivity [m2.s-1]",
inputs,
)
def j0(self, c_e, c_s_surf, T, lithiation=None):
"""Dimensional exchange-current density [A.m-2]"""
tol = pybamm.settings.tolerances["j0__c_e"]
c_e = pybamm.maximum(c_e, tol)
tol = pybamm.settings.tolerances["j0__c_s"]
c_s_surf = pybamm.maximum(
pybamm.minimum(c_s_surf, (1 - tol) * self.c_max), tol * self.c_max
)
domain, Domain = self.domain_Domain
if lithiation is None:
lithiation = ""
else:
lithiation = lithiation + " "
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
f"{Domain} particle surface concentration [mol.m-3]": c_s_surf,
f"{self.phase_prefactor}Maximum {domain} particle "
"surface concentration [mol.m-3]": self.c_max,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
f"{self.phase_prefactor}{Domain} electrode {lithiation}"
"exchange-current density [A.m-2]",
inputs,
)
def U(self, sto, T, lithiation=None):
"""Dimensional open-circuit potential [V]"""
# bound stoichiometry between tol and 1-tol. Adding 1/sto + 1/(sto-1) later
# will ensure that ocp goes to +- infinity if sto goes into that region
# anyway
Domain = self.domain.capitalize()
tol = pybamm.settings.tolerances["U__c_s"]
sto = pybamm.maximum(pybamm.minimum(sto, 1 - tol), tol)
if lithiation is None:
lithiation = ""
else:
lithiation = lithiation + " "
inputs = {f"{self.phase_prefactor}{Domain} particle stoichiometry": sto}
u_ref = pybamm.FunctionParameter(
f"{self.phase_prefactor}{Domain} electrode {lithiation}OCP [V]", inputs
)
# 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
if self.domain == "negative":
out.print_name = r"U_\mathrm{n}(c^\mathrm{surf}_\mathrm{s,n}, T)"
elif self.domain == "positive":
out.print_name = r"U_\mathrm{p}(c^\mathrm{surf}_\mathrm{s,p}, T)"
return out
def dUdT(self, sto):
"""
Dimensional entropic change of the open-circuit potential [V.K-1]
"""
domain, Domain = self.domain_Domain
inputs = {
f"{Domain} particle stoichiometry": sto,
f"{self.phase_prefactor}Maximum {domain} particle "
"surface concentration [mol.m-3]": self.c_max,
}
return pybamm.FunctionParameter(
f"{self.phase_prefactor}{Domain} electrode OCP entropic change [V.K-1]",
inputs,
)
def X_j(self, index):
"Available host sites indexed by reaction j"
domain = self.domain
d = domain[0]
Xj = pybamm.Parameter(f"X_{d}_{index}")
return Xj
def U0_j(self, index):
"Equilibrium potential indexed by reaction j"
domain = self.domain
d = domain[0]
U0j = pybamm.Parameter(f"U0_{d}_{index}")
return U0j
def w_j(self, index):
"Order parameter indexed by reaction j"
domain = self.domain
d = domain[0]
wj = pybamm.Parameter(f"w_{d}_{index}")
return wj
def alpha_bv_j(self, index):
"Dimensional Butler-Volmer exchange-current density indexed by reaction j"
domain = self.domain
d = domain[0]
alpha_bv_j = pybamm.Parameter(f"a_{d}_{index}")
return alpha_bv_j
def x_j(self, U, index):
"Fractional occupancy of site j as a function of potential"
T = self.main_param.T_ref
f = self.main_param.F / (self.main_param.R * T)
U0j = self.U0_j(index)
wj = self.w_j(index)
Xj = self.X_j(index)
# Equation 5, Baker et al 2018
xj = Xj / (1 + pybamm.exp(f * (U - U0j) / wj))
return xj
def dxdU_j(self, U, index):
"Derivative of fractional occupancy of site j as a function of potential [V-1]"
T = self.main_param.T_ref
f = self.main_param.F / (self.main_param.R * T)
U0j = self.U0_j(index)
wj = self.w_j(index)
Xj = self.X_j(index)
e = pybamm.exp(f * (U - U0j) / wj)
# Equation 25, Baker et al 2018
dxjdU = -(f / wj) * (Xj * e) / (1 + e) ** 2
return dxjdU
def j0_j(self, c_e, U, T, index):
"Exchange-current density index by reaction j [A.m-2]"
domain = self.domain
d = domain[0]
tol = pybamm.settings.tolerances["j0__c_e"]
c_e = pybamm.maximum(c_e, tol)
c_e_ref = self.main_param.c_e_init
xj = self.x_j(U, index)
# xj = pybamm.maximum(pybamm.minimum(xj, (1 - tol)), tol)
f = self.main_param.F / (self.main_param.R * T)
wj = self.w_j(index)
self.X_j(index)
aj = self.alpha_bv_j(index)
j0_ref_j = pybamm.FunctionParameter(
f"j0_ref_{d}_{index}", {"Temperature [K]": T}
)
# Equation 16, Baker et al 2018. The original formulation would be implemented
# as:
# j0_j = (
# j0_ref_j
# * xj ** (wj * aj)
# * (Xj - xj) ** (wj * (1 - aj))
# * (c_e / c_e_ref) ** (1 - aj)
# )
# However, we reformulate in terms of potential to avoid singularity as x_j
# approaches X_j
j0_j = (
j0_ref_j
* xj**wj
* pybamm.exp(f * (1 - aj) * (U - self.U0_j(index)))
* (c_e / c_e_ref) ** (1 - aj)
)
return j0_j
def x(self, U):
"Stoichiometry as a function of potential (for use with MSMR models)"
N = int(self.options["number of MSMR reactions"])
# Equation 6, Baker et al 2018
x = 0
for i in range(N):
x += self.x_j(U, i)
return x
def dxdU(self, U):
"""
Differential stoichiometry as a function of potential (for use with MSMR models)
"""
N = int(self.options["number of MSMR reactions"])
# Equation 25, Baker et al 2018
dxdU = 0
for i in range(N):
dxdU += self.dxdU_j(U, i)
return dxdU
def t_change(self, sto):
"""
Volume change for the electrode; sto should be R-averaged
"""
domain, Domain = self.domain_Domain
return pybamm.FunctionParameter(
f"{Domain} electrode volume change",
{
"Particle stoichiometry": sto,
f"{self.phase_prefactor}Maximum {domain} particle "
"surface concentration [mol.m-3]": self.c_max,
},
)