API
Electrolyte and cell data
Single electrolyte problems
LiquidElectrolytes.AbstractElectrolyteData — Type
abstract type AbstractElectrolyteDataAbstract super type for electrolytes.
LiquidElectrolytes.ElectrolyteData — Type
mutable struct ElectrolyteData{Tγ, Tcache, Texp, Tlog, Tflux} <: AbstractElectrolyteDataData for electrolyte. It is defined using Base.@kwdef allowing for keyword constructors like
ElectrolyteData(nc=3,z=[-1,2,1])The struct has three groups of fields:
- Problem parameters: these are meant to be set by user in order to provide simulation parameters.
- Derived values: these are derived from problem parameters by default, or via
update_derived!after setting some of the problems pararmeters - Fixed values: these are mostly physical constants and values derived from them, they should not be changed.
- Reserved fields: they are used to pass information during simulations and should not be set by the user.
Fields (reserved fields are modified by some algorithms):
nc::Int64: Number of charged species $N$.While in the default constructor, this value is primary to the value of cspecies,
update_derived!treats it as a derived datum.
cspecies::Vector{Int64}: Charged species list. Default: [1...nc]
na::Int64: Number of surface speciessspecies::Vector{Int64}: Surface species list. Default: [(nc + 1)...(nc + na)]
iϕ::Int64: Index of electrostatic potential $ϕ$ in species list.ip::Int64: Index of pressurepin species listD::Vector{Float64}: Mobility coefficients $D_i\; (i=1…N)$z::Vector{Int64}: Charge numbers of ions $z_i\; (i=1…N)$M0::Float64: Molar weight of solvent $M_0$M::Vector{Float64}: Molar weights of ions $M_i\; (i=1…N)$v0::Float64: Molar volume of solvent $v_0$v::Vector{Float64}: Molar volumes of ions $v_i\; (i=1…N)$κ::Vector{Float64}: Solvation numbers of ions $κ_i\; (i=1…N)$actcoeff!::Any: actcoeff!(γ, c, p, ::ElectrolyteData)Activity coefficient function. Write activity coefficients $γ_i\; (i=1…N)$ into vector
γ. Default:DGML_gamma!.
c_bulk::Vector{Float64}: Bulk ion concentrations $c_i^b\; (i=1…N)$Γ_we::Int64: Working electrode boundary numberΓ_bulk::Int64: Bulk boundary numberϕ_bulk::Float64: Bulk voltage $ϕ^b$p_bulk::Float64: Bulk pressure $p^b$T::Float64: Temperature $T$ε::Float64: Dielectric permittivity of solvent $ε$rexp::Any: Regularized exponential, default:exp(unregularized)rlog::Any: Regularized logarithm, default:log(unregularized)pscale::Float64: Pressure scaling factor. Default: 1.0e9eneutral::Bool: Local electroneutrality switch. Default: falseupwindflux!::Any: Upwind flux caculation method for ionic species. This allows to choose betweenμex_flux!(default, strongly preferrable): excess chemical potential (SEDAN) schemeact_flux!: scheme based on reciprocal activity coefficientscent_flux!: central scheme
weights::Vector{Float64}: Species weights for norms in solver control.
solvepressure::Bool: Solve for pressure.This is
trueby default. Setting this tofalsecan serve two purposes:- Use the pressure from the solution of a flow equation
- Ignore the pressure contribution to the excess chemical potential
F::Float64: Faraday constant $F$ (fixed)ε_0::Float64: Dielectric permittivity of vacuum $ε_0$ (fixed)RT::Float64: Molar gas constant scaled with temperature $RT$ (derived)Mrel::Vector{Float64}: Solvated molar mass ratio $m_i = \frac{M_i}{M_0} + κ_i \; (i=1… N)$ (derived)vrel::Vector{Float64}: Solvated molar volume ratio $\hat v_i = \frac{v_i}{v_0} + κ_i \; (i=1… N)$ (derived)barv::Vector{Float64}: Solvated molar volume $\bar v_i = v_i + κ_i v_0 \; (i=1… N)$ (derived)tildev::Vector{Float64}: Pressure relevant volume $\tilde v_i = \bar v_i + m_i v_0 \; (i=1… N)$ (derived)γ_bulk::Vector{Float64}: Activity coefficients at bulk interface $γ_i^b= γ_i(c_1^b … c_N^b, p^b) \; (i=1… N)$ (derived)γk_cache::Any: Cache for activity coefficient calculation (reserved)γl_cache::Any: Cache for activity coefficient calculation (reserved)ϕ_we::Float64: Working electrode voltage $ϕ_{we}$ (reserved) Used by sweep algorithms to pass boundary data.
edgevelocity::Union{Float64, Vector{Float64}}: Edge velocity projection (reserved).
scheme::Symbol: Scheme parameter. Deprecated and disabled. Useupwindflux!instead to change the discretization scheme.
The default values for electrolyte data are those of an symmetric 0.1M aqueous binary electrolyte at 298.5K with solvation number κ=10, ion molar volumes and masses similar to those of water molecules and diffusion coefficients 2.0e-9 $m^2/s$. All values given in SI base units:
using LiquidElectrolytes
ElectrolyteData()ElectrolyteData(
nc = 2,
cspecies = [1, 2],
na = 0,
sspecies = Int64[],
iϕ = 3,
ip = 4,
D = [2.0e-9, 2.0e-9],
z = [1, -1],
M0 = 0.018015,
M = [0.018015, 0.018015],
v0 = 1.8051e-5,
v = [1.8051e-5, 1.8051e-5],
κ = [10.0, 10.0],
actcoeff! = DGML_gamma!,
c_bulk = [100.0, 100.0],
Γ_we = 1,
Γ_bulk = 2,
ϕ_bulk = 0.0,
p_bulk = 0.0,
T = 298.15,
ε = 78.49,
rexp = exp,
rlog = log,
pscale = 1.0e9,
eneutral = false,
upwindflux! = μex_flux!,
weights = [1.8051e-5, 1.8051e-5, 1.0, 0.0],
solvepressure = true,
F = 96485.0,
ε_0 = 8.8542e-12,
RT = 2479.0,
Mrel = [11.0, 11.0],
vrel = [11.0, 11.0],
barv = [0.00019856, 0.00019856],
tildev = [0.0, 0.0],
γ_bulk = [1.0, 1.0],
γk_cache = DiffCache,
γl_cache = DiffCache,
ϕ_we = 0.0,
edgevelocity = 0.0,
scheme = :deprecated,
)
LiquidElectrolytes.update_derived! — Function
update_derived!(electrolyte::ElectrolyteData)Update derived electrolyte data. This needs to be called in order to update fields Mrel, vrel, barv, tildev, RT, γ_bulk of ElectrolyteData after changing some of the other parameters.
It also correctes electrolyte.nc in order to be consistent with electrolyte.cspecies.
Called on the passed electrolyte data by PNPSystem, PBSystem, dlcapsweep, ivsweep, cvsweep.
LiquidElectrolytes.dlcap0 — Method
dlcap0(electrolyte)Return double layer capacitance at zero voltage for symmetric binary electrolyte. The molarity is defined by the bulk concentration value $c_1^b$.
\[ c_{dl}=2 \frac{εε_0F^2c_1^b}{RT}\]
Example
using LessUnitful
ely = ElectrolyteData(c_bulk=fill(0.01ufac"mol/dm^3",2))
round(dlcap0(ely),sigdigits=5) |> u"μF/cm^2"
# output
22.847 μF cm^-2LiquidElectrolytes.debyelength — Method
debyelength(electrolyte)Return debye length for symmetric binary electrolyte. The molarity is defined by the bulk concentration value $c_1^b$.
\[ l_{debye}=\sqrt{RT\frac{εε_0}{F^2c_1^b}}\]
using LessUnitful
ely = ElectrolyteData(c_bulk=fill(0.01ufac"mol/dm^3",2))
round(debyelength(ely),sigdigits=5) |> u"nm"
# output
4.3018 nmLiquidElectrolytes.chargedensity — Function
chargedensity(c,electrolyte)Calculate charge density from vector of concentrations (in one grid point).
chargedensity(sol,electrolyte)Calculate charge density vector from solution (on whole grid)
chargedensity(tsol,electrolyte)Calculate time dependent charge densities from from time/voltage dependent solution solution (on whole grid). Returns a VoronoiFVM.TransientSolution.
LiquidElectrolytes.chemical_potential — Function
chemical_potential(c, barc, p, barv, electrolyte)Calculate chemical potential of species with concentration c
\[ μ = \bar v(p-p_{ref}) + RT\log \frac{c}{\bar c}\]
LiquidElectrolytes.chemical_potentials! — Function
chemical_potentials!(μ,u,electrolyte)Calculate chemical potentials from concentrations.
Input:
μ: memory for result (will be filled)u: local solution vector (concentrations, potential, pressure)
Returns μ0, μ: chemical potential of solvent and chemical potentials of ions.
using LessUnitful
ely = ElectrolyteData(c_bulk = fill(0.01ufac"mol/dm^3", 2))
μ0, μ = chemical_potentials!([0.0, 0.0], vcat(ely.c_bulk, [0, 0]), ely)
round(μ0, sigdigits = 5), round.(μ, sigdigits = 5)
# output
(-0.89834, [-21359.0, -21359.0])LiquidElectrolytes.rrate — Function
rrate(R0,β,A)
rrate(R0,β,A, electrolyte)Reaction rate expression
rrate(R0,β,A)=R0*(exp(-β*A) - exp((1-β)*A))LiquidElectrolytes.iselectroneutral — Function
iselectroneutral(cx::Vector,electrolyte)Check for electroneutrality of concentration vector
iselectroneutral(tsol::TransientSolution,electrolyte)Check for electroneutrality of transient solution
LiquidElectrolytes.isincompressible — Function
isincompressible(cx::Vector,electrolyte)Check if the concentration vector fulfills incompressibility constraint, including the fact that the solvent concentration is nonnegative
isincompressible(tsol::TransientSolution,electrolyte)Check for incompressibility of transient solution
LiquidElectrolytes.c0_barc — Function
c0_barc(u,electrolyte)Calculate solvent concentration $c_0$ and summary concentration $\bar c$ from vector of concentrations c using the incompressibility constraint (assuming $κ_0=0$):
\[ \sum_{i=0}^N c_i (v_i + κ_iv_0) =1\]
This gives
\[ c_0v_0=1-\sum_{i=1}^N c_i (v_i+ κ_iv_0)\]
\[c_0= 1/v_0 - \sum_{i=1}^N c_i(\frac{v_i}{v_0}+κ_i)\]
Then we can calculate
\[ \bar c= \sum_{i=0}^N c_i\]
Multielectrolyte problems
Handling multiple electrolytes (e.g. for certain ion channel models) is facilitated by this newer alternative API which at once allowd to pass additional user dependent data e.g. to reaction problems.
LiquidElectrolytes.AbstractCellData — Type
AbstractCellDataAbstract type for cell data. Users may implement their own subtypes.
LiquidElectrolytes.electrolytes — Function
electrolytes(::AbstractCellData)Return a vector of electrolytes, one electrolyte for each cell region.
Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.working_electrode — Function
working_electrode(d::AbstractCellData)
Return boundary index of working electrode. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.bulk_electrode — Function
bulk_electrode(d::AbstractCellData)
Return boundary index of bulk electrode. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.norm_weights — Function
norm_weights(d::AbstractCellData)Weights of components in norm calculation. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.working_electrode_voltage — Function
working_electrode_voltage(d::AbstractCellData)Return voltage applied at working electrode. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.working_electrode_voltage! — Function
working_electrode_voltage!(d::AbstractCellData, v)Set voltage applied at working electrode. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.pressure_index — Function
pressure_index(d::AbstractCellData)Index of pressure in species list. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.voltage_index — Function
voltage_index(d::AbstractCellData)Index of voltage in species list. Subtypes of AbstractCellData can implement their own method for this.
LiquidElectrolytes.check_celldata — Function
check_celldata(d::AbstractCellData)
Check if subtypes of AbstractCellData implement all necessary methods.
Activity coefficients
LiquidElectrolytes.DGML_gamma! — Function
DGML_gamma!(γ, c, p, electrolyte)Activity coefficients according to Dreyer, Guhlke, Müller, Landstorfer.
\[γ_i = \exp\left(\frac{\tilde v_i p}{RT}\right) \left(\frac{\bar c}{c_0}\right)^{m_i} \frac{1}{v_0\bar c}\]
Input:
- c: vector of concentrations
- p: pressure
- electrolyte: instance of
ElectrolyteData
Output:
- γ (mutated) activity coefficients
Poisson-Nernst-Planck system
LiquidElectrolytes.AbstractElectrochemicalSystem — Type
abstract type AbstractElectrochemicalSystemAbstract super type for electrochemical systems
VoronoiFVM.unknowns — Function
unknowns(sys)Return vector of unknowns initialized with bulk data.
LiquidElectrolytes.PNPSystem — Type
PNPSystem(grid;
celldata=ElectrolyteData(),
bcondition=(f, u, n, e)-> nothing,
reaction=(f, u, n, e)-> nothing,
kwargs...)Create VoronoiFVM system for generalized Poisson-Nernst-Planck. Input:
grid: discretization gridcelldata: instance of ElectrolyteData or of subtype of AbstractCellDatabcondition: boundary conditionreaction: reactions of the bulk specieskwargs: Keyword arguments of VoronoiFVM.System
LiquidElectrolytes.celldata — Function
celldata(sys)Extract celldata from system.
LiquidElectrolytes.electrolytedata — Function
electrolytedata(sys)Extract electrolyte data from system.
LiquidElectrolytes.solventconcentration — Function
solventconcentration(U::Array, electrolyte)Calculate vector of solvent concentrations from solution array.
LiquidElectrolytes.chemical_potentials — Function
chemical_potentials(solution, electrolyte)Calculate chemical potentials from solution. Returns μ0, μ, where μ0 is the vector of solvent chemical potentials, and μ is the nc×nnodes matrix of solute chemical potentials.
LiquidElectrolytes.electrochemical_potentials — Function
electrochemical_potentials(solution, electrolyte)Calculate electrochemical potentials from solution. and return nc×nnodes matrix of solute electrochemical potentials measured in Volts.
Upwind fluxes
LiquidElectrolytes.μex_flux! — Function
μex_flux!(f,dϕ,ck,cl,γk,γl,electrolyte; evelo=0.0)Excess chemical potential (Sedan) upweind flux, based on modified Scharfetter-Gummel scheme, see Gaudeul/Fuhrmann 2022.
Appearantly first described by Yu, Zhiping and Dutton, Robert, SEDAN III, www-tcad.stanford.edu/tcad/programs/sedan3.html
see also the 198? Fortran code available via https://web.archive.org/web/20210518233152/http://www-tcad.stanford.edu/tcad/programs/oldftpable.html
Verification calculation is in the paper.
LiquidElectrolytes.act_flux! — Function
act_flux!(ic,dϕ,ck,cl,γk,γl,electrolyte; evelo=0)Scharfetter-Gummel upwind flux expression based on activities, see Fuhrmann, CPC 2015. As shown in Chainais-Hilliaret, Cances, Fuhrmann, Gaudeul, 2019, this is consistent to thermodynamic equilibrium but shows inferior convergence behavior.
LiquidElectrolytes.cent_flux! — Function
cent_flux!(ic,dϕ,ck,cl,γk,γl,electrolyte; evelo = 0)Flux expression based on central differences, see Gaudeul/Fuhrmann 2022. As shown in the paper this is covergent, consistent to thermodynamic equilibrium but may show inferior convergence behavior.
Poisson-Boltzmann system
LiquidElectrolytes.PBSystem — Type
PBSystem(grid;
celldata=ElectrolyteData(),
bcondition=(f, u, n, e)-> nothing,
kwargs...)Create VoronoiFVM system generalized Poisson-Boltzmann. Input:
grid: discretization gridcelldata: composite struct containing electrolyte databcondition: boundary conditionkwargs: Keyword arguments of VoronoiFVM.System
Poisson-Nernst-Planck-Stokes system
LiquidElectrolytes.PNPStokesSolver — Type
struct PNPStokesSolver{Tflow, Tpnp}Stokes solver struct.
flowsolver::Anypnpsolver::Any
Utilities
LiquidElectrolytes.RLog — Type
RLog(eps)Callable struct for regularized logarithm. Smooth linear continuation for x<eps. This means we can calculate a "logarithm" of a small negative number. Objects mylog::RLog of this type are meant to replace the logarithm function and allow to invoke mylog(x).
LiquidElectrolytes.RExp — Type
RExp(trunc)Callable struct for regularized exponential. Linear continuation for x>trunc, returns 1/rexp(-x) for x<-trunc. Objects myexp::RExp of this type are meant to replace the exponential function and allow to invoke myexp(x).