codex/methane-chlorination-radical-bookkeeping.py

methane-chlorination-radical-bookkeeping.py
"""Generate methane-chlorination-radical-bookkeeping.png in CWD.

Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
Electron and chain-carrier bookkeeping, not spectral or kinetic measurements.
Run from _media with MPLBACKEND=Agg and MPLCONFIGDIR in /tmp.
"""

from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyBboxPatch


def electron(ax, x, y, color="#216c91"):
    ax.add_patch(Circle((x, y), 0.055, facecolor=color, edgecolor="none"))


def main():
    fig, axes = plt.subplots(1, 2, figsize=(10.2, 5.4), dpi=120, facecolor="white",
                             gridspec_kw={"width_ratios": [1.5, 1]})
    for ax in axes:
        ax.set(xlim=(0, 6), ylim=(0, 6))
        ax.axis("off")
    left, right = axes
    fig.suptitle("Methane chlorination transfers a neutral radical carrier",
                 fontsize=14, weight="bold", y=0.98)
    left.text(3, 5.65, "Initiation: split one bonding pair", ha="center",
              fontsize=12, weight="bold")
    for x, label in [(0.6, "Cl"), (1.9, "Cl"), (4.2, "Cl"), (5.4, "Cl")]:
        left.text(x, 4.93, label, ha="center", va="center", fontsize=15)
    electron(left, 1.13, 4.93)
    electron(left, 1.36, 4.93, "#b46c27")
    left.annotate("", (3.65, 4.93), (2.4, 4.93), arrowprops={"arrowstyle": "->", "lw": 1.6})
    left.text(3.03, 5.20, r"$h\nu$", ha="center", fontsize=13)
    electron(left, 4.58, 4.93)
    electron(left, 5.78, 4.93, "#b46c27")
    left.text(3, 4.40, "0 carriers → 2 carriers; total charge stays zero", ha="center", fontsize=11)
    left.text(3, 3.83, "Propagation: replace one carrier", ha="center",
              fontsize=12, weight="bold")
    equations = [r"$\mathrm{Cl}^{\bullet}+\mathrm{CH}_4\ \longrightarrow\ \mathrm{HCl}+\mathrm{CH}_3^{\bullet}$",
                 r"$\mathrm{CH}_3^{\bullet}+\mathrm{Cl}_2\ \longrightarrow\ \mathrm{CH}_3\mathrm{Cl}+\mathrm{Cl}^{\bullet}$"]
    for y, equation in zip([3.12, 2.12], equations):
        left.text(3, y, equation, ha="center", fontsize=14)
        left.text(3, y - 0.42, "1 carrier → 1 carrier", ha="center", fontsize=11, color="#216c91")
    left.text(3, 1.22, "Sum: cancel both intermediate radicals", ha="center", fontsize=11)
    left.text(3, 0.64, r"$\mathrm{CH}_4+\mathrm{Cl}_2\ \longrightarrow\ \mathrm{CH}_3\mathrm{Cl}+\mathrm{HCl}$",
              ha="center", fontsize=14)
    right.add_patch(FancyBboxPatch((0.12, 0.35), 5.75, 5.28, boxstyle="round,pad=0.04",
                                   facecolor="#faf5ed", edgecolor="#c6aa89"))
    right.text(3, 5.25, "Termination: form a bonding pair", ha="center",
               fontsize=12, weight="bold")
    right.text(3, 4.53, r"$2\mathrm{CH}_3^{\bullet}\longrightarrow\mathrm{C}_2\mathrm{H}_6$",
               ha="center", fontsize=16)
    right.text(3, 3.92, "2 carriers → 0 carriers", ha="center", fontsize=12, color="#9a5a20")
    for x, label in [(1.0, r"$R$"), (2.4, r"$R$"), (4.35, r"$R$"), (5.48, r"$R$")]:
        right.text(x, 3.10, label, fontsize=17, ha="center", va="center")
    electron(right, 1.4, 3.10)
    electron(right, 2.0, 3.10, "#b46c27")
    right.annotate("", (3.97, 3.10), (2.84, 3.10), arrowprops={"arrowstyle": "->", "lw": 1.6})
    electron(right, 4.78, 3.10)
    electron(right, 5.03, 3.10, "#b46c27")
    right.text(3, 2.40, r"$R=\mathrm{CH}_3$; only reacting electrons shown", ha="center", fontsize=11)
    right.text(3, 1.66, "Radical count need not be conserved.", ha="center", fontsize=11.2)
    right.text(3, 1.13, "Atoms, electrons and charge are conserved.", ha="center", fontsize=11.2)
    right.text(3, 0.65, "Schematic; not rates or an EPR spectrum.", ha="center", fontsize=10.7)
    fig.subplots_adjust(left=0.015, right=0.985, bottom=0.03, top=0.90, wspace=0.13)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()