codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2007iiipaper-71-advection-amplification.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2007/iii/paper-71-advection-amplification.py
"""Plot derived Fourier amplification; Python 3.14, NumPy 2.3.5, Matplotlib 3.10.7.
Write the opaque PNG basename to the caller's current directory.
"""
import os
os.environ.setdefault('MPLCONFIGDIR', '/tmp/paper-71-mplconfig')
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
def amplification(mu, angle):
a=mu*(1+mu)/2
b=(1+mu)*(2-mu)
c=(1-mu)*(2-mu)/2
numerator=(2-mu)+(1+mu)*np.exp(1j*angle)
denominator=a*np.exp(-1j*angle)+b+c*np.exp(1j*angle)
return np.abs(numerator/denominator)
def main():
angle=np.linspace(0,np.pi,1001)
fig,ax=plt.subplots(figsize=(7.2,3.8),dpi=140,facecolor='white')
ax.set_facecolor('white')
for mu,color,label in [(0.5,'#1764ab',r'$\mu=0.5$: stable'),(1.5,'#c64824',r'$\mu=1.5$: unstable'),(2.5,'#278447',r'$\mu=2.5$: stable')]:
ax.plot(angle,amplification(mu,angle),color=color,lw=2.2,label=label)
ax.axhline(1,color='#333333',ls='--',lw=1,label='unit amplification')
ax.set_xlim(0,np.pi)
ax.set_ylim(0,4.25)
ax.set_xticks([0,np.pi/4,np.pi/2,3*np.pi/4,np.pi],[r'$0$',r'$\pi/4$',r'$\pi/2$',r'$3\pi/4$',r'$\pi$'])
ax.set_xlabel(r'Fourier angle $\theta$')
ax.set_ylabel(r'Amplification modulus $|G(\theta)|$')
ax.set_title('Implicit advection: disconnected stable Courant ranges')
ax.grid(alpha=.18)
ax.legend(loc='upper left',framealpha=1,fontsize=9)
fig.tight_layout()
fig.savefig('paper-71-advection-amplification.png',facecolor='white',transparent=False)
plt.close(fig)
if __name__=='__main__':
main()