codexion-trap-functional-comparison.py
ion-trap-functional-comparison.py
"""Original ideal-field comparison; Python 3.14, matplotlib 3.10.7.
Run from _media; the drawing is functional, not a historical reconstruction.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyArrowPatch, Rectangle
import numpy as np
def main():
fig, axes = plt.subplots(1, 2, figsize=(10, 5.6), facecolor="white")
blue, red, grey = "#176a97", "#b44736", "#4d5965"
for ax in axes:
ax.set(xlim=(-2.6, 2.6), ylim=(-2.4, 2.8), aspect="equal")
ax.axis("off")
for z in (-1.35, 1.35):
ax.add_patch(Rectangle((-.8, z-.10), 1.6, .20,
facecolor="#dde5eb", edgecolor=grey, lw=1.5))
for x in (-1.25, 1.25):
ax.add_patch(Rectangle((x-.13, -.5), .26, 1,
facecolor="#dde5eb", edgecolor=grey, lw=1.5))
ax.add_patch(Circle((0, 0), .085, color="#201f25", zorder=5))
ax.text(0, 1.65, "endcap", ha="center", color=grey, fontsize=10)
ax.text(1.5, -.75, "ring section", ha="center", color=grey, fontsize=10)
ax.text(-.18, -.28, "charge Q", ha="right", fontsize=10)
ax = axes[0]
ax.set_title("Paul trap: oscillating electric field", fontsize=13, pad=18)
ax.text(0, 2.18, r"$\Phi\propto-\cos(\Omega t)(x^2+y^2-2z^2)$",
ha="center", fontsize=12)
for sign in (-1, 1):
ax.add_patch(FancyArrowPatch((sign*.95, 0), (sign*.3, 0),
arrowstyle="->", mutation_scale=14, color=blue, lw=2))
ax.add_patch(FancyArrowPatch((0, sign*.3), (0, sign*1.05),
arrowstyle="->", mutation_scale=14, color=red, lw=2))
ax.text(-2.4, .6, r"phase $\Omega t=\pi$", fontsize=10, color=grey)
ax.text(0, -1.8, "Electric focusing reverses each half-cycle.",
ha="center", fontsize=11)
ax.text(0, -2.18, "Small q: slow oscillation + RF micromotion",
ha="center", fontsize=11, color=blue)
ax = axes[1]
ax.set_title("Penning trap: static electric + magnetic fields", fontsize=13, pad=18)
ax.text(0, 2.18, r"$Q\Phi=\frac{m\omega_z^2}{2}[z^2-(x^2+y^2)/2]$",
ha="center", fontsize=12)
for sign in (-1, 1):
ax.add_patch(FancyArrowPatch((0, sign*1.05), (0, sign*.3),
arrowstyle="->", mutation_scale=14, color=blue, lw=2))
for x in (-2.05, 2.05):
ax.annotate("", (x, 1.3), (x, -1.05),
arrowprops={"arrowstyle": "->", "color": "#6b4aa5", "lw": 2})
ax.text(1.8, 1.55, r"$\mathbf{B}$", fontsize=14, color="#6b4aa5")
theta = np.linspace(0, 2*np.pi, 200)
ax.plot(.63*np.cos(theta), .20*np.sin(theta), color="#6b4aa5", lw=2)
ax.text(-1.0, .80, "axial E\nrestoring force", fontsize=10, color=blue,
ha="center")
ax.text(0, -1.8, "Magnetic bending confines transverse motion.",
ha="center", fontsize=11)
ax.text(0, -2.18, r"Ideal model: $\omega_c^2>2\omega_z^2>0$",
ha="center", fontsize=11, color="#6b4aa5")
fig.suptitle("Two ways around static electric confinement", fontsize=16, y=.99)
fig.text(.5, .025, "Schematic meridional sections; arrows show forces on the chosen charge. Not to scale.",
ha="center", fontsize=10, color=grey)
fig.subplots_adjust(left=.02, right=.98, bottom=.10, top=.84, wspace=.08)
fig.savefig(Path(__file__).stem + ".png", dpi=130, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()