codexpast-exam-of-the-particle-and-nuclear-physics-course-of-the-university-of-cambridge2022-gauge-cubic-vertices.py
past-exam-of-the-particle-and-nuclear-physics-course-of-the-university-of-cambridge/2022-gauge-cubic-vertices.py
"""Original solution diagrams for the 2022 Particle and Nuclear Physics exam.
Writes the PNG basename into the current working directory.
Dependencies are declared in the repository pyproject.toml.
Tested: Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def wavy(ax, start, finish, amplitude=0.037):
start, finish = np.array(start), np.array(finish)
delta = finish - start
normal = np.array([-delta[1], delta[0]]) / np.linalg.norm(delta)
t = np.linspace(0, 1, 240)
wave = start[:, None] + delta[:, None] * t + amplitude * normal[:, None] * np.sin(14 * np.pi * t)
ax.plot(wave[0], wave[1], color="#275e85", linewidth=1.55)
def main():
vertices = [['$g$', '$g$', '$g$'], ['$W^+$', '$W^-$', '$\\gamma$'], ['$W^+$', '$W^-$', '$Z$']]
ncols = 3
nrows = (len(vertices) + ncols - 1) // ncols
fig, axs = plt.subplots(nrows, ncols, figsize=(8.1, 2.9 * nrows), squeeze=False)
for ax, names in zip(axs.flat, vertices):
angle = np.linspace(np.pi / 2, np.pi / 2 + 2 * np.pi, len(names), endpoint=False)
for theta, name in zip(angle, names):
endpoint = 0.73 * np.array([np.cos(theta), np.sin(theta)])
wavy(ax, (0, 0), endpoint)
label = 1.02 * np.array([np.cos(theta), np.sin(theta)])
ax.text(*label, name, ha="center", va="center", fontsize=14)
ax.scatter([0], [0], color="#333333", s=18, zorder=5)
ax.set_xlim(-1.3, 1.3)
ax.set_ylim(-1.3, 1.3)
ax.set_aspect("equal")
ax.axis("off")
for ax in list(axs.flat)[len(vertices):]:
ax.axis("off")
fig.suptitle('Three cubic gauge-boson vertex types', fontsize=13)
fig.tight_layout(rect=(0, 0, 1, 0.94))
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=140, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()