codexpast-exam-of-the-differential-equations-2-course-of-the-university-of-oxford2021-boundary-layer.py
past-exam-of-the-differential-equations-2-course-of-the-university-of-oxford/2021-boundary-layer.py
#!/usr/bin/env python3
"""Oxford A6 2021, Q3(c): leading composite and inner approximations.
Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7 (repository dependencies).
These are asymptotic profiles, not numerical or exact BVP solutions.
Run in the output directory; writes 2021-boundary-layer.png there.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.linspace(1, 2, 2401)
fig, ax = plt.subplots(figsize=(8.2, 4.2), layout="constrained")
fig.patch.set_facecolor("white")
outer = np.exp(x - 1)
for eps, color in [(0.04, "#176aa5"), (0.08, "#b45224")]:
composite = outer - np.e * np.exp(-2 * (2 - x) / eps)
ax.plot(x, composite, color=color, lw=2,
label=rf"composite, $\epsilon={eps}$")
ax.plot(x, outer, color="#555555", lw=1.6, ls="--", label="outer")
ax.scatter([1, 2], [1, 0], color="#222222", s=24, zorder=5)
ax.annotate("right boundary layer", (1.985, 0.85), xytext=(1.60, 0.50),
fontsize=10, arrowprops={"arrowstyle": "->"})
ax.set(xlim=(1, 2), ylim=(-0.05, 2.95), xlabel="$x$", ylabel="leading approximation")
ax.grid(alpha=0.16)
ax.legend(loc="upper left", fontsize=9)
ax.spines[["top", "right"]].set_visible(False)
inset = ax.inset_axes([0.17, 0.15, 0.35, 0.24])
X = np.linspace(0, 3.5, 501)
inset.plot(X, np.e * (1 - np.exp(-2 * X)), color="#3a7d44", lw=1.7)
inset.axhline(np.e, color="#555555", ls="--", lw=0.9)
inset.set(xlim=(0, 3.5), ylim=(0, 2.95), xlabel=r"$X=(2-x)/\epsilon$",
title=r"Inner: $e(1-e^{-2X})$")
inset.set_yticks([0, np.e], ["0", "$e$"])
inset.tick_params(labelsize=8)
inset.xaxis.label.set_fontsize(9)
inset.title.set_fontsize(9)
inset.grid(alpha=0.12)
fig.savefig(Path("2021-boundary-layer.png"), dpi=115,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()