Lithium-Ion Diffusion and Swelling
Overview
A lithium-ion battery electrode breathes: as lithium intercalates it diffuses by Fick’s law
\[\frac{\partial c}{\partial t} = \nabla \cdot (D \nabla c)\]
and the local concentration c swells the host by a volumetric strain ε_ch = Ω (c − c₀), where Ω is the partial molar volume and c₀ the reference concentration (Newman & Thomas-Alyea 2004; Zhang, Shyy & Sastry 2007). The stress is then σ = C (ε − Ω(c−c₀)1) — the same chemical-strain coupling as hydration, but driven by an evolving diffusion field rather than a prescribed one.
using RasmahFickian diffusion into a particle
Hold one face of a cube at c = c_s and let lithium diffuse into an initially empty interior, forming a concentration front. The maximum principle keeps every value in [0, c_s].
D, c_s = 1.0, 1.0
m = tetrahedralize_box(1.0, 1.0, 1.0, 16, 4, 4)
n = size(m.nodes, 2)
fixed_c = [i for i in 1:n if m.nodes[1, i] < 1e-12] # surface x = 0 held at c_s
gc = fill(c_s, length(fixed_c))
cs = lithium_diffusion(m, D, zeros(n), 30, 0.01; fixed_c = fixed_c, gc = gc)
c_end = cs[end]
i_far = argmax(m.nodes[1, :]) # node on the far face
println("c at surface (x=0) = ", round(maximum(c_end); digits = 4))
println("c at far end (x=1) = ", round(c_end[i_far]; digits = 4))
println("0 ≤ c ≤ c_s everywhere: ", all(0 .<= c_end .<= c_s))c at surface (x=0) = 1.0
c at far end (x=1) = 0.3953
0 ≤ c ≤ c_s everywhere: true
Swelling
A uniform concentration c produces a free isotropic expansion ε_ch = Ω(c−c₀). Pin the rigid-body modes and measure the free end displacement of a bar.
E, ν, Ω, c0 = 1e3, 0.3, 1e-5, 0.0
C = Matrix(stiffness(Material(youngs_modulus = E, poisson_ratio = ν)))
findnode(x, y, z) = argmin(sum(abs2, m.nodes[:, i] .- [x, y, z]) for i in 1:n)
i0 = findnode(0.0, 0.0, 0.0); i1 = findnode(1.0, 0.0, 0.0); i2 = findnode(0.0, 1.0, 0.0)
fixed = [3i0 - 2, 3i0 - 1, 3i0, 3i1 - 1, 3i1, 3i2]
u = lithium_swelling(m, C, Ω, fill(1.0, n), c0; fixed = fixed)1275-element Vector{Float64}:
0.0
0.0
0.0
6.250000000020348e-7
-1.1632876267158147e-19
-3.330271354498828e-19
1.2500000000037698e-6
-6.304953833836819e-19
-9.672371497237602e-19
1.875000000005245e-6
⋮
8.75000000003628e-6
9.999999999989772e-6
9.999999999990304e-6
9.375000000036281e-6
9.999999999988991e-6
9.999999999989576e-6
1.0000000000036281e-5
9.999999999988208e-6
9.999999999988837e-6
Verification — free expansion
The free x-displacement at x = 1 must equal the chemical strain Ω (c − c₀):
println("u_x(x=1) = ", round(u[3i1 - 2]; digits = 8), " (analytic Ω(c−c₀) = ", Ω, ")")u_x(x=1) = 1.0e-5 (analytic Ω(c−c₀) = 1.0e-5)
Next steps
- Chemical (hydration) strain — the same coupling with prescribed kinetics.
- Nernst–Planck transport — the charged-species kinetics.
