codex/past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2005/ii/paper-3-orbits.py

past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2005/ii/paper-3-orbits.py
"""Energy orbits; Python 3.14, numpy 2.3.5, matplotlib 3.10.7.

Writes one opaque PNG basename to the caller's current directory. MPLCONFIGDIR
is left under caller control. No source image or external data are used.
"""
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

mu=1.0
fig,axes=plt.subplots(1,2,figsize=(9,4.2),layout='constrained',facecolor='white')
for ax,E in zip(axes,[0.05,25.0]):
    q0=mu*np.sqrt(E/(E+1));p0=mu*np.sqrt(E)
    theta=np.linspace(0,2*np.pi,700)
    ax.plot(q0*np.cos(theta),p0*np.sin(theta),color='#165a96',lw=2.1)
    ax.annotate('',xy=(q0*np.cos(1.35),p0*np.sin(1.35)),
        xytext=(q0*np.cos(1.8),p0*np.sin(1.8)),
        arrowprops={'arrowstyle':'->','color':'#165a96','lw':2})
    ax.axhline(0,color='0.55',lw=.8);ax.axvline(0,color='0.55',lw=.8)
    extent=max(q0*1.18,0.26)
    ax.set_xlim(-extent,extent);ax.set_ylim(-1.18*p0,1.18*p0)
    ax.set_facecolor('white');ax.set_xlabel(r'Position $q$');ax.set_ylabel(r'Momentum $p$')
    ax.set_title(('Low energy' if E<1 else 'High energy')+fr': $E={E:g}$')
    ax.grid(alpha=.2)
    ax.set_aspect('equal',adjustable='box')
    if E>1:
        for wall in [-mu,mu]:ax.axvline(wall,color='#ad4335',ls='--',lw=1)
        ax.text(0,-1.11*p0,r'Dashed lines: $q=\pm\mu$',ha='center',fontsize=9)
fig.suptitle(r'Periodic energy curves, $\mu=1$: $p^2+(E+1)q^2=E$')
fig.savefig('paper-3-orbits.png',dpi=140,facecolor='white',transparent=False)
plt.close(fig)