codex/past-exam-of-the-chemistry-course-of-the-year-3-of-the-natural-sciences-course-of-the-university-of-cambridge/2022/paper-2a-normal-modes.py

past-exam-of-the-chemistry-course-of-the-year-3-of-the-natural-sciences-course-of-the-university-of-cambridge/2022/paper-2a-normal-modes.py
"""Original solution figure. Tested with Python 3.14, numpy and matplotlib.
The PNG basename is written to the current working directory for Make's _media target.
"""
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from tools.chemistry_diagram import bond, atom, flow, finish, save

fig,axs=plt.subplots(2,2,figsize=(10,4.8))
def model(a,title,arrows,lab,anchor=False):
 bond(a,(0,0),(2.1,0));atom(a,(0,0),'a');atom(a,(2.1,0),'b')
 if anchor:
  a.plot([-.75,-.75],[-.45,.45],color='.4');bond(a,(-.75,0),(0,0),style='dotted')
 for x,d in zip([0,2.1],arrows):flow(a,(x,.45),(x+d,.45))
 a.text(1.05,-.65,lab,ha='center',fontsize=11)
 finish(a,(-1.2,3.4),(-1,1.1),title)
model(axs[0,0],'Free: translation',(.65,.65),r'$\delta y_a=\delta y_b$')
model(axs[0,1],'Free: internal stretch',(-.8,.4),r'$m_a\delta y_a=-m_b\delta y_b$'+'\n'+r'Illustration: $m_b=2m_a$')
model(axs[1,0],'Weak one-end anchoring: low mode',(.65,.65),r'$\omega^2\simeq k_2/(2m)$; translation-like',True)
model(axs[1,1],'Weak one-end anchoring: high mode',(-.6,.6),r'$\omega^2\simeq 2k_1/m+k_2/(2m)$',True)
fig.text(.5,.015,'Surface-bound arrows show leading-order free-mode shapes; anchoring mixes them at first order.',ha='center',fontsize=9)
fig.tight_layout(rect=(0,.045,1,1));save(fig,'paper-2a-normal-modes.png')