codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2004iiipaper-77-channel-profile.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2004/iii/paper-77-channel-profile.py
"""Generate the channel profile in caller CWD; tested with Python 3.14.4.
Uses root numpy/matplotlib dependencies and honors caller MPLCONFIGDIR.
"""
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
b = 30.0
xi = np.linspace(-1.0, 1.0, 2001)
coth_b = 1.0 / np.tanh(b)
profile = (2.0 * np.exp(b * (xi - 1.0)) / (1.0 - np.exp(-2.0 * b))
- coth_b - xi + 1.5 * (coth_b - 1.0 / b) * (1.0 - xi**2))
fig, ax = plt.subplots(figsize=(10, 5), dpi=120, facecolor='white')
ax.set_facecolor('white')
ax.axhline(0.0, color='#737373', linewidth=0.9)
ax.axvline(-1.0, color='#303030', linewidth=2)
ax.axvline(1.0, color='#303030', linewidth=2)
ax.fill_between(xi, 0, profile, where=profile >= 0, color='#d9eaf4')
ax.fill_between(xi, 0, profile, where=profile <= 0, color='#f6dfce')
ax.plot(xi, profile, color='#144c71', linewidth=2.4)
ax.annotate('Upward return flow', xy=(-0.45, 0.55), xytext=(-0.81, 1.04),
arrowprops={'arrowstyle': '->', 'color': '#144c71'}, fontsize=11)
ax.annotate('Downward cell-driven flow', xy=(0.72, -1.1), xytext=(-0.05, -1.55),
arrowprops={'arrowstyle': '->', 'color': '#98552c'}, fontsize=11)
ax.annotate('Illuminated wall', xy=(1.0, 0.0), xytext=(0.48, 0.70),
arrowprops={'arrowstyle': '->', 'color': '#303030'}, fontsize=11)
ax.set(xlim=(-1.08, 1.08), ylim=(-1.85, 1.24), xlabel=r'Cross-channel position $x/a$',
ylabel=r'Vertical velocity $w/W$ (positive upwards)',
title=r'Phototactic channel flow: $\beta a=30$, $W=g^{\prime}n_0a^2/(\mu\beta a)$')
ax.spines[['top', 'right']].set_visible(False)
ax.grid(axis='x', color='#e6e6e6', linewidth=0.6)
fig.tight_layout()
fig.savefig('paper-77-channel-profile.png', facecolor='white', transparent=False)
plt.close(fig)