codex/past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2017/ii/paper-1-relativistic-drift.py

past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2017/ii/paper-1-relativistic-drift.py
"""Original crossed-field trajectories, Cambridge 2017 II paper 1 Q35.
Output same-basename PNG in CWD. Python 3.14.4, matplotlib 3.10.7+dfsg1,
numpy 2.3.5 tested; project pins Python3.14/matplotlib3.10.7/numpy2.3.5.
"""
import os
os.environ.setdefault('MPLCONFIGDIR','/tmp/2017-ii-paper-1-mpl-cache')
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from pathlib import Path
fig,axs=plt.subplots(1,2,figsize=(10.4,4.5),dpi=100,facecolor='white')
for ax,beta,uc,label in zip(axs,[.005,.5],[.5,.05],['Small drift: nearly closed loops','Large drift: progressing oscillations']):
 d=beta/uc;gamma=1/np.sqrt(1-beta**2);s=np.linspace(0,6*np.pi,2401)
 x=gamma*(d*s+np.sin(s));y=np.cos(s)
 ax.plot(x,y,color='#0072B2',lw=1.7)
 for i in [250,850,1450,2050]:ax.annotate('',xy=(x[i+20],y[i+20]),xytext=(x[i],y[i]),arrowprops={'arrowstyle':'->','color':'#0072B2','lw':1.3})
 ax.set(xlabel=r'$\widetilde x$',ylabel=r'$\widetilde y$',ylim=(-1.3,1.3),title=label+'\n'+rf'$\beta={beta:g},\ u/c={uc:g},\ 2\pi\beta/(u/c)={2*np.pi*d:.3g}$')
 ax.axhline(0,color='gray',lw=.5)
 if d<1:ax.set_aspect('equal',adjustable='box')
 else:ax.text(.5,-.30,'Horizontal scale compressed to show three periods',transform=ax.transAxes,ha='center',fontsize=9)
fig.subplots_adjust(left=.07,right=.99,top=.80,bottom=.24,wspace=.35)
fig.savefig(Path.cwd()/(Path(__file__).stem+'.png'),facecolor='white',transparent=False)