📖 Read online: https://NGeorgescu.github.io/simulating-electrochemical-reactions-in-python/
A Python-native adaptation of Michael Honeychurch's Simulating Electrochemical Reactions in Mathematica (SERM). This project re-implements the book's electrochemistry and numerical methods as idiomatic Python: a complete, runnable course in digital simulation of electrochemical reactions (diffusion-controlled and kinetically-controlled mass transport, cyclic voltammetry, chronoamperometry, chronopotentiometry, AC voltammetry, adsorbed-species and thin-film responses, and rotating disk electrode voltammetry), built with the finite difference method and related numerical methods on top of NumPy, SciPy, and matplotlib, with SymPy reserved for genuinely symbolic work. Every worked example lives in a Jupyter notebook, and each chapter is checked against the closed-form results of electroanalytical chemistry (Cottrell, Randles–Sevcik, Nicholson–Shain, Sand, Levich, Butler–Volmer kinetics, and a Monte Carlo random-walk model) so the electrochemical simulation code is verified, not just plausible.
Attribution. All physics, algorithms, and the structure of the worked examples are due to Michael Honeychurch, Simulating Electrochemical Reactions in Mathematica. This repository is an independent Python re-implementation for study; the original Mathematica notebooks distributed with the book are the authoritative reference for the science and the numerical algorithms. The Python code here was validated independently against published analytic results (closed-form electrochemistry equations such as the Cottrell equation), not by copying the book's printed numbers.
git clone https://github.com/NGeorgescu/simulating-electrochemical-reactions-in-python.git
cd simulating-electrochemical-reactions-in-python
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtLaunch JupyterLab and open any chapter:
.venv/bin/jupyter labTo run every notebook end-to-end (headless):
for nb in notebooks/*.ipynb; do
.venv/bin/jupyter nbconvert --to notebook --execute --inplace "$nb"
doneA clean run means every chapter's validation asserts held.
notebooks/: the 18 chapter and appendix notebooks; this is the book.serp/: the shared package the notebooks import: finite-difference solvers (tridiagonal,grids), potentialwaveforms,filters,plottinghelpers,kinetics, and anechemlibrary of closed-form references used for validation.tools/nb_extract.py: converts the original Mathematica.nbfiles to plain text so the source algorithms can be read without Mathematica.
The book is re-organised into a Python-native sequence: the original Mathematica
introduction becomes a Python primer (Appendix A), and a generated serp
reference is added as Appendix B. Each chapter validates itself against a
closed-form or independently-computed result; the right-hand column names that
check.
| Ch. | Title | Validation method (in-notebook asserts) |
|---|---|---|
| 01 | Solving partial differential equations | sympy symbolic checks: separation-of-variables residual ≡ 0; Fourier coefficient A₁ = 4/π |
| 02 | Explicit finite differences | Cottrell match (mean rel err < 5e-3); demonstrates D_M > 0.5 instability |
| 03 | Speed and accuracy: implicit & Crank–Nicolson | convergence orders: backward-Euler ≈ 1, Crank–Nicolson ≈ 2 |
| 04 | Other numerical methods: Runge–Kutta, Volterra, SOR | RK/Volterra peak vs Randles–Sevcik constant (< 5e-3); RK2 error decreases on refinement |
| 05 | Potential sweep, reversible CV | peak current vs Randles–Sevcik (< 5e-3) |
| 06 | Potential sweep, quasi/non-reversible | Cottrell certification + reversible limit vs Nicholson–Shain 0.4463 |
| 07 | AC voltammetry | fundamental-harmonic peak ≈ 1/4 located at E⁰ |
| 08 | Potential steps and pulses | Cottrell 1/√t shape check (amplitude is matched at one time first, so it is self-consistent, not an independent prefactor match) < 1e-2; first-order convergence |
| 09 | Chronopotentiometry | Sand product/constant; wave-shape RMSE bound |
| 10 | Thin layers and thin films | thin-layer peak height, voltammogram symmetry, absence of diffusional tail |
| 11 | Strongly adsorbed molecules | surface-wave peak ψ ≈ 1/4 at E⁰, symmetric |
| 12 | Monte Carlo simulations | MSD = 2 D t within statistical tolerance; Cottrell t^(−1/2) slope |
| 13 | Coupled chemical reactions | sim-vs-sim self-consistency: no-reaction limit reproduces the Ch. 5 simulation to machine precision; monotone grid convergence to √λ |
| 14 | Rotating disk electrode voltammetry | independent Levich magnitude vs echem.levich_current (< 5e-3) and Levich-plot linearity R² > 0.9999; the tight Koutecky–Levich assert is an algebraic identity from the same fit, not an independent check |
| 15 | Finite differences with sparse arrays | sparse solver matches dense FD to < 1e-11 |
| 16 | Processing experimental data | smoothing reduces RMS; Savitzky–Golay preserves peak position/height |
| App. A | Python for electrochemical simulation | numpy-vs-list equivalence asserts throughout |
| App. A2 | Semi-integration and fractional calculus | semi-integral plateau matches analytic value (< 2%); sigmoid round-trip correlation > 0.999; fractional power-rule identity (< 5e-3) |
| App. B | The serp package reference (generated) |
auto-rendered signatures/docstrings + one runnable example per module |
| App. C | Setting up your own transport problem (Nernst–Planck, migration) | spherical microelectrode: supported limit recovers i_d = 4πnFDc*a (< 1e-3); unsupported limit recovers the sympy-derived migration factor W = 1 + z_p/|z_a| (= 2 for a monovalent 1:1 case) |
These chapters push past Honeychurch's scope into genuinely two-dimensional convective diffusion, into current distribution (an ohmic potential-field problem rather than mass transport), and into a unified formalism that treats several hydrodynamic geometries at once. Each re-implements the governing equations from primary sources, solves them both in closed form and by an independent numerical method, and asserts the two agree against a published anchor.
| Chapter | Extends into | Validation anchor |
|---|---|---|
| Channel and tubular electrodes | 2-D Lévêque convective diffusion at a wall-mounted band | Limiting-current prefactors 1.47 (channel) / 1.61 (tubular); flow scaling i ∝ Q^(1/3) |
| Primary current distribution on a disk | Laplace potential field / ohmic current distribution (Newman 1966) | Access resistance R = 1/(4 κ a) = 114.7 Ω |
| RRDE collection efficiency | Two-electrode rotating ring–disk convective diffusion (Bard & Faulkner §9.4) | Collection efficiency N = 0.555 |
| Unified convective-diffusion formalism | One Laplace/Airy formalism unifying RDE, RRDE, channel and tube (Tolmachev, Wang & Scherson 1996) | Reproduces Levich 0.620, channel/tube prefactors 1.47/1.61, and N = 0.555 from a single equation |
Beyond the main chapters, notebooks/extras/ collects
supplementary notebooks that port further algorithms and variants from the book,
grouped by the chapter they extend. Each validates itself in the same
assert-backed way and links back to its parent chapter.
Chapter 1: Solving PDEs
Chapter 3: Speed and accuracy
Chapter 4: Other numerical methods
Chapter 5: Potential sweep, reversible
Chapter 6: Potential sweep, non-reversible
Chapter 7: AC voltammetry
Chapter 8: Potential steps and pulses
Chapter 9: Chronopotentiometry
Chapter 10: Thin layers and thin films
Chapter 11: Adsorbed species
Chapter 13: Coupled chemical reactions
Chapter 14: Rotating disk electrode
Chapter 15: Sparse finite differences
- FIRM: the Richtmyer / BDF4 sparse time scheme
- The square scheme on an expanding grid, sparse vs. dense
Appendix A2: Semi-integration
Released under the MIT License. See LICENSE. The MIT license applies
to this independent Python re-implementation only; the original book and its
Mathematica notebooks remain the work of Michael Honeychurch.