codex/past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2002/iii/paper-52-triangular-dam-break.py

past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2002/iii/paper-52-triangular-dam-break.py
"""Original triangular-channel characteristic plot. Python 3.14; root pinned deps.
Emit the basename PNG to the caller's CWD; caller controls MPLCONFIGDIR.
"""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

def main():
    fig, ax = plt.subplots(figsize=(7.4, 4.5), constrained_layout=True)
    t = np.linspace(0, 1.6, 500)
    ax.fill_betweenx(t, -t, 4*t, color='#e8f1fb', label='Rarefaction fan')
    for speed in np.linspace(-1, 4, 12):
        ax.plot(speed*t, t, color='#83acd4', lw=.7)
    for entry in [.06, .15, .32, .55, .85]:
        tt = np.linspace(entry, 1.6, 350)
        xx = 4*tt-5*entry**.4*tt**.6
        ax.plot(xx, tt, color='#d9762b', lw=1.2)
        tr = np.linspace(0, entry, 70)
        ax.plot(tr-2*entry, tr, color='#d9762b', lw=1.2)
    ax.plot(-t, t, color='#214e79', lw=2, label=r'Fan back: $x=-c_0t$')
    ax.plot(4*t, t, color='#8b2635', lw=2, label=r'Dry front: $x=4c_0t$')
    ax.plot([], [], color='#d9762b', label=r'Plus family: $u+c$')
    ax.text(-2.04, 1.2, 'Undisturbed\nreservoir', ha='center', fontsize=9)
    ax.text(5.9, .7, 'Dry bed', ha='center', fontsize=10)
    ax.set(xlabel=r'$x/(c_0t_{\rm ref})$', ylabel=r'$t/t_{\rm ref}$', xlim=(-2.7, 7), ylim=(0, 1.65), title='Triangular-channel dry-bed release')
    ax.grid(alpha=.18)
    ax.legend(loc='upper right', fontsize=8)
    fig.savefig(Path.cwd() / 'paper-52-triangular-dam-break.png', dpi=130, facecolor='white', transparent=False)
    plt.close(fig)

if __name__ == '__main__':
    main()