codexpast-exam-of-the-advanced-fluid-dynamics-course-of-the-university-of-oxford2023-passing-sphere-rotation.py
past-exam-of-the-advanced-fluid-dynamics-course-of-the-university-of-oxford/2023-passing-sphere-rotation.py
"""Original one-way Stokes-sphere rotation model; write PNG only in cwd.
Tested with Python3.14, NumPy2.3.5, Matplotlib3.10.7; root pyproject.toml.
"""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams.update({'font.family': 'DejaVu Sans', 'font.size': 11})
s = np.linspace(-7, 7, 1001)
rate = -.75/(1+s*s)**1.5
fraction = .5*(1+s/np.sqrt(1+s*s))
fig, axes = plt.subplots(1, 2, figsize=(10.2, 3.9), dpi=130, facecolor='white')
ax = axes[0]
ax.plot(s, rate, color='#236c9d', lw=2)
ax.axhline(0, color='#777777', lw=.7)
ax.axvline(0, color='#888888', ls=':', lw=1)
ax.plot(0, -.75, 'o', color='#236c9d')
ax.text(.4, -.74, 'Closest passage', color='#236c9d')
ax.set(ylabel=r'$\Omega_y\ell^2/(aU)$', title='Rotation about the negative y axis', ylim=(-.85, .055))
ax = axes[1]
ax.plot(s, fraction, color='#9a4a27', lw=2)
ax.axhline(1, color='#888888', ls='--', lw=1)
ax.axvline(0, color='#888888', ls=':', lw=1)
ax.plot(0, .5, 'o', color='#9a4a27')
ax.text(.5, .36, 'Half the final angle\nat closest passage', color='#9a4a27')
ax.set(ylabel=r'$\theta_y/[-3a/(2\ell)]$', title='Finite total angle after passage', ylim=(-.05, 1.1))
for ax in axes:
ax.set(xlim=(-7, 7), xlabel=r'Passage coordinate $Ut/\ell=-Z/\ell$')
ax.spines[['top', 'right']].set_visible(False)
ax.grid(alpha=.18)
fig.suptitle('Prescribed isolated-sphere flow: angular rate and accumulated rotation', fontsize=13)
fig.tight_layout()
fig.savefig(Path.cwd()/Path(__file__).with_suffix('.png').name, facecolor='white', transparent=False)
plt.close(fig)