codex/past-exam-of-the-physics-b-course-of-the-university-of-cambridge/2016/paper-2-diatomic-heat-capacity.py

past-exam-of-the-physics-b-course-of-the-university-of-cambridge/2016/paper-2-diatomic-heat-capacity.py
"""Original explanatory figure; Python 3.14 and root pyproject dependencies."""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.rcParams.update({"font.size":10,"axes.spines.top":False,"axes.spines.right":False,"figure.facecolor":"white","axes.facecolor":"white"})

t=np.geomspace(.025,2000,1200);J=np.arange(0,301,dtype=float);ener=J*(J+1);W=(2*J[:,None]+1)*np.exp(-ener[:,None]/t[None,:]);Z=W.sum(axis=0);mean=(W*ener[:,None]).sum(axis=0)/Z;var=(W*ener[:,None]**2).sum(axis=0)/Z-mean**2;crot=var/t**2
x=50/t;ev=np.exp(-x);cvib=x*x*ev/(-np.expm1(-x))**2;total=1.5+crot+cvib
fig,ax=plt.subplots(figsize=(7.4,4.3),layout="constrained");ax.semilogx(t,total,color="#1565c0",lw=2.3,label="Translation + quantum rotation + vibration")
for v,label in [(1.5,r"$3/2$"),(2.5,r"$5/2$"),(3.5,r"$7/2$")]:ax.axhline(v,color="#bbb",ls=":",lw=1)
ax.set(xlabel=r"Temperature / rotational temperature $\Theta_r$",ylabel=r"Molar $C_V/R$",ylim=(1.3,3.7),xlim=(t[0],t[-1]),yticks=[1.5,2.5,3.5],yticklabels=[r"$3/2$",r"$5/2$",r"$7/2$"],title=r"Ideal diatomic model: $\Theta_v/\Theta_r=50$")
ax.annotate("Rotational activation",(1,total[np.argmin(abs(t-1))]),xytext=(.09,3.0),arrowprops={"arrowstyle":"->"},fontsize=9);ax.annotate("Vibrational activation",(30,total[np.argmin(abs(t-30))]),xytext=(8,3.55),arrowprops={"arrowstyle":"->"},fontsize=9)
ax.text(.04,1.38,"Fixed intact molecules; no condensation, dissociation or nuclear-spin statistics.",fontsize=8);ax.grid(alpha=.16,which="both")

fig.savefig(Path(__file__).stem+".png",dpi=150,facecolor="white",bbox_inches="tight")
plt.close(fig)