codexpast-exam-of-the-fluids-and-waves-course-of-the-university-of-oxford2021-streamlines.py
past-exam-of-the-fluids-and-waves-course-of-the-university-of-oxford/2021-streamlines.py
"""Draw the instantaneous streamlines in Oxford A10 (2021), question 1(a).
Run from the desired output directory. Tested with Python 3.14.4 and the
NumPy/Matplotlib versions in the repository's root pyproject.toml.
"""
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
t = 0.35
x = np.linspace(-2.1, 2.1, 501)
y = np.linspace(-2.6, 2.6, 541)
xx, yy = np.meshgrid(x, y)
fig, axes = plt.subplots(1, 2, figsize=(8.0, 4.4), facecolor="white")
for ax, omega, caption in zip(
axes,
(1.8, 0.6),
(r"$\Omega=1.8$: ellipses", r"$\Omega=0.6$: hyperbolas"),
):
psi = omega * (np.exp(2 * t) * xx**2 + np.exp(-2 * t) * yy**2) / 2 - xx * yy
if omega > 1:
ax.contour(xx, yy, psi, levels=(0.12, 0.3, 0.6, 1.0, 1.5), colors="#176b93", linewidths=1.5)
else:
ax.contour(xx, yy, psi, levels=(-0.9, -0.4, -0.12), colors="#b4591c", linestyles="solid", linewidths=1.5)
ax.contour(xx, yy, psi, levels=(0.12, 0.4, 0.9), colors="#176b93", linewidths=1.5)
ax.contour(xx, yy, psi, levels=(0,), colors="#5a476f", linewidths=1.8)
# Arrows tangent to the same frozen velocity field, of equal drawn length.
for px, py in ((0.0, 1.2), (0.0, -1.2), (0.75, 0.0), (-0.75, 0.0)):
vx = -px + omega * np.exp(-2 * t) * py
vy = py - omega * np.exp(2 * t) * px
norm = np.hypot(vx, vy)
vx, vy = 0.29 * vx / norm, 0.29 * vy / norm
ax.annotate("", xy=(px + vx / 2, py + vy / 2), xytext=(px - vx / 2, py - vy / 2), arrowprops={"arrowstyle": "->", "color": "#333333", "lw": 1.5})
ax.plot(0, 0, "o", color="black", ms=4)
ax.axhline(0, color="0.8", lw=0.6, zorder=0)
ax.axvline(0, color="0.8", lw=0.6, zorder=0)
ax.set(xlim=(-2.1, 2.1), ylim=(-2.6, 2.6), xlabel="$x$", ylabel="$y$", title=caption)
ax.set_aspect("equal")
ax.spines[["top", "right"]].set_visible(False)
ax.set_facecolor("white")
axes[1].text(0.03, 0.03, "Purple: straight separatrices", transform=axes[1].transAxes, fontsize=9, color="#5a476f", bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.9})
fig.suptitle(r"Instantaneous streamlines at $t=0.35$", fontsize=13)
fig.tight_layout()
fig.savefig("2021-streamlines.png", dpi=150, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()