codexelectrolyte-ion-drift-current.py
electrolyte-ion-drift-current.py
"""Show ion drift and conventional current; write basename.png to CWD.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
Uniform-field bulk toy model in a driven electrolytic cell. No diffusion,
convection, or electrode boundary layers. Arrow lengths are schematic.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np
def arrow(ax, start, end, y, color, width=2.5):
ax.annotate("", xy=(end, y), xytext=(start, y),
arrowprops={"arrowstyle": "-|>", "color": color,
"lw": width, "mutation_scale": 17})
def main():
elementary_charge = 1.602176634e-19
n = np.array([1e25, 1e25])
q = elementary_charge * np.array([1.0, -1.0])
vx = np.array([2e-4, -3e-4])
jx = n * q * vx
blue, orange = "#236d99", "#b6531f"
fig, ax = plt.subplots(figsize=(10, 6.6))
fig.patch.set_facecolor("white")
fig.subplots_adjust(left=0.03, right=0.97, bottom=0.14, top=0.86)
for x in (0.6, 9.0):
ax.add_patch(Rectangle((x, 3.1), 0.4, 3.0, facecolor="#dddddd",
edgecolor="#555555", linewidth=1.4))
ax.text(0.8, 6.35, "+ anode\nOxidation", ha="center", fontsize=12)
ax.text(9.2, 6.35, "− cathode\nReduction", ha="center", fontsize=12)
arrow(ax, 3.6, 6.4, 5.9, "#333333")
ax.text(5.0, 6.12, "Uniform electric field E →", ha="center", fontsize=12)
ax.scatter([3.2, 6.8], [4.9, 3.8], s=650, c=[blue, orange],
edgecolors="white", linewidths=1)
ax.text(3.2, 4.9, "+", color="white", ha="center", va="center", fontsize=19)
ax.text(6.8, 3.8, "−", color="white", ha="center", va="center", fontsize=19)
arrow(ax, 3.65, 7.5, 4.9, blue)
arrow(ax, 6.35, 2.5, 3.8, orange)
ax.text(4.7, 5.22, "Cation drift: v₊,ₓ > 0", color=blue, fontsize=12,
ha="center")
ax.text(5.3, 4.12, "Anion drift: v₋,ₓ < 0", color=orange, fontsize=12,
ha="center")
ax.plot([1.4, 8.6], [2.9, 2.9], color="#cccccc", lw=1)
ax.text(5.0, 2.56, "Conventional current contributions: n q vₓ", ha="center",
fontsize=13, weight="bold")
for k, (y, color, sign) in enumerate([(1.85, blue, "+"), (0.8, orange, "−")]):
ax.text(1.5, y + 0.23, f"q = {sign}e", color=color, fontsize=12)
arrow(ax, 3.5, 7.7, y, color)
ax.text(5.6, y + 0.23, f"J{'₊' if k == 0 else '₋'},ₓ = {jx[k]:.6f} A/m² > 0",
color=color, fontsize=12, ha="center")
ax.text(5.0, 0.08, f"Both point right: total Jₓ = {jx.sum():.6f} A/m²",
ha="center", fontsize=12, weight="bold")
ax.set_xlim(0, 10)
ax.set_ylim(-0.2, 7.0)
ax.axis("off")
fig.suptitle("Opposite ion motion, same conventional current", fontsize=17, y=0.97)
fig.text(0.5, 0.905, "Driven electrolytic cell: external source fixes the electrode signs",
ha="center", fontsize=12)
fig.text(0.5, 0.065, "Toy inputs: n₊ = n₋ = 10²⁵ m⁻³; v₊,ₓ = +2 × 10⁻⁴ m/s; v₋,ₓ = −3 × 10⁻⁴ m/s.",
ha="center", fontsize=10.5)
fig.text(0.5, 0.03, "Uniform bulk field; no diffusion or convection; schematic arrow lengths.",
ha="center", fontsize=10.5, color="#444444")
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=100,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()