codex/past-exam-of-the-mathematics-course-of-the-university-of-oxford/2017/prelims/mathematics-iv-q4-collision-threshold.py

past-exam-of-the-mathematics-course-of-the-university-of-oxford/2017/prelims/mathematics-iv-q4-collision-threshold.py
"""Plot the spring-charge energy barrier. Python 3.14; project pyproject.toml.

Run from the matching _media directory. Write only the PNG in the current directory.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np


def main():
    s = np.linspace(0.15, 1, 900)
    fig, ax = plt.subplots(figsize=(7.4, 4.2), layout='constrained')
    fig.set_facecolor('white')
    for ell, color, label in [
        (1.95, '#1966a6', r'$\ell_1<\ell<\ell_2$: collision'),
        (2.00, '#9a6000', r'$\ell=\ell_2$: asymptotic approach'),
        (2.20, '#a02040', r'$\ell>\ell_2$: turning point'),
    ]:
        relative_potential = 0.5 * (1-s)**2 + (1-1/s)/ell**3
        ax.plot(s, relative_potential, color=color, lw=2, label=label)
    ell = 2.2
    turning = (1 + np.sqrt(1-8/ell**3))/2
    ax.plot([turning, 1], [0, 0], 'o', color='#a02040', ms=5)
    ax.plot(0.5, 0, 'o', color='#9a6000', ms=5)
    ax.axhline(0, color='#333333', lw=0.8)
    ax.annotate('released from rest', xy=(1, 0), xytext=(0.73, 0.034),
                arrowprops={'arrowstyle': '->', 'color': '#333333'}, fontsize=10)
    ax.annotate('forbidden barrier', xy=(0.39, 0.041), xytext=(0.18, 0.068),
                arrowprops={'arrowstyle': '->', 'color': '#a02040'}, fontsize=10,
                color='#a02040')
    ax.set(xlim=(0.15, 1.03), ylim=(-0.065, 0.105),
           xlabel=r'Position $s=x/\ell$', ylabel=r'$(V-E)/(k\ell^2)$',
           title='Motion is allowed where the curve is at or below zero')
    ax.grid(alpha=0.2)
    ax.legend(loc='lower right', fontsize=9, framealpha=1)
    fig.savefig('mathematics-iv-q4-collision-threshold.png', dpi=150,
                facecolor='white', transparent=False)
    plt.close(fig)


if __name__ == '__main__':
    main()