codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2004iiipaper-79-collimating-interface.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2004/iii/paper-79-collimating-interface.py
"""Original ray/front plot; tested Python 3.14 with root NumPy/Matplotlib pins.
Only output is a same-basename opaque PNG in caller CWD. Preserves MPLCONFIGDIR.
"""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
def geometry(radius):
# z0=1, alpha=3, alpha_f=1; solid rho=2, beta=1.5; fluid rho=1.
alpha, alpha_f, z0 = 3.0, 1.0, 1.0
s = z0 * (alpha - alpha_f)
d2 = alpha ** 2 - alpha_f ** 2
D = np.sqrt(s ** 2 + d2 * np.asarray(radius) ** 2)
Z = (alpha * s + alpha_f * D) / d2
r = (alpha * D + alpha_f * s) / d2
return Z, r, D
def displacement_coefficient(radius):
alpha, alpha_f, beta, rho, rho_f = 3.0, 1.0, 1.5, 2.0, 1.0
_, r, D = geometry(radius)
denom_angle = np.sqrt(4 + alpha ** 2 * radius ** 2)
sinP = alpha * radius / denom_angle
cosP = 2 / denom_angle
sinS = beta / alpha * sinP
cosS = np.sqrt(1 - sinS ** 2)
cosF = D / denom_angle
C = 1 - 2 * sinS ** 2
E = C ** 2 + (beta / alpha) ** 2 * (2 * sinP * cosP) * (2 * sinS * cosS)
T = 2 * rho * alpha_f * C * cosP / (rho_f * alpha_f * cosP + rho * alpha * E * cosF)
return T / (alpha_f * r)
def main():
fig, axes = plt.subplots(1, 2, figsize=(11.0, 4.5), layout='constrained', facecolor='white')
x = np.linspace(-4, 4, 701)
Z, _, _ = geometry(np.abs(x))
ax = axes[0]
ax.fill_between(x, 0, Z, color='C1', alpha=0.08)
ax.fill_between(x, Z, 3.55, color='C0', alpha=0.06)
ax.plot(x, Z, color='black', label='Solid–fluid interface')
for hit in [-3.5, -2, -0.8, 0, 0.8, 2, 3.5]:
height, _, _ = geometry(abs(hit))
ax.plot([0, hit], [0, height], color='C1', linewidth=1)
ax.plot([hit, hit], [height, 3.45], color='C0', linewidth=1)
ax.annotate('', xy=(hit, 3.35), xytext=(hit, 3.05),
arrowprops={'arrowstyle': '->', 'color': 'C0'})
ax.scatter([0], [0], color='black', zorder=4)
ax.axhline(3.0, linestyle='--', color='0.45', label='Equal arrival time')
ax.text(-3.7, 0.85, 'Solid', fontsize=10)
ax.text(-3.7, 3.3, 'Fluid', fontsize=10)
ax.set(xlabel=r'Meridional coordinate / $z_0$', ylabel=r'Height / $z_0$',
title='Spherical incidence, parallel transmitted rays', xlim=(-4, 4), ylim=(-0.12, 3.55))
ax.legend(loc='lower left', fontsize=8)
R = np.geomspace(0.02, 1000, 1000)
ax = axes[1]
ax.loglog(R, displacement_coefficient(R), label='Exact leading-front transfer')
far = R[R >= 3]
ax.loglog(far, 8 / (9 * far ** 2), '--', label=r'Large-$R$ coefficient $8/(9R^2)$')
ax.hlines(4 / 7, 0.02, 0.25, color='0.5', linestyle=':', label=r'$A_u(0)=4/7$')
ax.set(xlabel=r'$R/z_0$', ylabel=r'Displacement coefficient $A_u$',
title=r'$\alpha=3,\ \beta=1.5,\ \alpha_f=1,\ \rho/\rho_f=2$', xlim=(0.02, 1000))
ax.grid(alpha=0.2, which='both')
ax.legend(fontsize=8, loc='lower left')
fig.savefig(Path(__file__).with_suffix('.png').name, dpi=140, facecolor='white', transparent=False)
plt.close(fig)
if __name__ == '__main__':
main()