Course #02: Diffusion Equation (Fick’s Second Law)
Read this file to seamlessly resume learning in a new conversation
This file follows thenote_specification.mdstandard
Teaching mode: Zero-basis friendly, all figures generated using matplotlib PNG
I. Prior Knowledge Review
1.1 Electrochemical Simulation Fundamentals
Electrochemical simulation = creating a “digital twin” of a battery — using mathematical equations to simulate internal battery processes on a computer:
- During discharge: negative electrode deintercalates Li → Li⁺ traverses electrolyte → positive electrode intercalates Li
- Electrons flow through external circuit to do work
1.2 SPM (Single Particle Model)
Core simplification: Collapse thousands of particles in each electrode into a single spherical particle.
Three assumptions:
- All particles behave identically → one sphere represents the entire electrode
- Neglect electrolyte concentration variation → c_e is uniform everywhere
- Uniform current distribution → each particle experiences the same current
Capability boundaries:
- Can predict voltage-time curves (discharge curves)
- Can predict lithium concentration distribution inside particles
- Cannot accurately predict high current operation (lacks electrolyte gradients)
1.3 Parameter Naming Convention
self.{physical_quantity}_{phase}_{position}, e.g.:
c_s_max_n= concentration-solid-max-negative = negative electrode solid-phase maximum lithium concentrationD_s_p= diffusivity-solid-positive = positive electrode solid-phase diffusion coefficienteps_e_s= epsilon-electrolyte-separator = separator electrolyte volume fraction
1.4 SOC and N/P Ratio
- Battery SOC ≠ electrode SOC; change in opposite directions during discharge
- Lithium conservation constraint:
N_total × ΔSOC_n = P_total × ΔSOC_p - N/P ratio = negative electrode total capacity / positive electrode total capacity
- In
parameters.py, onlybattery_soc_initialneeds to be set; electrode SOC is computed automatically
1.5 OCV Curves
- Nernst Equation: Thermodynamic equilibrium potential for ideal solutions
$$
OCV(\theta) = U_0 + \frac{RT}{F} \cdot \ln!\left(\frac{\theta}{1-\theta}\right)
$$
- Graphite negative electrode: tanh function fits staircase-like plateaus (phase transition characteristics)
- NMC positive electrode: quadratic polynomial fit, $OCV_{\mathrm{NMC}}(\theta) = 4.15 - 0.9\theta + 0.2\theta^2$
- Cell open-circuit voltage: $V_{\mathrm{cell}} = OCV_p - OCV_n$
II. Current Code Status
2.1 File Inventory
| File | Purpose | Status |
|---|---|---|
spm/parameters.py |
Battery physical parameters + SOC auto-conversion | Complete |
spm/model.py |
SPM core engine (four governing equations) | Complete (to be studied) |
spm/__init__.py |
Package initialization | Complete |
visualize_ocv.py |
OCV visualization script | Complete |
requirements.txt |
numpy, scipy, matplotlib | Complete |
2.2 Functions Already Implemented in model.py
1 | ocv_negative(theta) # Graphite negative OCV (tanh fit) |
2.3 Key Parameters in parameters.py (used in this session)
| Parameter | Value | Meaning | Role in Diffusion |
|---|---|---|---|
R_n, R_p |
5 μm | Particle radius | Spatial domain [0, R] |
D_s_n |
3.9e-14 m²/s | Negative electrode diffusivity | Diffusion speed |
D_s_p |
1.0e-13 m²/s | Positive electrode diffusivity | Diffusion speed |
c_s_max_n |
31507 mol/m³ | Negative max concentration | SOC normalization reference |
c_s_max_p |
51554 mol/m³ | Positive max concentration | SOC normalization reference |
Nr |
50 | Radial discretization points | Spatial resolution |
dt |
1.0 s | Time step | Temporal resolution |
T |
298.15 K | Temperature | Affects diffusion coefficient |
2.4 Figure Generation Notes
This course uses matplotlib to generate PNG figures (consistent with course 1 visualize_ocv.py style):
| Session | Image File | Content |
|---|---|---|
| 2.1 | diffusion_concept.png |
Diffusion physical concept (concentration gradient, flux direction, spherical shell onion model) |
| 2.2 | diffusion_discretization.png |
Discretization illustration (node grid, tridiagonal matrix structure, boundary condition schematic) |
| 2.3 | diffusion_simulation.png |
Numerical simulation results (concentration profile evolution, different parameter comparisons) |
III. Current Session Topic
Numerical Implementation of the Diffusion Equation (Fick’s Second Law)
Among SPM’s four governing equations, the diffusion equation describes how lithium atom concentration inside a spherical particle evolves over time. This is key to understanding battery polarization and concentration distribution.
IV. Three-Session Step-by-Step Learning Plan
Teaching positioning: Assumes zero mathematical background, starting from “what is concentration” and progressively deriving up to matrix operations.
Learning method: Each session includes hand-derivation exercises + PNG figure visualization.
1 | Session 2.1 ────→ Session 2.2 ────→ Session 2.3 |
Session 2.1: What is Diffusion? — From “a Cup of Sugar Water” to the Spherical Coordinate Equation
Goal: Build physical intuition, no code or matrices
Difficulty: ⭐ · Pure concepts
2.1.1 Learning Content
| # | Topic | Core Question | Teaching Method |
|---|---|---|---|
| 1 | What is concentration | Starting from “sugar dissolving in water”: c = amount of substance ÷ volume, unit mol/m³. Lithium in particles is like sugar in water — some regions more concentrated, others more dilute. | Everyday analogy |
| 2 | Fick’s First Law | The driving force of diffusion is concentration gradient — “water flows downhill”. J = −D · ∂c/∂r, each symbol explained character by character: J is flux (moles per second per square meter), D is diffusion coefficient (how fast it moves), ∂c/∂r is concentration gradient (how steep the slope). The negative sign indicates flow from high to low concentration. | Formula decomposition + illustration |
| 3 | Fick’s Second Law | Derive from mass conservation — imagine a thin shell inside the particle, inflow J(r) from left, outflow J(r+dr) from right; net change = inflow − outflow, substitute J = −D·∂c/∂r to obtain ∂c/∂t = D·∂²c/∂r² (Cartesian form). | Hand-derive: 1D mass conservation → PDE |
| 4 | Why spherical coordinates | Battery particles are spherical! Shell volume ∝ r², outer layers can hold more lithium than inner layers. For shells of equal thickness: near-center shell volume is small → small amount of Li changes concentration dramatically; near-surface shell volume is large → needs more Li. This introduces the 1/r² factor in the equation. | Onion model + diagram |
| 5 | Spherical equation expansion | ∂c/∂t = D · [∂²c/∂r² + (2/r) · ∂c/∂r]. Physical meaning of each term: ∂²c/∂r² is the “curvature effect” (also present in Cartesian), (2/r)·∂c/∂r is the “geometric focusing effect” (unique to spherical coordinates). | Term-by-term explanation |
| 6 | Two boundary conditions | Center (r=0): Symmetry → concentration profile is “flat” at center (∂c/∂r=0). The center is a perfect symmetry point, lithium diffuses uniformly from all directions, net flux is zero. Surface (r=R): Flux determined by current (D·∂c/∂r = j). During discharge j<0 (deintercalation), concentration is lowest at surface. | Diagram + physical intuition |
| 7 | Analogy understanding | Particle = circular sponge absorbing/squeezing water. Discharge = squeezing water out from surface, squeeze too fast → surface dries out → this is the root of “concentration polarization”. If diffusion is fast enough (large D), internal water continuously replenishes the surface. If diffusion is too slow (small D), surface is dry but interior is still wet. | Analogy |
2.1.2 Hand-Derivation Exercise
Derive Fick’s Second Law (Cartesian form) starting from 1D mass conservation:
1 | Step 1: Write mass conservation |
2.1.3 Generate Figure: diffusion_concept.png
Use matplotlib to generate PNG, style referencing
visualize_ocv.py
Subplot 1: 1D diffusion illustration
- X-axis: position r, Y-axis: concentration c
- Draw a descending curve from left to right (high concentration → low concentration)
- Label concentration gradient ∂c/∂r (slope), arrow from high to low concentration labeled J (diffusion flux direction)
- Annotation text: “J = −D · ∂c/∂r”, “Diffusion direction: high C → low C”
Subplot 2: Spherical “onion model”
- Draw a circle (particle cross-section), draw 3-4 concentric rings (spherical shells) inside
- Label r=0 (center), r=R (surface)
- Annotate each shell with different volume hints (inner shell small, outer shell large)
- Title: “Shell volume ∝ r², larger near surface”
Subplot 3: Expected concentration distribution during discharge
- Draw a circle, use color (or grayscale) to indicate concentration: light at surface (low concentration), dark interior (high concentration)
- Label arrows: surface → exterior (deintercalation direction), interior → surface (diffusion replenishment direction)
- Title: “Negative electrode particle during discharge: surface deintercalation → interior diffusion replenishment”
2.1.4 Extended Thinking (preview for 2.2)
- If we want to solve the spherical diffusion equation on a computer, how many segments should we slice the continuous r into?
- How does a computer compute “∂c/∂r”? Computers only do addition, subtraction, multiplication, and division — they can’t take derivatives.
Session 2.2: Turning Equations into Matrices — Finite Differences and Implicit Euler
Goal: Hand-derive all discretization formulas, understand the origin of every matrix coefficient
Difficulty: ⭐⭐⭐ · Mathematical core, “hard bone”
2.2.1 Learning Content
| # | Topic | Core Question | Teaching Method |
|---|---|---|---|
| 1 | Why numerical solutions | PDEs have no general analytical solution. The spherical diffusion equation (with time-varying boundary conditions) can only be solved numerically. | Motivation |
| 2 | Spatial discretization basics | Place Nr=50 points uniformly on [0, R]. Spacing dr = R/(Nr−1). Node i=0 is center, i=Nr−1 is surface. Convert continuous c(r,t) to discrete array c[0], c[1], …, c[Nr−1]. | Diagram + example |
| 3 | Finite difference introduction ⭐ | Derive difference formulas from Taylor expansion: f(x+h) = f(x) + h·f’(x) + (h²/2)·f’’(x) + … . 1st-order central difference: (c_{i+1}−c_{i-1})/(2dr). 2nd-order: (c_{i+1}−2c_i+c_{i-1})/dr². Hand-derive Taylor expansion. | Hand-derive Taylor → differences |
| 4 | Spherical Laplacian discretization ⭐⭐ | The most critical step. Substitute difference formulas into ∇²c = ∂²c/∂r² + (2/r)·∂c/∂r, combine like terms to obtain α_i, β_i, γ_i. Hand-derive the combination process. | Hand-derive core derivation |
| 5 | Explicit vs. Implicit Euler | Explicit: c_new = c_old + Δt·D·∇²c_old → simple but Δt < dr²/(2D) ≈ 0.13s (for negative electrode D=3.9e-14, dr≈0.1μm). Implicit: c_new − Δt·D·∇²c_new = c_old → requires solving linear system, but Δt can be arbitrarily large (unconditionally stable). Calculate CFL condition with actual parameters. | Example calculation + comparison |
| 6 | Tridiagonal matrix assembly | Implicit Euler in matrix form: (I − Δt·D·L)·c_new = c_old. L is the discrete Laplacian tridiagonal matrix. Draw the sparse pattern (only three lines). | Diagram: matrix structure |
| 7 | Center boundary (i=0) | At r=0, 1/r → ∞, discrete formula fails. Use L’Hôpital’s rule: lim_{r→0} (2/r)·∂c/∂r = 2·∂²c/∂r². Substituting yields ∇²c₀ = 6(c₁−c₀)/dr². Why 6 and not 4? Hand-derive. | Hand-derive L’Hôpital |
| 8 | Surface Neumann boundary (i=Nr−1) | D·(c_{Nr−1} − c_{Nr−2})/dr = j. Here j comes from the electrochemical reaction (Butler-Volmer), a known quantity. During discharge j<0 → c_surf < c_near (surface concentration lower). | Physical meaning |
| 9 | scipy banded storage | solve_banded((1,1), ab, rhs). Why (1,1)? Lower bandwidth=1, upper bandwidth=1. What do the 3 rows of ab store? ab[0]=upper diagonal, ab[1]=main diagonal, ab[2]=lower diagonal. |
Code interface |
2.2.2 Core Hand-Derivation: Spherical Laplacian Discretization
This is the most important derivation of the entire second course. Recommended to work through on paper step by step:
1 | Given: |
After completing the derivation, open
model.pyand comparealphaandgammain_build_diffusion_matrix— verify that the code matches your derivation exactly.
2.2.3 Hand-Derivation: Center Boundary (i=0)
1 | As r → 0: |
2.2.4 Explicit vs. Implicit: Calculate with Actual Parameters
1 | Parameters: D = 3.9e-14 m²/s, R = 5e-6 m, Nr = 50 |
2.2.5 Generate Figure: diffusion_discretization.png
Subplot 1: Particle discrete grid
- Draw a circle (particle cross-section), mark node positions along a radius
- Nodes 0 (center), 1, 2, …, Nr−1 (surface), marked with dots
- Label dr spacing
- Title: “N=50 nodes, dr = R/(N−1)”
Subplot 2: Tridiagonal matrix structure (spy plot)
- Use
plt.spy()or manually draw non-zero element pattern - Show only three diagonals (upper, main, lower)
- Color-code: main diagonal (blue), upper diagonal (red), lower diagonal (green)
- Label row indices and corresponding node i
- Title: “Banded matrix structure: only adjacent nodes are coupled”
Subplot 3: Boundary condition illustration
- Left: center symmetry condition — c_{-1}=c_1 (ghost mirror), label ∂c/∂r=0
- Right: surface flux condition — D·(c_{Nr−1}−c_{Nr−2})/dr = j, arrow indicating j direction
2.2.6 Extended Thinking (preview for 2.3)
- What does the parameter
(1,1)passed toscipy.linalg.solve_bandedmean? - Why is the surface Neumann boundary placed in the RHS (right-hand side vector) rather than in the matrix?
Session 2.3: Writing Code from Scratch — Rewrite, Compare, Run
Goal: Implement the diffusion solver independently without referencing the original code, then compare and learn
Difficulty: ⭐⭐ · Hands-on practice
2.3.1 Learning Content
| # | Topic | Core Question | Teaching Method |
|---|---|---|---|
| 1 | Understanding scipy interface | Detailed explanation of solve_banded((l,u), ab, rhs) parameters. l=1 (lower bandwidth), u=1 (upper bandwidth), ab is (l+u+1, N) matrix, column-major storage. |
Documentation walkthrough |
| 2 | Write build_diffusion_matrix(N, D, dt, dr, r_nodes) from scratch |
No reference! Based on Session 2.2 derivations, assemble the tridiagonal matrix yourself. Handle three regions: i=0 (center boundary), i=1..N−2 (interior nodes), i=N−1 (surface). | Independent coding |
| 3 | Write a minimal diffusion solver from scratch | Manually set parameters (R=5μm, D=4e-14, Nr=50, dt=1s, j=−1e-6), initialize uniform concentration c_init = 0.5·c_max, loop time steps solving, update surface boundary RHS each step. | Independent coding |
| 4 | Comparison analysis ⭐ | Your implementation vs. model.py original. Key differences: original places surface BC in RHS rather than matrix — why? Which design is clearer? What is the cost of decoupling? Code style differences? |
Code comparison |
| 5 | Parameter experiments | D increased 10× → concentration more uniform (flatter profile); j increased → surface concentration drops faster; Δt changed from 1s to 10s → verify implicit Euler stability; Nr changed from 50 to 20 and 100 → accuracy vs. speed trade-off. | Experiment + plot |
| 6 | Trace step() flow |
Complete walkthrough of step() Step 3 (diffusion part) in model.py: surface flux j → RHS construction → solve_banded → obtain new concentration array. |
Code walkthrough |
2.3.2 Independent Coding Checklist
Create file learning/learning_notes_02_diffusion/diffusion_solver_my.py (purely educational, independent of SPM), containing:
1 | Function signatures to implement from scratch: |
Then write learning/learning_notes_02_diffusion/plot_diffusion_results.py for visualization.
2.3.3 Comparison Analysis Checklist
After completing independent coding, open spm/model.py and compare the following:
| Comparison Point | Your Implementation | model.py Original | Difference Analysis |
|---|---|---|---|
| Surface BC placement | ? | RHS (not in matrix) | Original pre-builds matrix in init (without surface BC), step modifies RHS last entry each time |
| Matrix storage format | ? | (3, Nr) solve_banded | Are they consistent? |
| Diffusion-Chemistry decoupling | ? | Fully independent | Diffusion only cares about j value, not where j comes from |
| Code commenting style | ? | Physical meaning + derivation chain | Any differences? |
| Naming convention | ? | lam, alpha, gamma | Are they consistent? |
2.3.4 Generate Figure: diffusion_simulation.png
Subplot 1: Concentration profile evolution
- X-axis: r (μm), Y-axis: c / c_max (normalized concentration, i.e., SOC)
- Draw multiple curves, each representing different times (t=0, 60s, 300s, 1200s, 3600s)
- Discharge process: surface SOC gradually decreases, interior remains higher
- Labels: surface SOC (lowest point), center SOC (highest point), concentration gradient
Subplot 2: Diffusion coefficient sensitivity
- At the same time point (e.g., t=600s), draw three concentration profiles for different D values
- D=3.9e-14 (baseline), D×5, D×10
- Demonstrate that larger D gives more uniform concentration, smaller D causes deeper surface drop
Subplot 3: Center vs. surface SOC time evolution
- X-axis: time t (s), Y-axis: SOC
- Two curves: c_surf/c_max (surface), c_center/c_max (center)
- Gap between the two curves = degree of concentration polarization
- Label maximum gap point
2.3.5 Your Implementation vs. Original File Structure
1 | learning/learning_notes_02_diffusion/ |
diffusion_simulation_ref.pngis generated by directly callingspm/model.py‘sSPMModelwith the same diffusion scenario, used for visual comparison with your implementation.
V. Preview Questions (Across All Three Sessions)
| # | Question | Related Session |
|---|---|---|
| 1 | Why does sugar eventually distribute uniformly in a cup of water left undisturbed? What drives the sugar molecules? | 2.1 |
| 2 | In spherical coordinates, why does the diffusion equation gain the (2/r)·∂c/∂r term? What would happen without it? | 2.1 |
| 3 | Why choose Implicit Euler over Explicit Euler? Calculate the maximum explicit time step using actual negative electrode parameters. | 2.2 |
| 4 | Why does ∂c/∂r|_{r=0}=0 require modifying the Laplacian discretization? What would happen using the interior node formula directly? | 2.2 |
| 5 | What advantage does banded storage provide for tridiagonal matrices? How many zeros are stored in a full 50×50 matrix? | 2.2 |
| 6 | During discharge, why is the negative electrode surface concentration lower than the interior? What happens if diffusion coefficient D approaches infinity? | 2.1+2.3 |
| 7 | If the surface flux j varies with time (e.g., pulse discharge), where does your code need to change? | 2.3 |
VI. Connection to Next Chapter
After completing the diffusion equation study, the next chapter will cover Butler-Volmer Kinetics (Session 3):
$$
j = j_0 \cdot \left[ \exp!\left(\frac{\alpha F \eta}{RT}\right) - \exp!\left(-\frac{(1-\alpha)F \eta}{RT}\right) \right]
$$
where $j_0 = k \cdot c_e^{1-\alpha} \cdot c_s^{\alpha} \cdot (c_{\mathrm{max}} - c_s)^{1-\alpha}$
Relationship chain between the two chapters:
1 | Diffusion Equation (Ch 2) BV Kinetics (Ch 3) |
Diffusion answers “how is lithium distributed inside the particle”, BV answers “how difficult is the surface reaction”. Together they determine the cell terminal voltage.
VII. Technical Details Memo (for AI assistant reference)
7.1 Figure Generation Standards
- Use matplotlib, Chinese labels use
Microsoft YaHeifont plt.savefig(filename, dpi=150, bbox_inches='tight')- Place in
learning/learning_notes_02_diffusion/directory - At least one figure per session, use
plt.subplotsfor multi-panel layout
7.2 Formula Standards
- Follow
note_specification.md, use KaTeX-compatible syntax - No Chinese inside formulas, use
\mathrm{English}instead of\text{} - Annotate complex formulas with parameter description tables (symbol, name, unit)
7.3 Teaching Principles
- Zero basis: Every new concept starts with an everyday analogy before entering formulas
- Hand-derivation verification: Key derivations require the student to write them out, then verify against code
- Diagrams over text: Use PNG figures wherever possible, no ASCII art
- Comparative learning: Independent implementation → compare with original → understand design philosophy behind differences
VIII. Reference File Index
| Path | Description |
|---|---|
../learning_notes_01_foundation/learning_notes_01_foundation.md |
Course 1 complete notes (OCV + SPM fundamentals) |
../../spm/model.py |
SPM core code (_build_diffusion_matrix, step()) |
../../spm/parameters.py |
Battery parameters (R_n, D_s_n, Nr, dt, etc.) |
../../visualize_ocv.py |
Course 1 figure generation code (style reference) |
../../note_specification.md |
Note writing standards (formulas, formatting) |
Session background file · Version 2.0
Created: 2026-05-22 · Updated: 2026-05-25
Next session: Say “Please read session_02_background.md to begin Session 2.1” in the conversation