Conformal completion of Minkowski spacetime

This Jupyter/SageMath worksheet is relative to the lectures Geometry and physics of black holes

These computations are based on SageManifolds (version 1.0, as included in SageMath 7.5 and higher versions)

The worksheet file (ipynb format) can be downloaded from here.

NB: a version of SageMath at least equal to 7.5 is required to run this worksheet:

In [1]:
version()
Out[1]:
'SageMath version 8.0.beta6, Release Date: 2017-05-12'

First we set up the notebook to display mathematical objects using LaTeX formatting:

In [2]:
%display latex

We also define a viewer for 3D plots (use 'threejs' or 'jmol' for interactive 3D graphics):

In [3]:
viewer3D = 'threejs' # must be 'threejs', jmol', 'tachyon' or None (default)

Spherical coordinates on Minkowski spacetime

We declare the spacetime manifold $M$:

In [4]:
M = Manifold(4, 'M')
print M
4-dimensional differentiable manifold M

and the spherical coordinates $(t,r,\theta,\phi)$ as a chart on $M$:

In [5]:
XS.<t,r,th,ph> = M.chart(r't r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
XS
Out[5]:
In [6]:
XS.coord_range()
Out[6]:

In term of these coordinates, the Minkowski metric is

In [7]:
g = M.lorentzian_metric('g')
g[0,0] = -1
g[1,1] = 1
g[2,2] = r^2
g[3,3] = r^2*sin(th)^2
g.display()
Out[7]:

Null coordinates

Let us introduce the null coordinates $u=t-r$ (retarded time) and $v=t+r$ (advanced time):

In [8]:
XN.<u,v,th,ph> = M.chart(r'u v th:(0,pi):\theta ph:(0,2*pi):\phi')
XN.add_restrictions(v-u>0)
XN
Out[8]:
In [9]:
XN.coord_range()
Out[9]:
In [10]:
XS_to_XN = XS.transition_map(XN, [t-r, t+r, th, ph])
XS_to_XN.display()
Out[10]:
In [11]:
XS_to_XN.inverse().display()
Out[11]:

In terms of the null coordinates $(u,v,\theta,\phi)$, the Minkowski metric writes

In [12]:
g.display(XN.frame(), XN)
Out[12]:

Let us plot the coordinate grid $(u,v)$ in terms of the coordinates $(t,r)$:

In [13]:
graph = XN.plot(XS, ambient_coords=(r,t), fixed_coords={th: pi/2, ph: pi}, 
                number_values=17, plot_points=200, color='green', 
                style={u: '-', v: ':'}, thickness={u: 1, v: 2})
show(graph)
In [14]:
show(graph, xmin=0, xmax=4, ymin=0, ymax=4, aspect_ratio=1, fontsize=16)
In [15]:
graph.save("glo_null_coord.pdf", xmin=0, xmax=4, ymin=0, ymax=4, aspect_ratio=1, fontsize=16)

Compactified null coordinates

Instead of $(u,v)$, which span $\mathbb{R}$, let consider the coordinates $U = \mathrm{atan}\, u$ and $V = \mathrm{atan}\, v$, which span $\left(-\frac{\pi}{2}, \frac{\pi}{2}\right)$:

In [16]:
graph = plot(atan(u), (u,-6, 6), thickness=2, axes_labels=[r'$u$', r'$U$']) + \
        line([(-6,-pi/2), (6,-pi/2)], linestyle='--') + \
        line([(-6,pi/2), (6,pi/2)], linestyle='--')
show(graph, aspect_ratio=1)
In [17]:
graph.save('glo_atan.pdf', aspect_ratio=1)
In [18]:
XNC.<U,V,th,ph> = M.chart(r'U:(-pi/2,pi/2) V:(-pi/2,pi/2) th:(0,pi):\theta ph:(0,2*pi):\phi')
XNC.add_restrictions(V-U>0)
XNC
Out[18]:
In [19]:
XNC.coord_range()
Out[19]:
In [20]:
XN_to_XNC = XN.transition_map(XNC, [atan(u), atan(v), th, ph])
XN_to_XNC.display()
Out[20]:
In [21]:
XN_to_XNC.inverse().display()
Out[21]:

Expressed in terms of the coordinates $(U,V,\theta,\phi)$, the metric tensor is

In [22]:
g.display(XNC.frame(), XNC)
Out[22]:

Let us call $\Omega^{-2}$ the common factor:

In [23]:
Omega = M.scalar_field({XNC: 2*cos(U)*cos(V)}, name='Omega', latex_name=r'\Omega')
Omega.display()
Out[23]:
In [24]:
Omega.display(XS)
Out[24]:

Conformal metric

We introduce the metric $\tilde g = \Omega^2 g$:

In [25]:
gt = M.lorentzian_metric('gt', latex_name=r'\tilde{g}')
gt.set(Omega^2*g)
gt.display(XNC.frame(), XNC)
Out[25]:

Clearly the metric components ${\tilde g}_{\theta\theta}$ and ${\tilde g}_{\phi\phi}$ can be simplified further. Let us do it by hand, by extracting the symbolic expression via expr():

In [26]:
g22 = gt[XNC.frame(), 2, 2, XNC].expr()
g22
Out[26]:
In [27]:
g22.factor().reduce_trig()
Out[27]:
In [28]:
g33st = gt[XNC.frame(), 3, 3, XNC].expr() / sin(th)^2
g33st
Out[28]:
In [29]:
g33st.factor().reduce_trig()
Out[29]:
In [30]:
gt.add_comp(XNC.frame())[2,2, XNC] = g22.factor().reduce_trig()
gt.add_comp(XNC.frame())[3,3, XNC] = g33st.factor().reduce_trig() * sin(th)^2

Hence the final form of the conformal metric in terms of the compactified null coordinates:

In [31]:
gt.display(XNC.frame(), XNC)
Out[31]:

In terms of the non-compactified null coordinates $(u,v,\theta,\phi)$:

In [32]:
gt.display(XN.frame(), XN)
Out[32]:

and in terms of the default coordinates $(t,r,\theta,\phi)$:

In [33]:
gt.display()
Out[33]:

Einstein cylinder coordinates

Let us introduce some coordinates $(\tau,\chi)$ such that the null coordinates $(U,V)$ are respectively half the retarded time $\tau -\chi$ and half the advanced time $\tau+\chi$:

In [34]:
XC.<tau,ch,th,ph> = M.chart(r'tau:(-pi,pi):\tau ch:(0,pi):\chi th:(0,pi):\theta ph:(0,2*pi):\phi')
XC.add_restrictions([tau<pi-ch, tau>ch-pi])
XC
Out[34]:
In [35]:
XC.coord_range()
Out[35]:
In [36]:
XC_to_XNC = XC.transition_map(XNC, [(tau-ch)/2, (tau+ch)/2, th, ph])
XC_to_XNC.display()
Out[36]:
In [37]:
XC_to_XNC.inverse().display()
Out[37]:

The conformal metric takes then the form of the standard metric on the Einstein cylinder $\mathbb{R}\times\mathbb{S}^3$:

In [38]:
gt.display(XC.frame(), XC)
Out[38]:

The square of the conformal factor expressed in all the coordinates introduced so far:

In [39]:
(Omega^2).display()
Out[39]:
In [40]:
XS_to_XC = M.coord_change(XNC,XC) * M.coord_change(XN, XNC) * M.coord_change(XS, XN)
XS_to_XC.display()
Out[40]:
In [41]:
XC_to_XS = M.coord_change(XN, XS) * M.coord_change(XNC, XN) * M.coord_change(XC,XNC)
XC_to_XS.display()
Out[41]:

The expressions for $t$ and $r$ can be simplified:

In [42]:
tc = XC_to_XS(tau,ch,th,ph)[0]
tc
Out[42]:
In [43]:
tc.reduce_trig()
Out[43]:
In [44]:
rc = XC_to_XS(tau,ch,th,ph)[1]
rc
Out[44]:
In [45]:
rc.reduce_trig()
Out[45]:
In [46]:
XS_to_XC.set_inverse(tc.reduce_trig(), rc.reduce_trig(), th, ph)
XC_to_XS = XS_to_XC.inverse()
In [47]:
XC_to_XS.display()
Out[47]:

Conformal Penrose diagram

Let us draw the coordinate grid $(t,r)$ in terms of the coordinates $(\tau,\chi)$:

In [48]:
graphXS = XS.plot(XC, ambient_coords=(ch, tau), fixed_coords={th: pi/2, ph: pi}, 
                  max_range=30, number_values=51, plot_points=250, color={t: 'red', r: 'grey'})
graph_i0 = circle((pi,0), 0.05, fill=True, color='grey') + \
           text(r"$i^0$", (3.3, 0.2), fontsize=18, color='grey') 
graph_ip = circle((0,pi), 0.05, fill=True, color='red') + \
           text(r"$i^+$", (0.25, 3.3), fontsize=18, color='red')
graph_im = circle((0,-pi), 0.05, fill=True, color='red') + \
           text(r"$i^-$", (0.25, -3.3), fontsize=18, color='red')
graph_Ip = line([(0,pi), (pi,0)], color='green', thickness=2) + \
           text(r"$\mathscr{I}^+$", (1.8, 1.8), fontsize=18, color='green')
graph_Im = line([(0,-pi), (pi,0)], color='green', thickness=2) + \
           text(r"$\mathscr{I}^-$", (1.8, -1.8), fontsize=18, color='green')
graph = graphXS + graph_i0 + graph_ip + graph_im + graph_Ip + graph_Im
show(graph)
In [49]:
graph.save('glo_conf_diag_Mink.pdf')

Some blow-up near $i^0$:

In [50]:
graph = XS.plot(XC, ambient_coords=(ch, tau), fixed_coords={th: pi/2, ph: pi}, 
                max_range=100, number_values=41, plot_points=200, color={t: 'red', r: 'grey'})
graph += circle((pi,0), 0.005, fill=True, color='grey') + \
         text(r"$i^0$", (pi, 0.02), fontsize=18, color='grey') 
show(graph, xmin=3., xmax=3.2, ymin=-0.2, ymax=0.2, aspect_ratio=1)

To produce a more satisfactory figure, let us use some logarithmic radial coordinate:

In [51]:
XL.<t, rh, th, ph> = M.chart(r't rh:\rho th:(0,pi):\theta ph:(0,2*pi):\phi')
XL
Out[51]:
In [52]:
XS_to_XL = XS.transition_map(XL, [t, ln(r), th, ph])
XS_to_XL.display()
Out[52]:
In [53]:
XS_to_XL.inverse().display()
Out[53]:
In [54]:
XL_to_XC = M.coord_change(XS, XC) * M.coord_change(XL, XS)
XC_to_XL = M.coord_change(XS, XL) * M.coord_change(XC, XS)
In [55]:
graph = XL.plot(XC, ambient_coords=(ch, tau), fixed_coords={th: pi/2, ph: pi}, 
                ranges={t: (-20, 20), rh: (-2, 10)}, number_values=19, 
                color={t: 'red', rh: 'grey'})
graph += circle((pi,0), 0.005, fill=True, color='grey') + \
         text(r"$i^0$", (pi, 0.02), fontsize=18, color='grey') 
show(graph, xmin=3., xmax=3.2, ymin=-0.2, ymax=0.2, aspect_ratio=1)

Null radial geodesics in the conformal diagram

To get a view of the null radial geodesics in the conformal diagram, it suffices to plot the chart $(u,v,\theta,\phi)$ in terms of the chart $(\tau,\chi,\theta,\phi)$. The following plot shows

  • the null geodesics defined by $(u,\theta,\phi) = (u_0, \pi/2,\pi)$ for 17 values of $u_0$ evenly spaced in $[-8,8]$ (dashed lines)
  • the null geodesics defined by $(v,\theta,\phi) = (v_0, \pi/2,\pi)$ for 17 values of $v_0$ evenly spaced in $[-8,8]$ (solid lines)
In [56]:
graphXN = XN.plot(XC, ambient_coords=(ch, tau), fixed_coords={th: pi/2, ph: pi}, 
                  number_values=17, plot_points=150, color='green', 
                  style={u: '-', v: ':'}, thickness={u: 1, v: 2})
graph = graphXN + graph_i0 + graph_ip + graph_im + graph_Ip + graph_Im
show(graph)
In [57]:
graph.save('glo_conf_Mink_null.pdf')

Conformal factor

The conformal factor expressed in various coordinate systems:

In [58]:
Omega.display()
Out[58]:

The expression in terms of $(\tau,\chi,\theta,\phi)$ can be simplified:

In [59]:
Omega.expr(XC)
Out[59]:
In [60]:
s = Omega.expr(XC) - cos(tau) - cos(ch)
s.trig_reduce()
Out[60]:

Hence we set

In [61]:
Omega.add_expr(cos(tau) + cos(ch), XC)
Omega.display()
Out[61]:

A plot of $\Omega$ in terms of the coordinates $(\tau,\chi)$:

In [62]:
graph = plot3d(Omega.expr(XC), (tau,-pi,pi), (ch,0,pi), adaptive=True) + \
        plot3d(0, (tau,-pi,pi), (ch,0,pi), color='yellow', opacity=0.7)
show(graph, aspect_ratio=1, viewer=viewer3D, oneline=True,
     axes_labels=['tau', 'chi', ''])