#
# Standard parameters for lithium-ion battery models
#
import pybamm
from .base_parameters import BaseParameters
[docs]class LithiumIonParameters(BaseParameters):
"""
Standard parameters for lithium-ion battery models
Layout:
1. Dimensional Parameters
2. Dimensional Functions
3. Scalings
4. Dimensionless Parameters
5. Dimensionless Functions
6. Input Current
Parameters
----------
options : dict, optional
A dictionary of options to be passed to the parameters. The options that
can be set are listed below.
* "particle shape" : str, optional
Sets the model shape of the electrode particles. This is used to
calculate the surface area to volume ratio. Can be "spherical"
(default). TODO: implement "cylindrical" and "platelet".
* "working electrode": str
Which electrode(s) intercalates and which is counter. If "both"
(default), the model is a standard battery. Otherwise can be "negative"
or "positive" to indicate a half-cell model.
"""
def __init__(self, options=None):
self.options = options
# Save whether the submodel is a half-cell submodel
self.half_cell = self.options["working electrode"] != "both"
# Get geometric, electrical and thermal parameters
self.geo = pybamm.geometric_parameters
self.elec = pybamm.electrical_parameters
self.therm = pybamm.thermal_parameters
# Set parameters and scales
self._set_dimensional_parameters()
self._set_scales()
self._set_dimensionless_parameters()
# Set input current
self._set_input_current()
def _set_dimensional_parameters(self):
"""Defines the dimensional parameters"""
# Physical constants
self.R = pybamm.constants.R
self.F = pybamm.constants.F
self.T_ref = self.therm.T_ref
# Macroscale geometry
self.L_cn = self.geo.L_cn
self.L_n = self.geo.L_n
self.L_s = self.geo.L_s
self.L_p = self.geo.L_p
self.L_cp = self.geo.L_cp
self.L_x = self.geo.L_x
self.L_y = self.geo.L_y
self.L_z = self.geo.L_z
self.L = self.geo.L
self.A_cc = self.geo.A_cc
self.A_cooling = self.geo.A_cooling
self.V_cell = self.geo.V_cell
# Tab geometry
self.L_tab_n = self.geo.L_tab_n
self.Centre_y_tab_n = self.geo.Centre_y_tab_n
self.Centre_z_tab_n = self.geo.Centre_z_tab_n
self.L_tab_p = self.geo.L_tab_p
self.Centre_y_tab_p = self.geo.Centre_y_tab_p
self.Centre_z_tab_p = self.geo.Centre_z_tab_p
self.A_tab_n = self.geo.A_tab_n
self.A_tab_p = self.geo.A_tab_p
# Electrical
self.I_typ = self.elec.I_typ
self.Q = self.elec.Q
self.C_rate = self.elec.C_rate
self.n_electrodes_parallel = self.elec.n_electrodes_parallel
self.n_cells = self.elec.n_cells
self.i_typ = self.elec.i_typ
self.voltage_low_cut_dimensional = self.elec.voltage_low_cut_dimensional
self.voltage_high_cut_dimensional = self.elec.voltage_high_cut_dimensional
# Electrolyte properties
self.c_e_typ = pybamm.Parameter("Typical electrolyte concentration [mol.m-3]")
# Electrode properties
self.c_n_max = pybamm.Parameter(
"Maximum concentration in negative electrode [mol.m-3]"
)
self.c_p_max = pybamm.Parameter(
"Maximum concentration in positive electrode [mol.m-3]"
)
self.sigma_cn_dimensional = pybamm.Parameter(
"Negative current collector conductivity [S.m-1]"
)
self.sigma_cp_dimensional = pybamm.Parameter(
"Positive current collector conductivity [S.m-1]"
)
# 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_n_dimensional = self.geo.R_n_dimensional
self.R_p_dimensional = self.geo.R_p_dimensional
inputs = {
"Through-cell distance (x_n) [m]": pybamm.standard_spatial_vars.x_n
* self.L_x
}
self.epsilon_n_init = pybamm.FunctionParameter(
"Negative electrode porosity", inputs
)
inputs = {
"Through-cell distance (x_s) [m]": pybamm.standard_spatial_vars.x_s
* self.L_x
}
self.epsilon_s_init = pybamm.FunctionParameter("Separator porosity", inputs)
inputs = {
"Through-cell distance (x_p) [m]": pybamm.standard_spatial_vars.x_p
* self.L_x
}
self.epsilon_p_init = pybamm.FunctionParameter(
"Positive electrode porosity", inputs
)
if self.half_cell:
self.epsilon_init = pybamm.concatenation(
self.epsilon_s_init, self.epsilon_p_init
)
else:
self.epsilon_init = pybamm.concatenation(
self.epsilon_n_init, self.epsilon_s_init, self.epsilon_p_init
)
self.epsilon_inactive_n = (
1 - self.epsilon_n_init - self.epsilon_s_n(pybamm.standard_spatial_vars.x_n)
)
self.epsilon_inactive_s = 1 - self.epsilon_s_init
self.epsilon_inactive_p = (
1 - self.epsilon_p_init - self.epsilon_s_p(pybamm.standard_spatial_vars.x_p)
)
self.b_e_n = self.geo.b_e_n
self.b_e_s = self.geo.b_e_s
self.b_e_p = self.geo.b_e_p
self.b_s_n = self.geo.b_s_n
self.b_s_p = self.geo.b_s_p
# Particle-size distribution parameters
self.R_min_n_dim = self.geo.R_min_n_dim
self.R_min_p_dim = self.geo.R_min_p_dim
self.R_max_n_dim = self.geo.R_max_n_dim
self.R_max_p_dim = self.geo.R_max_p_dim
self.sd_a_n_dim = self.geo.sd_a_n_dim
self.sd_a_p_dim = self.geo.sd_a_p_dim
self.f_a_dist_n_dimensional = self.geo.f_a_dist_n_dimensional
self.f_a_dist_p_dimensional = self.geo.f_a_dist_p_dimensional
# Electrochemical reactions
self.ne_n = pybamm.Parameter("Negative electrode electrons in reaction")
self.ne_p = pybamm.Parameter("Positive electrode electrons in reaction")
self.C_dl_n_dimensional = pybamm.Parameter(
"Negative electrode double-layer capacity [F.m-2]"
)
self.C_dl_p_dimensional = pybamm.Parameter(
"Positive electrode double-layer capacity [F.m-2]"
)
# SEI parameters
self.V_bar_inner_dimensional = pybamm.Parameter(
"Inner SEI partial molar volume [m3.mol-1]"
)
self.V_bar_outer_dimensional = pybamm.Parameter(
"Outer SEI partial molar volume [m3.mol-1]"
)
self.m_sei_dimensional = pybamm.Parameter(
"SEI reaction exchange current density [A.m-2]"
)
self.R_sei_dimensional = pybamm.Parameter("SEI resistivity [Ohm.m]")
self.D_sol_dimensional = pybamm.Parameter(
"Outer SEI solvent diffusivity [m2.s-1]"
)
self.c_sol_dimensional = pybamm.Parameter(
"Bulk solvent concentration [mol.m-3]"
)
self.m_ratio = pybamm.Parameter(
"Ratio of inner and outer SEI exchange current densities"
)
self.U_inner_dimensional = pybamm.Parameter(
"Inner SEI open-circuit potential [V]"
)
self.U_outer_dimensional = pybamm.Parameter(
"Outer SEI open-circuit potential [V]"
)
self.kappa_inner_dimensional = pybamm.Parameter(
"Inner SEI electron conductivity [S.m-1]"
)
self.D_li_dimensional = pybamm.Parameter(
"Inner SEI lithium interstitial diffusivity [m2.s-1]"
)
self.c_li_0_dimensional = pybamm.Parameter(
"Lithium interstitial reference concentration [mol.m-3]"
)
self.L_inner_0_dim = pybamm.Parameter("Initial inner SEI thickness [m]")
self.L_outer_0_dim = pybamm.Parameter("Initial outer SEI thickness [m]")
self.L_sei_0_dim = self.L_inner_0_dim + self.L_outer_0_dim
# EC reaction
self.c_ec_0_dim = pybamm.Parameter(
"EC initial concentration in electrolyte [mol.m-3]"
)
self.D_ec_dim = pybamm.Parameter("EC diffusivity [m2.s-1]")
self.k_sei_dim = pybamm.Parameter("SEI kinetic rate constant [m.s-1]")
self.U_sei_dim = pybamm.Parameter("SEI open-circuit potential [V]")
# Li plating parameters
self.V_bar_plated_Li = pybamm.Parameter(
"Lithium metal partial molar volume [m3.mol-1]"
)
self.c_plated_Li_0_dim = pybamm.Parameter(
"Initial plated lithium concentration [mol.m-3]"
)
# 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_dimensional = pybamm.Parameter(
"Initial concentration in electrolyte [mol.m-3]"
)
# Mechanical parameters
self.nu_n = pybamm.Parameter("Negative electrode Poisson's ratio")
self.nu_p = pybamm.Parameter("Positive electrode Poisson's ratio")
self.E_n = pybamm.Parameter("Negative electrode Young's modulus [Pa]")
self.E_p = pybamm.Parameter("Positive electrode Young's modulus [Pa]")
self.c_n_0_dim = pybamm.Parameter(
"Negative electrode reference concentration for free of deformation "
"[mol.m-3]"
)
self.c_p_0_dim = pybamm.Parameter(
"Positive electrode reference concentration for free of deformation "
"[mol.m-3]"
)
self.Omega_n = pybamm.Parameter(
"Negative electrode partial molar volume [m3.mol-1]"
)
self.Omega_p = pybamm.Parameter(
"Positive electrode partial molar volume [m3.mol-1]"
)
self.l_cr_n_0 = pybamm.Parameter("Negative electrode initial crack length [m]")
self.l_cr_p_0 = pybamm.Parameter("Positive electrode initial crack length [m]")
self.w_cr = pybamm.Parameter("Negative electrode initial crack width [m]")
self.rho_cr_n_dim = pybamm.Parameter(
"Negative electrode number of cracks per unit area [m-2]"
)
self.rho_cr_p_dim = pybamm.Parameter(
"Positive electrode number of cracks per unit area [m-2]"
)
self.b_cr_n = pybamm.Parameter("Negative electrode Paris' law constant b")
self.b_cr_p = pybamm.Parameter("Positive electrode Paris' law constant b")
self.m_cr_n = pybamm.Parameter("Negative electrode Paris' law constant m")
self.m_cr_p = pybamm.Parameter("Positive electrode Paris' law constant m")
self.Eac_cr_n = pybamm.Parameter(
"Negative electrode activation energy for cracking rate [kJ.mol-1]"
) # noqa
self.Eac_cr_p = pybamm.Parameter(
"Positive electrode activation energy for cracking rate [kJ.mol-1]"
) # noqa
# intermediate variables [K*m^3/mol]
self.theta_n_dim = (
(self.Omega_n / self.R) * 2 * self.Omega_n * self.E_n / 9 / (1 - self.nu_n)
)
self.theta_p_dim = (
(self.Omega_p / self.R) * 2 * self.Omega_p * self.E_p / 9 / (1 - self.nu_p)
)
self.alpha_T_cell_dim = pybamm.Parameter(
"Cell thermal expansion coefficient [m.K-1]"
)
# Electrode capacities
x_n = pybamm.SpatialVariable(
"x_n", domain=["negative electrode"], coord_sys="cartesian"
)
x_p = pybamm.SpatialVariable(
"x_p", domain=["positive electrode"], coord_sys="cartesian"
)
eps_s_n_av = pybamm.x_average(self.epsilon_s_n(x_n))
eps_s_p_av = pybamm.x_average(self.epsilon_s_p(x_p))
self.neg_elec_loading = eps_s_n_av * self.L_n * self.c_n_max * self.F / 3600
self.pos_elec_loading = eps_s_p_av * self.L_p * self.c_p_max * self.F / 3600
self.C_n_init = self.neg_elec_loading * self.A_cc
self.C_p_init = self.pos_elec_loading * self.A_cc
# Total lithium
c_e_av_init = pybamm.x_average(self.epsilon_init) * self.c_e_typ
self.n_Li_e_init = c_e_av_init * self.L_x * self.A_cc
if self.options["working electrode"] == "both":
eps_s_n = self.epsilon_s_n(x_n)
c_n = self.c_n_init(x_n)
c_n_av = pybamm.x_average(eps_s_n * c_n)
self.n_Li_n_init = c_n_av * self.c_n_max * self.L_n * self.A_cc
else:
self.n_Li_n_init = pybamm.Scalar(0)
eps_s_p = self.epsilon_s_p(x_p)
c_p = self.c_p_init(x_p)
c_p_av = pybamm.x_average(eps_s_p * c_p)
self.n_Li_p_init = c_p_av * self.c_p_max * self.L_p * self.A_cc
self.n_Li_particles_init = self.n_Li_n_init + self.n_Li_p_init
self.n_Li_init = self.n_Li_particles_init + self.n_Li_e_init
# Loss of active material parameters
self.m_LAM_n = pybamm.Parameter(
"Negative electrode LAM constant exponential term"
)
self.beta_LAM_n_dimensional = pybamm.Parameter(
"Negative electrode LAM constant proportional term [s-1]"
)
self.stress_critical_n_dim = pybamm.Parameter(
"Negative electrode critical stress [Pa]"
)
self.m_LAM_p = pybamm.Parameter(
"Positive electrode LAM constant exponential term"
)
self.beta_LAM_p_dimensional = pybamm.Parameter(
"Positive electrode LAM constant proportional term [s-1]"
)
self.stress_critical_p_dim = pybamm.Parameter(
"Positive electrode critical stress [Pa]"
)
self.beta_LAM_sei_n_dimensional = pybamm.Parameter(
"Negative electrode reaction-driven LAM factor [m3.mol-1]"
)
self.beta_LAM_sei_p_dimensional = pybamm.Parameter(
"Positive electrode reaction-driven LAM factor [m3.mol-1]"
)
# utilisation parameters
self.u_n_init = pybamm.Parameter(
"Initial negative electrode interface utilisation"
)
self.u_p_init = pybamm.Parameter(
"Initial positive electrode interface utilisation"
)
self.beta_utilisation_n_dimensional = pybamm.Parameter(
"Negative electrode current-driven interface utilisation factor [m3.mol-1]"
)
self.beta_utilisation_p_dimensional = pybamm.Parameter(
"Positive electrode current-driven interface utilisation factor [m3.mol-1]"
)
def sigma_n_dimensional(self, T):
"""Dimensional electrical conductivity in negative electrode"""
inputs = {"Temperature [K]": T}
return pybamm.FunctionParameter(
"Negative electrode conductivity [S.m-1]", inputs
)
def sigma_p_dimensional(self, T):
"""Dimensional electrical conductivity in positive electrode"""
inputs = {"Temperature [K]": T}
return pybamm.FunctionParameter(
"Positive electrode conductivity [S.m-1]", inputs
)
def D_e_dimensional(self, c_e, T):
"""Dimensional diffusivity in electrolyte"""
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Electrolyte diffusivity [m2.s-1]", inputs)
def kappa_e_dimensional(self, c_e, T):
"""Dimensional electrolyte conductivity"""
inputs = {"Electrolyte concentration [mol.m-3]": c_e, "Temperature [K]": T}
return pybamm.FunctionParameter("Electrolyte conductivity [S.m-1]", inputs)
def D_n_dimensional(self, sto, T):
"""Dimensional diffusivity in negative particle. Note this is defined as a
function of stochiometry"""
inputs = {"Negative particle stoichiometry": sto, "Temperature [K]": T}
return pybamm.FunctionParameter(
"Negative electrode diffusivity [m2.s-1]", inputs
)
def D_p_dimensional(self, sto, T):
"""Dimensional diffusivity in positive particle. Note this is defined as a
function of stochiometry"""
inputs = {"Positive particle stoichiometry": sto, "Temperature [K]": T}
return pybamm.FunctionParameter(
"Positive electrode diffusivity [m2.s-1]", inputs
)
def j0_n_dimensional(self, c_e, c_s_surf, T):
"""Dimensional negative exchange-current density [A.m-2]"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
"Negative particle surface concentration [mol.m-3]": c_s_surf,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
"Negative electrode exchange-current density [A.m-2]", inputs
)
def j0_p_dimensional(self, c_e, c_s_surf, T):
"""Dimensional negative exchange-current density [A.m-2]"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e,
"Positive particle surface concentration [mol.m-3]": c_s_surf,
"Temperature [K]": T,
}
return pybamm.FunctionParameter(
"Positive electrode exchange-current density [A.m-2]", inputs
)
def j0_stripping_dimensional(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_dimensional(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 U_n_dimensional(self, sto, T):
"""Dimensional open-circuit potential in the negative electrode [V]"""
inputs = {"Negative particle stoichiometry": sto}
u_ref = pybamm.FunctionParameter("Negative electrode 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_n_dim_func = self.dUdT_n_dimensional(sto)
dudt_n_dim_func.print_name = r"\frac{dU}{dT_n}"
return u_ref + (T - self.T_ref) * dudt_n_dim_func
def U_p_dimensional(self, sto, T):
"""Dimensional open-circuit potential in the positive electrode [V]"""
inputs = {"Positive particle stoichiometry": sto}
u_ref = pybamm.FunctionParameter("Positive electrode 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_p_dim_func = self.dUdT_p_dimensional(sto)
dudt_p_dim_func.print_name = r"\frac{dU}{dT_p}"
return u_ref + (T - self.T_ref) * dudt_p_dim_func
def dUdT_n_dimensional(self, sto):
"""
Dimensional entropic change of the negative electrode open-circuit
potential [V.K-1]
"""
inputs = {"Negative particle stoichiometry": sto}
return pybamm.FunctionParameter(
"Negative electrode OCP entropic change [V.K-1]", inputs
)
def dUdT_p_dimensional(self, sto):
"""
Dimensional entropic change of the positive electrode open-circuit
potential [V.K-1]
"""
inputs = {"Positive particle stoichiometry": sto}
return pybamm.FunctionParameter(
"Positive electrode OCP entropic change [V.K-1]", inputs
)
def epsilon_s_n(self, x):
"""Negative electrode active material volume fraction"""
inputs = {"Through-cell distance (x_n) [m]": x * self.L_x}
return pybamm.FunctionParameter(
"Negative electrode active material volume fraction", inputs
)
def epsilon_s_p(self, x):
"""Positive electrode active material volume fraction"""
inputs = {"Through-cell distance (x_p) [m]": x * self.L_x}
return pybamm.FunctionParameter(
"Positive electrode active material volume fraction", inputs
)
def c_n_init_dimensional(self, x):
"""Initial concentration as a function of dimensionless position x"""
inputs = {"Dimensionless through-cell position (x_n)": x}
return pybamm.FunctionParameter(
"Initial concentration in negative electrode [mol.m-3]", inputs
)
def c_p_init_dimensional(self, x):
"""Initial concentration as a function of dimensionless position x"""
inputs = {"Dimensionless through-cell position (x_p)": x}
return pybamm.FunctionParameter(
"Initial concentration in positive electrode [mol.m-3]", inputs
)
def _set_scales(self):
"""Define the scales used in the non-dimensionalisation scheme"""
# Microscale
self.R_n_typ = self.geo.R_n_typ
self.R_p_typ = self.geo.R_p_typ
if self.options["particle shape"] == "spherical":
if self.half_cell:
self.a_n_typ = pybamm.Scalar(1)
else:
self.a_n_typ = 3 * self.epsilon_s_n(0) / self.R_n_typ
self.a_p_typ = 3 * self.epsilon_s_p(1) / self.R_p_typ
# Concentration
self.electrolyte_concentration_scale = self.c_e_typ
self.negative_particle_concentration_scale = self.c_n_max
self.positive_particle_concentration_scale = self.c_p_max
# Electrical
self.potential_scale = self.R * self.T_ref / self.F
self.current_scale = self.i_typ
self.current_scale.print_name = "I_typ"
# Scale for interfacial current density in A/m2
if self.options["working electrode"] == "both":
# porous electrode
self.j_scale_n = self.i_typ / (self.a_n_typ * self.L_x)
else:
# metal electrode (boundary condition between negative and separator)
self.j_scale_n = self.i_typ
self.j_scale_p = self.i_typ / (self.a_p_typ * self.L_x)
# Reference OCP based on initial concentration at
# current collector/electrode interface
if self.options["working electrode"] == "both":
sto_n_init = self.c_n_init_dimensional(0) / self.c_n_max
self.U_n_ref = self.U_n_dimensional(sto_n_init, self.T_ref)
else:
self.U_n_ref = pybamm.Scalar(0)
# Reference OCP based on initial concentration at
# current collector/electrode interface
sto_p_init = self.c_p_init_dimensional(1) / self.c_p_max
self.U_p_ref = self.U_p_dimensional(sto_p_init, self.T_ref)
# Reference exchange-current density
self.j0_n_ref_dimensional = (
self.j0_n_dimensional(self.c_e_typ, self.c_n_max / 2, self.T_ref) * 2
)
self.j0_p_ref_dimensional = (
self.j0_p_dimensional(self.c_e_typ, self.c_p_max / 2, self.T_ref) * 2
)
# Thermal
self.Delta_T = self.therm.Delta_T
# Velocity scale
self.velocity_scale = pybamm.Scalar(1)
# Discharge timescale
if self.options["working electrode"] == "positive":
self.c_max = self.c_p_max
else:
self.c_max = self.c_n_max
self.tau_discharge = self.F * self.c_max * self.L_x / self.i_typ
# Reaction timescales
self.tau_r_n = (
self.F * self.c_n_max / (self.j0_n_ref_dimensional * self.a_n_typ)
)
self.tau_r_p = (
self.F * self.c_p_max / (self.j0_p_ref_dimensional * self.a_p_typ)
)
# Electrolyte diffusion timescale
self.D_e_typ = self.D_e_dimensional(self.c_e_typ, self.T_ref)
self.tau_diffusion_e = self.L_x ** 2 / self.D_e_typ
# Particle diffusion timescales
self.D_n_typ_dim = self.D_n_dimensional(pybamm.Scalar(1), self.T_ref)
self.D_p_typ_dim = self.D_p_dimensional(pybamm.Scalar(1), self.T_ref)
self.tau_diffusion_n = self.R_n_typ ** 2 / self.D_n_typ_dim
self.tau_diffusion_p = self.R_p_typ ** 2 / self.D_p_typ_dim
# Thermal diffusion timescale
self.tau_th_yz = self.therm.tau_th_yz
# Choose discharge timescale
self.timescale = self.tau_discharge
def _set_dimensionless_parameters(self):
"""Defines the dimensionless parameters"""
# Timescale ratios
self.C_n = self.tau_diffusion_n / self.timescale
self.C_p = self.tau_diffusion_p / self.timescale
self.C_e = self.tau_diffusion_e / self.timescale
self.C_r_n = self.tau_r_n / self.timescale
self.C_r_p = self.tau_r_p / self.timescale
self.C_th = self.tau_th_yz / self.timescale
# Concentration ratios
self.gamma_e = self.c_e_typ / self.c_max
self.gamma_p = self.c_p_max / self.c_max
# Macroscale Geometry
self.l_cn = self.geo.l_cn
self.l_n = self.geo.l_n
self.l_s = self.geo.l_s
self.l_p = self.geo.l_p
self.l_cp = self.geo.l_cp
self.l_x = self.geo.l_x
self.l_y = self.geo.l_y
self.l_z = self.geo.l_z
self.a_cc = self.geo.a_cc
self.a_cooling = self.geo.a_cooling
self.v_cell = self.geo.v_cell
self.l = self.geo.l
self.delta = self.geo.delta
# Tab geometry
self.l_tab_n = self.geo.l_tab_n
self.centre_y_tab_n = self.geo.centre_y_tab_n
self.centre_z_tab_n = self.geo.centre_z_tab_n
self.l_tab_p = self.geo.l_tab_p
self.centre_y_tab_p = self.geo.centre_y_tab_p
self.centre_z_tab_p = self.geo.centre_z_tab_p
# Microscale geometry
self.R_n = self.geo.R_n
self.R_p = self.geo.R_p
self.a_R_n = self.a_n_typ * self.R_n_typ
self.a_R_p = self.a_p_typ * self.R_p_typ
# Particle-size distribution geometry
self.R_min_n = self.geo.R_min_n
self.R_min_p = self.geo.R_min_p
self.R_max_n = self.geo.R_max_n
self.R_max_p = self.geo.R_max_p
self.sd_a_n = self.geo.sd_a_n
self.sd_a_p = self.geo.sd_a_p
self.f_a_dist_n = self.geo.f_a_dist_n
self.f_a_dist_p = self.geo.f_a_dist_p
# Electrode Properties
self.sigma_cn = (
self.sigma_cn_dimensional * self.potential_scale / self.i_typ / self.L_x
)
self.sigma_cp = (
self.sigma_cp_dimensional * self.potential_scale / self.i_typ / self.L_x
)
self.sigma_cn_prime = self.sigma_cn * self.delta ** 2
self.sigma_cp_prime = self.sigma_cp * self.delta ** 2
self.sigma_cn_dbl_prime = self.sigma_cn_prime * self.delta
self.sigma_cp_dbl_prime = self.sigma_cp_prime * self.delta
# Electrolyte Properties
self.beta_surf = pybamm.Scalar(0)
self.beta_surf_n = pybamm.Scalar(0)
self.beta_surf_p = pybamm.Scalar(0)
# Electrochemical Reactions
self.C_dl_n = (
self.C_dl_n_dimensional
* self.potential_scale
/ self.j_scale_n
/ self.timescale
)
self.C_dl_p = (
self.C_dl_p_dimensional
* self.potential_scale
/ self.j_scale_p
/ self.timescale
)
# Electrical
self.voltage_low_cut = (
self.voltage_low_cut_dimensional - (self.U_p_ref - self.U_n_ref)
) / self.potential_scale
self.voltage_high_cut = (
self.voltage_high_cut_dimensional - (self.U_p_ref - self.U_n_ref)
) / self.potential_scale
# Thermal
self.rho_cn = self.therm.rho_cn
self.rho_n = self.therm.rho_n
self.rho_s = self.therm.rho_s
self.rho_p = self.therm.rho_p
self.rho_cp = self.therm.rho_cp
self.lambda_cn = self.therm.lambda_cn
self.lambda_n = self.therm.lambda_n
self.lambda_s = self.therm.lambda_s
self.lambda_p = self.therm.lambda_p
self.lambda_cp = self.therm.lambda_cp
self.Theta = self.therm.Theta
self.h_edge = self.therm.h_edge
self.h_tab_n = self.therm.h_tab_n
self.h_tab_p = self.therm.h_tab_p
self.h_cn = self.therm.h_cn
self.h_cp = self.therm.h_cp
self.h_total = self.therm.h_total
self.B = (
self.i_typ
* self.R
* self.T_ref
* self.tau_th_yz
/ (self.therm.rho_eff_dim(self.T_ref) * self.F * self.Delta_T * self.L_x)
)
self.T_amb_dim = self.therm.T_amb_dim
self.T_amb = self.therm.T_amb
# SEI parameters
self.C_sei_reaction = (self.j_scale_n / self.m_sei_dimensional) * pybamm.exp(
-(self.F * self.U_n_ref / (2 * self.R * self.T_ref))
)
self.C_sei_solvent = (
self.j_scale_n
* self.L_sei_0_dim
/ (self.c_sol_dimensional * self.F * self.D_sol_dimensional)
)
self.C_sei_electron = (
self.j_scale_n
* self.F
* self.L_sei_0_dim
/ (self.kappa_inner_dimensional * self.R * self.T_ref)
)
self.C_sei_inter = (
self.j_scale_n
* self.L_sei_0_dim
/ (self.D_li_dimensional * self.c_li_0_dimensional * self.F)
)
self.U_inner_electron = self.F * self.U_inner_dimensional / self.R / self.T_ref
self.R_sei = (
self.F
* self.j_scale_n
* self.R_sei_dimensional
* self.L_sei_0_dim
/ self.R
/ self.T_ref
)
self.v_bar = self.V_bar_outer_dimensional / self.V_bar_inner_dimensional
self.c_sei_scale = (
self.L_sei_0_dim * self.a_n_typ / self.V_bar_inner_dimensional
)
self.c_sei_outer_scale = (
self.L_sei_0_dim * self.a_n_typ / self.V_bar_outer_dimensional
)
self.L_inner_0 = self.L_inner_0_dim / self.L_sei_0_dim
self.L_outer_0 = self.L_outer_0_dim / self.L_sei_0_dim
# ratio of SEI reaction scale to intercalation reaction
self.Gamma_SEI = (
self.V_bar_inner_dimensional * self.j_scale_n * self.timescale
) / (self.F * self.L_sei_0_dim)
# EC reaction
self.C_ec = (
self.L_sei_0_dim
* self.j_scale_n
/ (self.F * self.c_ec_0_dim * self.D_ec_dim)
)
self.C_sei_ec = (
self.F
* self.k_sei_dim
* self.c_ec_0_dim
/ self.j_scale_n
* (
pybamm.exp(
-(
self.F
* (self.U_n_ref - self.U_sei_dim)
/ (2 * self.R * self.T_ref)
)
)
)
)
self.beta_sei = self.a_n_typ * self.L_sei_0_dim * self.Gamma_SEI
self.c_sei_init = self.c_ec_0_dim / self.c_sei_outer_scale
# lithium plating parameters
self.c_Li_typ = pybamm.Parameter(
"Typical plated lithium concentration [mol.m-3]"
)
self.c_plated_Li_0 = self.c_plated_Li_0_dim / self.c_Li_typ
# ratio of lithium plating reaction scaled to intercalation reaction
self.Gamma_plating = (self.a_n_typ * self.j_scale_n * self.timescale) / (
self.F * self.c_Li_typ
)
self.beta_plating = self.Gamma_plating * self.V_bar_plated_Li * self.c_Li_typ
# Initial conditions
self.T_init = self.therm.T_init
self.c_e_init = self.c_e_init_dimensional / self.c_e_typ
if self.options["working electrode"] == "both":
self.U_n_init = self.U_n(self.c_n_init(0), self.T_init)
else:
self.U_n_init = pybamm.Scalar(0)
self.U_p_init = self.U_p(self.c_p_init(1), self.T_init)
# Dimensionless mechanical parameters
self.rho_cr_n = self.rho_cr_n_dim * self.l_cr_n_0 * self.w_cr
self.rho_cr_p = self.rho_cr_p_dim * self.l_cr_p_0 * self.w_cr
self.theta_p = self.theta_p_dim * self.c_p_max / self.T_ref
self.theta_n = self.theta_n_dim * self.c_n_max / self.T_ref
self.c_p_0 = self.c_p_0_dim / self.c_p_max
self.c_n_0 = self.c_n_0_dim / self.c_n_max
self.t0_cr = 3600 / self.C_rate / self.timescale
self.beta_LAM_n = self.beta_LAM_n_dimensional * self.timescale
self.beta_LAM_p = self.beta_LAM_p_dimensional * self.timescale
# normalised typical time for one cycle
self.stress_critical_n = self.stress_critical_n_dim / self.E_n
self.stress_critical_p = self.stress_critical_p_dim / self.E_p
# Reaction-driven LAM parameters
self.beta_LAM_sei_n = (
self.beta_LAM_sei_n_dimensional
* self.a_n_typ
* self.j_scale_n
* self.timescale
) / self.F
self.beta_LAM_sei_p = (
self.beta_LAM_sei_p_dimensional
* self.a_p_typ
* self.j_scale_p
* self.timescale
) / self.F
# Utilisation factors
self.beta_utilisation_n = (
self.beta_utilisation_n_dimensional
* self.a_n_typ
* self.j_scale_n
* self.timescale
) / self.F
self.beta_utilisation_p = (
self.beta_utilisation_p_dimensional
* self.a_p_typ
* self.j_scale_p
* self.timescale
) / self.F
def sigma_n(self, T):
"""Dimensionless negative electrode electrical conductivity"""
T_dim = self.Delta_T * T + self.T_ref
return (
self.sigma_n_dimensional(T_dim)
* self.potential_scale
/ self.i_typ
/ self.L_x
)
def sigma_p(self, T):
"""Dimensionless positive electrode electrical conductivity"""
T_dim = self.Delta_T * T + self.T_ref
return (
self.sigma_p_dimensional(T_dim)
* self.potential_scale
/ self.i_typ
/ self.L_x
)
def sigma_n_prime(self, T):
"""Rescaled dimensionless negative electrode electrical conductivity"""
return self.sigma_n(T) * self.delta
def sigma_p_prime(self, T):
"""Rescaled dimensionless positive electrode electrical conductivity"""
return self.sigma_p(T) * self.delta
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.one_plus_dlnf_dlnc(c_e, T))
def t_plus(self, c_e, T):
"""Cation transference number (dimensionless)"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e * self.c_e_typ,
"Temperature [K]": self.Delta_T * T + self.T_ref,
}
return pybamm.FunctionParameter("Cation transference number", inputs)
def one_plus_dlnf_dlnc(self, c_e, T):
"""Thermodynamic factor (dimensionless)"""
inputs = {
"Electrolyte concentration [mol.m-3]": c_e * self.c_e_typ,
"Temperature [K]": self.Delta_T * T + self.T_ref,
}
return pybamm.FunctionParameter("1 + dlnf/dlnc", inputs)
def D_e(self, c_e, T):
"""Dimensionless electrolyte diffusivity"""
c_e_dimensional = c_e * self.c_e_typ
T_dim = self.Delta_T * T + self.T_ref
return self.D_e_dimensional(c_e_dimensional, T_dim) / self.D_e_typ
def kappa_e(self, c_e, T):
"""Dimensionless electrolyte conductivity"""
c_e_dimensional = c_e * self.c_e_typ
kappa_scale = self.F ** 2 * self.D_e_typ * self.c_e_typ / (self.R * self.T_ref)
T_dim = self.Delta_T * T + self.T_ref
return self.kappa_e_dimensional(c_e_dimensional, T_dim) / kappa_scale
def D_n(self, c_s_n, T):
"""Dimensionless negative particle diffusivity"""
sto = c_s_n
T_dim = self.Delta_T * T + self.T_ref
return self.D_n_dimensional(sto, T_dim) / self.D_n_typ_dim
def D_p(self, c_s_p, T):
"""Dimensionless positive particle diffusivity"""
sto = c_s_p
T_dim = self.Delta_T * T + self.T_ref
return self.D_p_dimensional(sto, T_dim) / self.D_p_typ_dim
def j0_n(self, c_e, c_s_surf, T):
"""Dimensionless negative exchange-current density"""
c_e_dim = c_e * self.c_e_typ
c_s_surf_dim = c_s_surf * self.c_n_max
T_dim = self.Delta_T * T + self.T_ref
return (
self.j0_n_dimensional(c_e_dim, c_s_surf_dim, T_dim)
/ self.j0_n_ref_dimensional
)
def j0_p(self, c_e, c_s_surf, T):
"""Dimensionless positive exchange-current density"""
c_e_dim = c_e * self.c_e_typ
c_s_surf_dim = c_s_surf * self.c_p_max
T_dim = self.Delta_T * T + self.T_ref
return (
self.j0_p_dimensional(c_e_dim, c_s_surf_dim, T_dim)
/ self.j0_p_ref_dimensional
)
def j0_stripping(self, c_e, c_Li, T):
"""Dimensionless exchange-current density for stripping"""
c_e_dim = c_e * self.c_e_typ
c_Li_dim = c_Li * self.c_Li_typ
T_dim = self.Delta_T * T + self.T_ref
return self.j0_stripping_dimensional(c_e_dim, c_Li_dim, T_dim) / self.j_scale_n
def j0_plating(self, c_e, c_Li, T):
"""Dimensionless reverse plating current"""
c_e_dim = c_e * self.c_e_typ
c_Li_dim = c_Li * self.c_Li_typ
T_dim = self.Delta_T * T + self.T_ref
return self.j0_plating_dimensional(c_e_dim, c_Li_dim, T_dim) / self.j_scale_n
def U_n(self, c_s_n, T):
"""Dimensionless open-circuit potential in the negative electrode"""
sto = c_s_n
T_dim = self.Delta_T * T + self.T_ref
return (self.U_n_dimensional(sto, T_dim) - self.U_n_ref) / self.potential_scale
def U_p(self, c_s_p, T):
"""Dimensionless open-circuit potential in the positive electrode"""
sto = c_s_p
T_dim = self.Delta_T * T + self.T_ref
return (self.U_p_dimensional(sto, T_dim) - self.U_p_ref) / self.potential_scale
def dUdT_n(self, c_s_n):
"""Dimensionless entropic change in negative open-circuit potential"""
sto = c_s_n
return self.dUdT_n_dimensional(sto) * self.Delta_T / self.potential_scale
def dUdT_p(self, c_s_p):
"""Dimensionless entropic change in positive open-circuit potential"""
sto = c_s_p
return self.dUdT_p_dimensional(sto) * self.Delta_T / self.potential_scale
def c_n_init(self, x):
"""
Dimensionless initial concentration as a function of dimensionless position x.
"""
return self.c_n_init_dimensional(x) / self.c_n_max
def c_p_init(self, x):
"""
Dimensionless initial concentration as a function of dimensionless position x.
"""
return self.c_p_init_dimensional(x) / self.c_p_max
def rho(self, T):
"""Dimensionless effective volumetric heat capacity"""
return (
self.rho_cn(T) * self.l_cn
+ self.rho_n(T) * self.l_n
+ self.rho_s(T) * self.l_s
+ self.rho_p(T) * self.l_p
+ self.rho_cp(T) * self.l_cp
) / self.l
def t_n_change(self, sto):
"""
Dimensionless volume change for the negative electrode;
sto should be R-averaged
"""
return pybamm.FunctionParameter(
"Negative electrode volume change", {"Particle stoichiometry": sto}
)
def t_p_change(self, sto):
"""
Dimensionless volume change for the positive electrode;
sto should be R-averaged
"""
return pybamm.FunctionParameter(
"Positive electrode volume change", {"Particle stoichiometry": sto}
)
def k_cr_p(self, T):
"""
Dimensionless cracking rate for the positive electrode;
"""
T_dim = self.Delta_T * T + self.T_ref
delta_k_cr = self.E_p ** self.m_cr_p * self.l_cr_p_0 ** (self.m_cr_p / 2 - 1)
return (
pybamm.FunctionParameter(
"Positive electrode cracking rate", {"Temperature [K]": T_dim}
)
* delta_k_cr
)
def k_cr_n(self, T):
"""
Dimensionless cracking rate for the negative electrode;
"""
T_dim = self.Delta_T * T + self.T_ref
delta_k_cr = self.E_n ** self.m_cr_n * self.l_cr_n_0 ** (self.m_cr_n / 2 - 1)
return (
pybamm.FunctionParameter(
"Negative electrode cracking rate", {"Temperature [K]": T_dim}
)
* delta_k_cr
)
def _set_input_current(self):
"""Set the input current"""
self.dimensional_current_with_time = pybamm.FunctionParameter(
"Current function [A]", {"Time [s]": pybamm.t * self.timescale}
)
self.dimensional_current_density_with_time = (
self.dimensional_current_with_time
/ (self.n_electrodes_parallel * self.geo.A_cc)
)
self.current_with_time = (
self.dimensional_current_with_time / self.I_typ * pybamm.sign(self.I_typ)
)
@property
def options(self):
return self._options
@options.setter
def options(self, extra_options):
self._options = pybamm.BatteryModelOptions(extra_options)