codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2008iipaper-4-null-rays.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2008/ii/paper-4-null-rays.py
"""Ingoing-chart Schwarzschild null rays; Python 3.14, numpy 2.3.5, matplotlib 3.10.7.
Writes paper-4-null-rays.png to caller CWD; preserves MPLCONFIGDIR.
"""
import os
import tempfile
if 'MPLCONFIGDIR' not in os.environ:
os.environ['MPLCONFIGDIR']=tempfile.mkdtemp(prefix='paper-4-null-rays-mpl-')
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
fig,ax=plt.subplots(figsize=(6.2,5.6),layout='constrained',facecolor='white')
ax.set_facecolor('white')
r=np.linspace(.02,2.8,800)
for j,v in enumerate([-2,0,2,4,6]):
ax.plot(r,v-r,color='#246ca7',lw=1.2,label='Ingoing: v constant' if j==0 else None)
for j,u in enumerate([-4,-2,0,2,4,6]):
for inside in [True,False]:
x=np.linspace(.015,.995,800) if inside else np.linspace(1.005,2.8,800)
y=u+x+2*np.log(np.abs(x-1))
ax.plot(x,y,color='#b75b32',lw=1.2,label='Outgoing null family' if j==0 and inside else None)
ax.axvline(1,color='#333333',ls='--',lw=1.8,label='Horizon: r = 2M')
ax.axvline(0,color='black',lw=3)
ax.text(.04,5.5,'Singularity',rotation=90,va='top',fontsize=9)
# Future arrows: all ingoing rays move left; outgoing rays move left inside and right outside.
for x,u in [(.6,4),(1.65,0)]:
dx=-.065 if x<1 else .065
y=lambda z:u+z+2*np.log(abs(z-1))
ax.annotate('',xy=(x+dx,y(x+dx)),xytext=(x,y(x)),arrowprops={'arrowstyle':'->','color':'#b75b32','lw':1.8})
ax.annotate('',xy=(1.65,.35),xytext=(1.8,.2),arrowprops={'arrowstyle':'->','color':'#246ca7','lw':1.8})
ax.set_xlim(0,2.8);ax.set_ylim(-6,6)
ax.set_xlabel(r'$r/(2M)$');ax.set_ylabel(r'$\hat t/(2M)$')
ax.set_title('Future light rays in a regular ingoing chart')
ax.legend(loc='lower right',fontsize=8);ax.grid(alpha=.15)
fig.savefig('paper-4-null-rays.png',dpi=150,facecolor='white',transparent=False)
plt.close(fig)