codex/de-broglie-wavelength-momentum-voltage.py

de-broglie-wavelength-momentum-voltage.py
"""Formula plots; Python 3.14, matplotlib 3.10.7, numpy 2.3.5.

Run from _media; output uses this script's basename in the current directory.
No experimental observations are plotted.
"""
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

H = 6.62607015e-34  # J s, exact SI definition
E_CHARGE = 1.602176634e-19  # C, exact SI definition
E_MASS = 9.1093837139e-31  # kg, 2022 CODATA central value


def wavelength_from_voltage(voltage):
    """Nonrelativistic electron wavelength in metres, initially at rest."""
    return H / np.sqrt(2 * E_MASS * E_CHARGE * np.asarray(voltage))


def main():
    plt.rcParams.update({"font.size": 11, "axes.spines.top": False,
                         "axes.spines.right": False, "figure.facecolor": "white",
                         "axes.facecolor": "white", "savefig.facecolor": "white"})
    fig, (ax_p, ax_u) = plt.subplots(1, 2, figsize=(10, 4.6))
    fig.subplots_adjust(left=0.085, right=0.975, bottom=0.21, top=0.79, wspace=0.32)
    fig.suptitle("de Broglie wavelength: momentum and electron accelerating voltage", y=0.96, fontsize=14)
    fig.text(0.5, 0.87, "Calculated relations • negligible initial energy • no measured data",
             ha="center", color="#444444")

    momentum = np.geomspace(1e-24, 1.4e-23, 600)
    ax_p.loglog(momentum / 1e-24, H / momentum / 1e-9, color="#2367a2", lw=2.5)
    ax_p.set(xlabel=r"Momentum magnitude $p$ ($10^{-24}$ kg m s$^{-1}$)",
             ylabel=r"Wavelength $\lambda$ (nm)", title=r"Any free particle: $\lambda=h/p$")
    ax_p.set_xticks([1, 2, 4, 8, 12], labels=["1", "2", "4", "8", "12"])
    ax_p.set_yticks([0.05, 0.1, 0.2, 0.4, 0.6], labels=["0.05", "0.1", "0.2", "0.4", "0.6"])
    ax_p.minorticks_off()
    ax_p.grid(alpha=0.2)
    ax_p.text(0.08, 0.1, r"Double $p$ → halve $\lambda$", transform=ax_p.transAxes)

    voltage = np.geomspace(10, 500, 600)
    ax_u.loglog(voltage, wavelength_from_voltage(voltage) / 1e-9, color="#9a4f1b", lw=2.5)
    ax_u.set(xlabel=r"Accelerating voltage $U$ (V)", ylabel=r"Wavelength $\lambda$ (nm)",
             title=r"Electron: $\lambda=h/\sqrt{2m_e eU}$")
    for u, offset in [(54, (10, 15)), (100, (10, -28)), (400, (-105, 12))]:
        lam = float(wavelength_from_voltage(u) / 1e-9)
        ax_u.plot(u, lam, "o", color="#9a4f1b", ms=5)
        ax_u.annotate(f"{u} V: {lam:.4f} nm", (u, lam), xytext=offset,
                      textcoords="offset points", fontsize=10,
                      arrowprops={"arrowstyle": "-", "color": "#888888"})
    ax_u.set_xticks([10, 20, 50, 100, 200, 500], labels=["10", "20", "50", "100", "200", "500"])
    ax_u.set_yticks([0.05, 0.1, 0.2, 0.4], labels=["0.05", "0.1", "0.2", "0.4"])
    ax_u.minorticks_off()
    ax_u.grid(alpha=0.2)
    fig.text(0.5, 0.065, "Both axes use logarithmic scales.  Quadrupling voltage doubles momentum and halves wavelength.",
             ha="center", fontsize=10)
    fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name, dpi=120, transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()