API

Electrolyte and cell data

Single electrolyte problems

LiquidElectrolytes.ElectrolyteDataType
mutable struct ElectrolyteData{Tγ, Tcache, Texp, Tlog, Tflux} <: AbstractElectrolyteData

Data 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 species

  • sspecies::Vector{Int64}: Surface species list. Default: [(nc + 1)...(nc + na)]

  • iϕ::Int64: Index of electrostatic potential $ϕ$ in species list.

  • ip::Int64: Index of pressure p in species list

  • D::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.0e9

  • eneutral::Bool: Local electroneutrality switch. Default: false

  • upwindflux!::Any: Upwind flux caculation method for ionic species. This allows to choose between

    • μex_flux! (default, strongly preferrable): excess chemical potential (SEDAN) scheme
    • act_flux!: scheme based on reciprocal activity coefficients
    • cent_flux!: central scheme
  • weights::Vector{Float64}: Species weights for norms in solver control.
  • solvepressure::Bool: Solve for pressure.

    This is true by default. Setting this to false can 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. Use upwindflux! instead to change the discretization scheme.
source

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{typeof(LiquidElectrolytes.DGML_gamma!), PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, typeof(exp), typeof(log), typeof(LiquidElectrolytes.μex_flux!)}(
nc = 2, 
cspecies = [1.0, 2.0], 
na = 0, 
sspecies = Float64[], 
iϕ = 3, 
ip = 4, 
D = [2.0e-9, 2.0e-9], 
z = [1.0, -1.0], 
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 = PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, 
γl_cache = PreallocationTools.DiffCache{Vector{Float64}, Vector{Float64}}, 
ϕ_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.

source
LiquidElectrolytes.dlcap0Method
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^-2
source
LiquidElectrolytes.debyelengthMethod
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 nm
source
LiquidElectrolytes.chargedensityFunction
chargedensity(c,electrolyte)

Calculate charge density from vector of concentrations (in one grid point).

source
chargedensity(sol,electrolyte)

Calculate charge density vector from solution (on whole grid)

source
chargedensity(tsol,electrolyte)

Calculate time dependent charge densities from from time/voltage dependent solution solution (on whole grid). Returns a VoronoiFVM.TransientSolution.

source
LiquidElectrolytes.chemical_potentialFunction
 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}\]

source
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])
Breaking change between v0.2 and 0.3

This function has been corrected in version 0.3. Before it used the molar volume $v$ instead of the effective molar volume $\bar v = v + κv_0$ to calculate the ion chemical potentials. Examples with κ=0 are not affected.

source
LiquidElectrolytes.rrateFunction
rrate(R0,β,A)
rrate(R0,β,A, electrolyte)

Reaction rate expression

rrate(R0,β,A)=R0*(exp(-β*A) - exp((1-β)*A))
source
LiquidElectrolytes.iselectroneutralFunction
iselectroneutral(cx::Vector,electrolyte)

Check for electroneutrality of concentration vector

source
iselectroneutral(tsol::TransientSolution,electrolyte)

Check for electroneutrality of transient solution

source
LiquidElectrolytes.isincompressibleFunction
isincompressible(cx::Vector,electrolyte)

Check if the concentration vector fulfills incompressibility constraint, including the fact that the solvent concentration is nonnegative

source
isincompressible(tsol::TransientSolution,electrolyte)

Check for incompressibility of transient solution

source
LiquidElectrolytes.c0_barcFunction
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\]

source

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.electrolytesFunction
electrolytes(::AbstractCellData)

Return a vector of electrolytes, one electrolyte for each cell region.

Subtypes of AbstractCellData can implement their own method for this.

source
LiquidElectrolytes.bulk_electrodeFunction

bulk_electrode(d::AbstractCellData)

Return boundary index of bulk electrode. Subtypes of AbstractCellData can implement their own method for this.

source
LiquidElectrolytes.norm_weightsFunction
norm_weights(d::AbstractCellData)

Weights of components in norm calculation. Subtypes of AbstractCellData can implement their own method for this.

source

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
source

Poisson-Nernst-Planck system

LiquidElectrolytes.PNPSystemType
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 grid
  • celldata: instance of ElectrolyteData or of subtype of AbstractCellData
  • bcondition: boundary condition
  • reaction : reactions of the bulk species
  • kwargs: Keyword arguments of VoronoiFVM.System
source
LiquidElectrolytes.chemical_potentialsFunction
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.

source

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.

source
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.

source
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.

source

Poisson-Boltzmann system

LiquidElectrolytes.PBSystemType
PBSystem(grid;
             celldata=ElectrolyteData(),
         bcondition=(f, u, n, e)-> nothing,
         kwargs...)

Create VoronoiFVM system generalized Poisson-Boltzmann. Input:

  • grid: discretization grid
  • celldata: composite struct containing electrolyte data
  • bcondition: boundary condition
  • kwargs: Keyword arguments of VoronoiFVM.System
source

Poisson-Nernst-Planck-Stokes system

Utilities

LiquidElectrolytes.RLogType
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).

source
LiquidElectrolytes.RExpType
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).

source