codex/past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2005/iii/paper-62-extension.py

past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2005/iii/paper-62-extension.py
"""Original Schwarzschild causal diagrams; tested with Python 3.14.4.

Uses declared NumPy/Matplotlib dependencies. Output is the PNG basename in
caller CWD. The caller's MPLCONFIGDIR is preserved.
"""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon


def main():
    fig, axes = plt.subplots(1, 2, figsize=(11.6, 5.3), dpi=120)
    fig.patch.set_facecolor('white')
    black, white, exterior = '#e1eaf5', '#f8eddc', '#eef4ef'
    ax = axes[0]
    x = np.linspace(-2.05, 2.05, 401)
    h = np.sqrt(1+x*x)
    ax.fill_between(x, abs(x), h, color=black)
    ax.fill_between(x, -h, -abs(x), color=white)
    ax.fill_between(x, -abs(x), abs(x), color=exterior)
    ax.plot(x, h, color='#9c332c', lw=2)
    ax.plot(x, -h, color='#9c332c', lw=2)
    ax.plot(x, x, '--', color='#535353', lw=1)
    ax.plot(x, -x, '--', color='#535353', lw=1)
    ax.scatter([0], [0], color='#333333', s=18, zorder=4)
    for X,T,label in [(1.35,0,'I: right exterior'),(-1.35,0,'III: left exterior'),
                       (0,.60,'II\nblack hole'),(0,-.60,'IV\nwhite hole')]:
        ax.text(X,T,label,ha='center',va='center',fontsize=10)
    ax.text(0,1.17,r'$r=0$: future singularity',ha='center',fontsize=9,color='#9c332c')
    ax.text(0,-1.28,r'$r=0$: past singularity',ha='center',fontsize=9,color='#9c332c')
    ax.annotate('',xy=(.5,.80),xytext=(1.05,.25),arrowprops={'arrowstyle':'->','color':'#236192','lw':1.5})
    ax.text(1.02,.62,'ingoing light',fontsize=8,color='#236192')
    ax.set(xlim=(-2.15,2.15),ylim=(-2.45,2.45),xlabel=r'$X_K$',ylabel=r'$T_K$')
    ax.set_title('Kruskal coordinates: horizons are regular',fontsize=12)
    ax.set_aspect('equal')
    ax.tick_params(labelsize=8)
    ax=axes[1]
    polygons=[([(0,0),(1,1),(2,0),(1,-1)],exterior),
              ([(0,0),(-1,1),(-2,0),(-1,-1)],exterior),
              ([(0,0),(-1,1),(1,1)],black),
              ([(0,0),(-1,-1),(1,-1)],white)]
    for points,color in polygons:ax.add_patch(Polygon(points,facecolor=color,edgecolor='none'))
    for side in [-1,1]:
        for time in [-1,1]:
            ax.plot([0,side],[0,time],'--',color='#535353',lw=1)
            ax.plot([side,2*side],[time,0],color='#236192',lw=1.5)
            label=r'$\mathcal{I}^+$' if time>0 else r'$\mathcal{I}^-$'
            ax.text(1.62*side,.65*time,label,ha='center',va='center',fontsize=12,color='#236192')
    sx=np.linspace(-1,1,101)
    for sign in [-1,1]:
        zig=sign*(1+.025*np.where(np.arange(len(sx))%2==0,1,-1))
        ax.plot(sx,zig,color='#9c332c',lw=1.7)
    for X,T,label in [(1.1,0,'I: right exterior'),(-1.1,0,'III: left exterior'),
                       (0,.58,'II: black hole'),(0,-.58,'IV: white hole')]:
        ax.text(X,T,label,ha='center',va='center',fontsize=10)
    ax.text(0,1.17,'spacelike future singularity',ha='center',color='#9c332c',fontsize=9)
    ax.text(0,-1.21,'spacelike past singularity',ha='center',color='#9c332c',fontsize=9)
    ax.text(2.08,0,r'$i^0$',ha='left',va='center',fontsize=11)
    ax.text(-2.08,0,r'$i^0$',ha='right',va='center',fontsize=11)
    ax.scatter([0],[0],color='#333333',s=18,zorder=4)
    ax.annotate('future',xy=(2.12,.98),xytext=(2.12,.48),ha='center',fontsize=9,
                arrowprops={'arrowstyle':'->','color':'#333333'})
    ax.set(xlim=(-2.4,2.4),ylim=(-1.4,1.4))
    ax.set_aspect('equal')
    ax.axis('off')
    ax.set_title('Penrose diagram: null infinities compactified',fontsize=12,pad=22)
    fig.suptitle('The maximal Schwarzschild extension',fontsize=15,y=.98)
    fig.text(.5,.025,'Dashed lines: horizons. Each diagram point represents a symmetry two-sphere.',
             ha='center',fontsize=9)
    fig.tight_layout(rect=(0,.055,1,.93),w_pad=1.8)
    output=Path(Path(__file__).with_suffix('.png').name)
    fig.savefig(output,facecolor='white',transparent=False)
    plt.close(fig)
    print(output)


if __name__=='__main__':main()