#!/usr/bin/env python
# coding: utf-8
# # Anti-de Sitter spacetime
#
# This worksheet demonstrates a few capabilities of SageMath in computations regarding the 4-dimensional anti-de Sitter spacetime. The corresponding tools have been developed within the [SageManifolds](http://sagemanifolds.obspm.fr) project (version 1.2, as included in SageMath 8.2).
#
# Click [here](https://raw.githubusercontent.com/sagemanifolds/SageManifolds/master/Worksheets/v1.2/SM_AdS.ipynb) to download the worksheet file (ipynb format). To run it, you must start SageMath within the Jupyter notebook, via the command `sage -n jupyter`
# *NB:* a version of SageMath at least equal to 8.2 is required to run this worksheet:
# In[1]:
version()
# First we set up the notebook to display mathematical objects using LaTeX rendering:
# In[2]:
get_ipython().run_line_magic('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)
# ## Spacetime manifold
#
# We declare the anti-de Sitter spacetime as a 4-dimensional Lorentzian manifold:
# In[4]:
M = Manifold(4, 'M', r'\mathcal{M}', structure='Lorentzian')
print(M); M
#
We consider hyperbolic coordinates $(\tau,\rho,\theta,\phi)$ on $\mathcal{M}$. Allowing for the standard coordinate singularities at $\rho=0$, $\theta=0$ or $\theta=\pi$, these coordinates cover the entire spacetime manifold (which is topologically $\mathbb{R}^4$). If we restrict ourselves to regular coordinates (i.e. to considering only mathematically well defined charts), the hyperbolic coordinates cover only an open part of $\mathcal{M}$, which we call $\mathcal{M}_0$, on which $\rho$ spans the open interval $(0,+\infty)$, $\theta$ the open interval $(0,\pi)$ and $\phi$ the open interval $(0,2\pi)$. Therefore, we declare:
# In[5]:
M0 = M.open_subset('M_0', r'\mathcal{M}_0' )
X_hyp. = M0.chart(r'ta:\tau rh:(0,+oo):\rho th:(0,pi):\theta ph:(0,2*pi):\phi')
print(X_hyp) ; X_hyp
# In[6]:
X_hyp.coord_range()
# ## $\mathbb{R}^{2,3}$ as an ambient space
# The AdS metric can be defined as that induced by the immersion of $\mathcal{M}$ in $\mathbb{R}^{2,3}$, the latter being nothing but $\mathbb{R}^5$ equipped with a flat pseudo-Riemannian metric of signature $(-,-,+,+,+)$. Let us construct $\mathbb{R}^{2,3}$ as a 5-dimensional manifold covered by canonical coordinates:
# In[7]:
R23 = Manifold(5, 'R23', r'\mathbb{R}^{2,3}', structure='pseudo-Riemannian', signature=1,
metric_name='h')
X23. = R23.chart()
print(X23); X23
# We define the pseudo-Riemannian metric of $\mathbb{R}^{2,3}$:
# In[8]:
h = R23.metric()
h[0,0], h[1,1], h[2,2], h[3,3], h[4,4] = -1, -1, 1, 1, 1
h.display()
# The AdS immersion into $\mathbb{R}^{2,3}$ is defined as a differential map $\Phi$ from $\mathcal{M}$ to $\mathbb{R}^{2,3}$, by providing its expression in terms of $\mathcal{M}$'s default chart (which is X_hyp = $(\mathcal{M}_0,(\tau,\rho,\theta,\phi))$ ) and $\mathbb{R}^{2,3}$'s default chart (which is X23 = $(\mathbb{R}^{2,3},(U,V,X,Y,Z))$ ):
# In[9]:
var('l', latex_name=r'\ell', domain='real')
assume(l>0)
Phi = M.diff_map(R23, [l*cosh(rh)*cos(ta/l),
l*cosh(rh)*sin(ta/l),
l*sinh(rh)*sin(th)*cos(ph),
l*sinh(rh)*sin(th)*sin(ph),
l*sinh(rh)*cos(th)],
name='Phi', latex_name=r'\Phi')
print(Phi); Phi.display()
# The constant $\ell$ is the AdS length parameter. Considering AdS metric as a solution of vacuum Einstein equation with negative cosmological constant $\Lambda$, one has $\ell = \sqrt{-3/\Lambda}$.
#
# Let us evaluate the image of a point via the map $\Phi$:
# In[10]:
p = M((ta, rh, th, ph), name='p'); print(p)
# The coordinates of $p$ in the chart `X_hyp`:
# In[11]:
X_hyp(p)
# In[12]:
q = Phi(p); print(q)
# In[13]:
X23(q)
# The image of $\mathcal{M}$ by the immersion $\Phi$ is a hyperboloid of one sheet, of equation $$-U^2-V^2+X^2+Y^2+Z^2=-\ell^2.$$
# Indeed:
# In[14]:
(Uq,Vq,Xq,Yq,Zq) = X23(q)
s = - Uq^2 - Vq^2 + Xq^2 + Yq^2 + Zq^2
s.simplify_full()
# We may use the immersion $\Phi$ to draw the coordinate grid $(\tau,\rho)$ in terms of the coordinates $(U,V,X)$ for $\theta=\pi/2$ and $\phi=0$ ($X\geq 0$ part) or $\phi=\pi$
# ($X\leq 0$ part). The red (rep. grey) curves are those for which $\rho={\rm const}$
# (resp. $\tau={\rm const}$):
# In[15]:
graph_hyp = X_hyp.plot(X23, mapping=Phi, ambient_coords=(V,X,U), fixed_coords={th:pi/2, ph:0},
ranges={ta:(0,2*pi), rh:(0,2)}, number_values=9,
color={ta:'red', rh:'grey'}, thickness=2, parameters={l:1},
label_axes=False) # phi = 0 => X > 0 part
graph_hyp += X_hyp.plot(X23, mapping=Phi, ambient_coords=(V,X,U), fixed_coords={th:pi/2, ph:pi},
ranges={ta:(0,2*pi), rh:(0,2)}, number_values=9,
color={ta:'red', rh:'grey'}, thickness=2, parameters={l:1},
label_axes=False) # phi = pi => X < 0 part
show(graph_hyp, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# To have a nicer picture, we add the plot of the hyperboloid obtained by `parametric_plot` with $(\tau,\rho)$ as parameters and the expressions of $(U,V,X)$ in terms of $(\tau,\rho)$ deduced from the coordinate representation of $\Phi$:
# In[16]:
Phi.coord_functions() # the default pair of charts (X_hyp, X23) is assumed
# In[17]:
Ug = Phi.coord_functions()[0](ta,rh,pi/2,0).subs({l:1}) # l=1 substituted to have numerical values
Vg = Phi.coord_functions()[1](ta,rh,pi/2,0).subs({l:1})
Xg = Phi.coord_functions()[2](ta,rh,pi/2,0).subs({l:1})
Ug, Vg, Xg
# In[18]:
hyperboloid = parametric_plot3d([Vg, Xg, Ug], (ta,0,2*pi), (rh,-2,2), color=(1.,1.,0.9))
graph_hyp += hyperboloid
show(graph_hyp, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# ## Spacetime metric
# As mentionned above, the AdS metric $g$ on $\mathcal{M}$ is that induced by the flat metric $h$ on $\mathbb{R}^{2,3}$, i.e.$g$ is the pullback of $h$ by the differentiable map $\Phi$:
# In[19]:
g = M.metric()
g.set( Phi.pullback(h) )
# The expression of $g$ in terms of $\mathcal{M}$'s default frame is found to be
# In[20]:
g.display()
# In[21]:
g[:]
# Curvature
# The Riemann tensor of $g$ is
# In[22]:
Riem = g.riemann()
print(Riem)
# In[23]:
Riem.display_comp(only_nonredundant=True)
# The Ricci tensor:
# In[24]:
Ric = g.ricci()
print(Ric)
Ric.display()
# In[25]:
Ric[:]
# The Ricci scalar:
# In[26]:
R = g.ricci_scalar()
print(R)
R.display()
# We recover the fact that AdS spacetime has a constant curvature. It is indeed a **maximally symmetric space**. In particular, the Riemann tensor is expressible as
# $$ R^i_{\ \, jlk} = \frac{R}{n(n-1)} \left( \delta^i_{\ \, k} g_{jl} - \delta^i_{\ \, l} g_{jk} \right), $$
# where $n$ is the dimension of $\mathcal{M}$: $n=4$ in the present case. Let us check this formula here, under the form $R^i_{\ \, jlk} = -\frac{R}{6} g_{j[k} \delta^i_{\ \, l]}$:
# In[27]:
delta = M.tangent_identity_field()
Riem == - (R/6)*(g*delta).antisymmetrize(2,3) # 2,3 = last positions of the type-(1,3) tensor g*delta
# We may also check that AdS metric is a solution of the vacuum **Einstein equation** with (negative) cosmological constant $\Lambda = - 3/\ell^2$:
# In[28]:
Lambda = -3/l^2
Ric - 1/2*R*g + Lambda*g == 0
# ## Radial null geodesics
#
# Null geodesics that are radial with respect to coordinates $(\tau,\rho,\theta,\phi)$ obey
# $$ \tau = \pm 2 \ell \left( \mathrm{atan} \left(\mathrm{e}^\rho\right) - \frac{\pi}{4} \right) + \tau_0,$$
# where $\tau_0$ is a constant (the value of $\tau$ at $\rho=0$). Note that, due to the homogeneity of AdS spacetime, any null geodesic is a "radial" geodesic with respect to some coordinate system $(\tau',\rho',\theta',\phi')$, as in Minkowski spacetime, any null geodesic is a straight line and one can always find a Minkowskian coordinate system $(t',x',y',z')$ with respect to which the null geodesic is radial.
#
# Let us consider two finite families of radial null geodesics having $\theta=\pi/2$ and $\phi=0$ or $\pi$:
# - `null_geod1` has $\phi=\pi$ when $\tau< 0$ and $\phi=0$ when $\tau>0$
# - `null_geod2` has $\phi=0$ when $\tau<0$ and $\phi=\pi$ when $\tau>0$
# In[29]:
lamb = var('lamb', latex_name=r'\lambda')
null_geod1 = [M.curve({X_hyp: [2*sgn(lamb)*l*(atan(exp(abs(lamb))) - pi/4) + 2*pi*(i-4)/8,
abs(lamb), pi/2, pi*unit_step(-lamb)]},
(lamb, -oo, +oo)) for i in range(9)]
null_geod2 = [M.curve({X_hyp: [2*sgn(lamb)*l*(atan(exp(abs(lamb))) - pi/4) + 2*pi*(i-4)/8,
abs(lamb), pi/2, pi*unit_step(lamb)]},
(lamb, -oo, +oo)) for i in range(9)]
null_geods = null_geod1 + null_geod2
# In[30]:
print(null_geods[0])
# In[31]:
null_geods[0].display()
# In[32]:
null_geods[9].display()
# To graphically display these geodesics, we introduce a Cartesian-like coordinate system
# $(\tau,x_\rho,y_\rho,z_\rho)$ linked to $(\tau,\rho,\theta,\phi)$ by the standard formulas:
# In[33]:
X_hyp_graph. = M0.chart(r'ta:\tau x_rho:x_\rho y_rho:y_\rho z_rho:z_\rho')
hyp_to_hyp_graph = X_hyp.transition_map(X_hyp_graph, [ta, rh*sin(th)*cos(ph),
rh*sin(th)*sin(ph), rh*cos(th)])
hyp_to_hyp_graph.display()
# Let us plot the null geodesics in terms of the coordinates $(\tau,x_\rho)$:
# In[34]:
graph_2d = Graphics()
for geod in null_geods:
geod.expr(geod.domain().canonical_chart(), X_hyp_graph)
graph_2d += geod.plot(X_hyp_graph, ambient_coords=(x_rho,ta), prange=(-4,4),
parameters={l:1}, color='green', thickness=1.5)
graph_2d += X_hyp_graph.plot(X_hyp_graph, ambient_coords=(x_rho,ta),
fixed_coords={th:0, ph:pi},
ranges={ta:(-pi,pi), x_rho:(-4,4)},
number_values={ta: 9, x_rho: 9},
color={ta:'red', x_rho:'grey'}, parameters={l:1})
show(graph_2d, aspect_ratio=1, ymin=-pi, ymax=pi)
# We can also get a 3D view of the radial null geodesics via the isometric immersion $\Phi$:
# In[35]:
graph_3d = Graphics()
for geod in null_geods:
graph_3d += geod.plot(X23, mapping=Phi, ambient_coords=(V,X,U), prange=(-2,2),
parameters={l:1}, color='green', thickness=2,
plot_points=20, label_axes=False)
show(graph_3d+graph_hyp, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# We notice that the image by $\Phi$ of the null geodesics are straight lines of $\mathbb{R}^{2,3}$.
# This is not surprising since $\Phi$ is an isometric immersion and the null geodesics of
# $\mathbb{R}^{2,3}$ are straight lines. Note that the two considered families of null geodesics of $\mathrm{AdS}_4$
# rule the hyperboloid (remember that a hyperboloid of one sheet is a ruled surface).
# ## A timelike geodesic
#
# Let us consider a timelike geodesic:
# In[36]:
time_geod = M.curve({X_hyp: [ta, abs(atanh(4*sin(ta/l)/5)), pi/2,
pi*unit_step(frac(ta/(2*pi*l))-1/2)]},
(ta, -oo, +oo))
time_geod.display()
# and draw it in terms of the $(\tau,x_\rho)$ coordinates:
# In[37]:
graph = time_geod.plot(X_hyp_graph, ambient_coords=(x_rho,ta), plot_points=800,
parameters={l:1}, color='purple', thickness=2)
show(graph+graph_2d, aspect_ratio=1, ymin=-pi, ymax=pi)
# Let us superpose the timelike geodesic to the 3D plot obtained via the immersion $\Phi$ of AdS$_4$ in $\mathbb{R}^{2,3}$:
# In[38]:
graph_3d += time_geod.plot(X23, mapping=Phi, ambient_coords=(V,X,U), prange=(0,2*pi),
parameters={l:1}, color='purple', thickness=2,
label_axes=False)
show(graph_3d+graph_hyp, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# We notice that the immersed timelike geodesic looks like an ellipse. It is actually a *circle* of $\mathbb{R}^{2,3}$, as we can see by considering its restriction to $\tau\in(0,\pi)$ (this avoids absolute values and step functions and therefore ease the simplifications):
# In[39]:
time_geod_partial = M.curve({X_hyp: [ta, atanh(4*sin(ta/l)/5), pi/2, 0]},
(ta, 0, pi))
time_geod_partial.display()
# The immersed curve:
# In[40]:
(Phi*time_geod_partial).display()
# The position vector with respect to the origin of $\mathbb{R}^{2,3}$:
# In[41]:
v = R23.vector_field(name='v')
v[:] = (Phi*time_geod_partial).expr()
v.display()
# In[42]:
h(v,v).display()
# Since $v$ has a constant (negative) squared norm, we conclude that the immersed timelike geodesic is a "circle" of $\mathbb{R}^{2,3}$. This circle is nothing but the intersection of the hyperboloid with a 2-plane through the origin. Note also that the straight line representing the immersed null geodesics are also intersections of the hyperboloid with some 2-planes through the origin, but with a different inclination.
# ## "Static" coordinates
# Let us introduce coordinates $(\tau,R,\theta,\phi)$ on the AdS spacetime via the simple coordinate change
# $$R = \ell \sinh(\rho) $$
# Despite the $(\tau,\rho,\theta,\phi)$ coordinates are as adapted to the spacetime staticity as the $(\tau,R,\theta,\phi)$ coordinates, the latter ones are usually called "static" coordinates.
# In[43]:
X_stat. = M0.chart(r'ta:\tau R:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
print(X_stat); X_stat
# In[44]:
X_stat.coord_range()
# In[45]:
hyp_to_stat = X_hyp.transition_map(X_stat, [ta, l*sinh(rh), th, ph])
hyp_to_stat.display()
# In[46]:
hyp_to_stat.set_inverse(ta, asinh(R/l), th, ph, verbose=True)
stat_to_hyp = hyp_to_stat.inverse()
stat_to_hyp.display()
# The expression of the metric tensor in the new coordinates is
# In[47]:
g.display(X_stat.frame(), X_stat)
# Similarly, the expression of the Riemann tensor is
# In[48]:
Riem.display_comp(X_stat.frame(), X_stat, only_nonredundant=True)
# In[49]:
Phi.display(X_stat, X23)
# A view of the various geodesics in terms of the coordinates $(\tau,R)$:
# In[50]:
graph = Graphics()
for geod in null_geods:
geod.expr(geod.domain().canonical_chart(), X_stat)
graph += geod.plot(X_stat, ambient_coords=(R,ta), prange=(-3,3),
parameters={l:1}, color='green', thickness=1.5)
graph += X_stat.plot(X_stat, ambient_coords=(R,ta), fixed_coords={th:0, ph:pi},
ranges={ta:(-pi,pi), R:(0,5)},
number_values={ta: 9, R: 11},
color={ta:'grey', R:'grey'}, parameters={l:1})
time_geod.expr(time_geod.domain().canonical_chart(), X_stat)
graph += time_geod.plot(X_stat, ambient_coords=(R,ta), plot_points=800,
parameters={l:1}, color='purple', thickness=2)
show(graph, aspect_ratio=1, ymin=-pi, ymax=pi, xmin=0, xmax=5)
# ## Conformal coordinates
#
# We introduce coordinates $(\tilde{\tau},\chi,\theta,\phi)$ such that
# $$ \tilde{\tau} = \frac{\tau}{\ell} \qquad\mbox{and}\qquad \chi = \mathrm{atan}\left(\frac{R}{\ell}\right) $$
# In[51]:
X_conf. = M0.chart(r'tat:\tilde{\tau} ch:(0,pi/2):\chi th:(0,pi):\theta ph:(0,2*pi):\phi')
print(X_conf); X_conf
# In[52]:
X_conf.coord_range()
# In[53]:
stat_to_conf = X_stat.transition_map(X_conf, [ta/l, atan(R/l), th, ph])
stat_to_conf.display()
# In[54]:
stat_to_conf.inverse().display()
# In[55]:
hyp_to_conf = stat_to_conf * hyp_to_stat
hyp_to_conf.display()
# In[56]:
conf_to_hyp = hyp_to_stat.inverse() * stat_to_conf.inverse()
conf_to_hyp.display()
# The expression of the metric tensor in the conformal coordinates is
# In[57]:
g.display(X_conf.frame(), X_conf)
# The immersion of $\mathcal{M}$ in $(\mathbb{R}^{2,3},h)$ in terms of the conformal coordinates:
# In[58]:
Phi.display(X_conf, X23)
# In[59]:
Riem.display_comp(X_conf.frame(), X_conf, only_nonredundant=True)
# Let us draw the grid of hyperbolic coordinates in terms of the conformal ones:
# In[60]:
graph = X_hyp.plot(X_conf, ambient_coords=(ch, tat), fixed_coords={th: pi/2, ph: pi},
ranges={ta: (-pi,pi), rh: (0,10)}, number_values={ta: 9, rh: 20},
parameters={l:1}, color={ta: 'red', rh: 'grey'})
show(graph, aspect_ratio=0.25)
# Same thing for the grid of static coordinates in terms of the conformal ones:
# In[61]:
graph = X_stat.plot(X_conf, ambient_coords=(ch, tat), fixed_coords={th: pi/2, ph: pi},
ranges={ta: (-pi,pi), R: (0,40)}, number_values={ta: 9, R: 40},
parameters={l:1}, color={ta: 'red', R: 'grey'})
show(graph, aspect_ratio=0.25)
# Let us add some geodesics:
# In[62]:
for geod in null_geods:
geod.display(geod.domain().canonical_chart(), X_conf)
time_geod.display(time_geod.domain().canonical_chart(), X_conf)
# In[63]:
for geod in null_geods:
graph += geod.plot(X_conf, ambient_coords=(ch,tat),
parameters={l:1}, color='green', thickness=2)
graph += time_geod.plot(X_conf, ambient_coords=(ch,tat), prange=(-pi, pi),
plot_points=200, parameters={l:1}, color='purple', thickness=2)
show(graph, aspect_ratio=0.25, ymin=-pi, ymax=pi)
# We notice that the null geodesics are straight lines in terms of the conformal coordinates
# $(\tau,\chi)$.
# ## Conformal metric
# Let us call $\Omega^{-2}$ the common factor that appear in the expression of the metric in conformal coordinates:
# In[64]:
Omega = M.scalar_field({X_conf: cos(ch)/l}, name='Omega', latex_name=r'\Omega')
Omega.display()
# In[65]:
Omega.display(X_hyp)
# We introduce the metric $\tilde g = \Omega^2 g$:
# In[66]:
gt = M.lorentzian_metric('gt', latex_name=r'\tilde{g}')
gt.set(Omega^2*g)
gt.display(X_conf.frame(), X_conf)
# ## Einstein static universe
# The Einstein static universe is the manifold $\mathbb{R}\times\mathbb{S}^3$ equipped with a Lorentzian metric equivalent to $\tilde{g}$. We consider here the part $E$ of $\mathbb{R}\times\mathbb{S}^3$ covered by hyperspherical coordinates:
# In[67]:
E = Manifold(4, 'E')
print(E)
# In[68]:
XE. = E.chart(r'tat:\tilde{\tau} cht:(0,pi):\chi th:(0,pi):\theta ph:(0,2*pi):\phi')
XE
# In[69]:
XE.coord_range()
# The conformal completion of AdS spacetime is defined by the map:
# In[70]:
Psi = M.diff_map(E, {(X_conf, XE): [tat, ch, th, ph]},
name='Psi', latex_name=r'\Psi')
print(Psi); Psi.display()
# ### Embedding of $E$ in $\mathbb{R}^5$
# For visualization purposes, we introduce the (differentiable, not isometric) embedding $\Phi_E$ of the Einstein cylinder $\mathbb{R}\times\mathbb{S}^3$ in $\mathbb{R}^5$ that follows immediately from the canonical embedding of $\mathbb{S}^3$ in $\mathbb{R}^4$. We introduce $\mathbb{R}^5$ first:
# In[71]:
R5 = Manifold(5, 'R5', latex_name=r'\mathbb{R}^5')
X5. = R5.chart()
X5
# and define $\Phi_E$ as
# In[72]:
PhiE = E.diff_map(R5, {(XE, X5): [tat,
cos(cht),
sin(cht)*sin(th)*cos(ph),
sin(cht)*sin(th)*sin(ph),
sin(cht)*cos(th)]},
name='Phi_E', latex_name=r'\Phi_E')
print(PhiE); PhiE.display()
# In[73]:
graphE = XE.plot(X5, ambient_coords=(W,X,T), mapping=PhiE, fixed_coords={th:pi/2, ph:0},
ranges={tat: (-pi,pi), cht: (0,pi)}, number_values=9, color='silver',
thickness=0.5, label_axes=False) # phi = 0
graphE += XE.plot(X5, ambient_coords=(W,X,T), mapping=PhiE, fixed_coords={th:pi/2, ph:pi},
ranges={tat: (-pi,pi), cht: (0,pi)}, number_values=9, color='silver',
thickness=0.5, label_axes=False) # phi = pi
show(graphE, aspect_ratio=1, viewer=viewer3D, online=True, axes_labels=['W','X','tau'])
# ## View of $\mathrm{AdS}_4$ on the Einstein cylinder
#
# The view is obtained by composing the embeddings
# $\Psi:\, \mathcal{M}\rightarrow E$ and $\Phi_E:\, E\rightarrow \mathbb{R}^5$, i.e. by introducing
# $$\Theta= \Phi_E\circ \Psi :\ \mathcal{M}\rightarrow \mathbb{R}^5$$
# In[74]:
Theta = PhiE * Psi
print(Theta)
Theta.display()
# In[75]:
graph = X_stat.plot(X5, ambient_coords=(W,X,T), mapping=Theta,
fixed_coords={th: pi/2, ph: 0}, ranges={ta: (-pi,pi), R: (0,40)},
number_values={ta: 9, R: 40}, parameters={l:1},
color={ta: 'red', R: 'grey'}, label_axes=False) # phi = 0
graph += X_stat.plot(X5, ambient_coords=(W,X,T), mapping=Theta,
fixed_coords={th: pi/2, ph: pi}, ranges={ta: (-pi,pi), R: (0,40)},
number_values={ta: 9, R: 40}, parameters={l:1},
color={ta: 'red', R: 'grey'}, label_axes=False) # phi = pi
graph += graphE # superposing the plot of the Einstein cylinder
half_cylinder = parametric_plot3d([sin(ph), cos(ph), ta], (ta, -pi, pi), (ph, 0, pi),
color=(1.,1.,0.9))
graph += half_cylinder
show(graph, aspect_ratio=1, viewer=viewer3D, online=True, axes_labels=['W','X','tau'])
# In[76]:
for geod in null_geods:
graph += geod.plot(X5, ambient_coords=(W,X,T), mapping=Theta,
parameters={l:1}, color='green', thickness=1, label_axes=False)
graph += time_geod.plot(X5, ambient_coords=(W,X,T), mapping=Theta, prange=(-pi, pi),
plot_points=100, parameters={l:1}, color='purple', thickness=2,
label_axes=False)
show(graph, aspect_ratio=1, viewer=viewer3D, online=True, zmin=-pi, zmax=pi,
axes_labels=['W','X','tau'])
# In[77]:
graph1 = graph.rotate((0,0,1), 0.4)
show(graph1, aspect_ratio=1, viewer='tachyon', frame=False,
figsize=20)
# A different cylindrical view of AdS spacetime is obtained by using the coordinates $(T,X,Y)$ of $\mathbb{R}^5$ instead of $(T,W,X)$ as above. Let us draw the grid of conformal
# coordinates at $\theta=\pi/2$, with
# - red lines as those along which $\tilde{\tau}$ varies at fixed $(\chi,\phi)$
# - grey lines as those along which $\chi$ varies at fixed $(\tilde{\tau},\phi)$
# - orange lines as those along which $\phi$ varies at fixed $(\tilde{\tau},\chi)$
# In[78]:
graph = X_conf.plot(X5, ambient_coords=(X,Y,T), mapping=Theta,
fixed_coords={th: pi/2},
ranges={tat: (-pi,pi), ch: (0,pi/2), ph:(0,2*pi)},
number_values=6, parameters={l:1},
color={tat: 'red', ch: 'grey', ph: 'orange'},
label_axes=False)
graph += graphE
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['X','Y','tau'])
# Let us add the previously considered null (green) and timelike (purple) geodesics, noticing that they all lie in the plane $Y=0$ for they have $\phi=0$ or $\pi$:
# In[79]:
for geod in null_geods:
graph += geod.plot(X5, ambient_coords=(X,Y,T), mapping=Theta,
parameters={l:1}, color='green', thickness=1, label_axes=False)
graph += time_geod.plot(X5, ambient_coords=(X,Y,T), mapping=Theta, prange=(-pi, pi),
plot_points=100, parameters={l:1}, color='purple', thickness=2,
label_axes=False)
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['X','Y','tau'])
# ## Poincaré coordinates
# The Poincaré coordinates are defined on the open subset $\mathcal{M}_{\rm P}$ of $\mathcal{M}_0$ defined by $U-X>0$ in terms of the canonical immersion $\Phi$ in $\mathbb{R}^{2,3}$. The open subset $\mathcal{M}_{\rm P}$ is usually called the **Poincaré patch** of AdS spacetime and its boundary $U-X=0$ is called the **Poincaré horizon**.
#
# Given the expression of $\Phi$:
# In[80]:
Phi.display()
# we see that $U-X>0$ is equivalent to each of the following conditions:
#
# - in hyperboloidal coordinates:
# In[81]:
Phi.expr(X_hyp, X23)[0] - Phi.expr(X_hyp, X23)[2] > 0
# - in static coordinates:
# In[82]:
Phi.expr(X_stat, X23)[0] - Phi.expr(X_stat, X23)[2] > 0
# - in conformal coordinates:
# In[83]:
Phi.expr(X_conf, X23)[0] - Phi.expr(X_conf, X23)[2] > 0
# Since $\chi\in(0,\pi/2)$, we have actually $|\cos(\chi)| = \cos(\chi)>0$ (the lack of simplification of $|\cos(\chi)|$ for such a case will be corrected in a future version of SageMath); hence we declare:
# In[84]:
MP = M0.open_subset('MP', latex_name=r'\mathcal{M}_{\rm P}',
coord_def={X_hyp: cos(ta/l) - tanh(rh)*sin(th)*cos(ph)>0,
X_stat: cos(ta/l) - R/sqrt(R^2+l^2)*sin(th)*cos(ph)>0,
X_conf: cos(tat) - sin(ch)*sin(th)*cos(ph)>0})
print(MP)
# In[85]:
print("Coordinate definition of the Poincaré patch in different charts:")
for chart in MP.atlas():
show(chart)
show(chart._restrictions)
# A view of the Poincaré patch on the AdS hyperboloid in $\mathbb{R}^{2,3}$:
# In[86]:
graph = X_hyp.restrict(MP).plot(X23, mapping=Phi, ambient_coords=(V,X,U),
fixed_coords={th: pi/2, ph:0},
ranges={ta:(0,2*pi), rh:(0,2)}, number_values={ta: 24, rh: 11},
color={ta:'red', rh:'grey'}, thickness=2, parameters={l:1},
label_axes=False)
graph += X_hyp.restrict(MP).plot(X23, mapping=Phi, ambient_coords=(V,X,U),
fixed_coords={th: pi/2, ph:pi},
ranges={ta:(0,2*pi), rh:(0,2)}, number_values={ta: 24, rh: 11},
color={ta:'red', rh:'grey'}, thickness=2, parameters={l:1},
label_axes=False)
graph += hyperboloid
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# A view of the Poincaré patch on the Einstein cylinder:
# In[87]:
graph = X_stat.restrict(MP).plot(X5, ambient_coords=(W,X,T), mapping=Theta,
fixed_coords={th: pi/2, ph: 0},
ranges={ta: (-pi,pi), R: (0, 10)}, number_values={ta: 15, R: 20},
parameters={l:1}, color={ta: 'red', R: 'grey'},
label_axes=False) # phi = 0
graph += X_stat.restrict(MP).plot(X5, ambient_coords=(W,X,T), mapping=Theta,
fixed_coords={th: pi/2, ph: pi},
ranges={ta: (-pi,pi), R: (0, 10)}, number_values={ta: 15, R: 20},
parameters={l:1}, color={ta: 'red', R: 'grey'},
label_axes=False) # phi = pi
graph += graphE + half_cylinder
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['W','X','tau'])
# Let us add the Poincaré horizon:
# In[88]:
poincare_hor = parametric_plot3d([cos(ch), sin(ch), acos(-sin(ch))-pi], (ch, 0, pi/2),
color='green', thickness=2) + \
parametric_plot3d([cos(ch), sin(ch), -acos(-sin(ch))+pi], (ch, 0, pi/2),
color='green', thickness=2) + \
parametric_plot3d([cos(ch), -sin(ch), acos(sin(ch))-pi], (ch, 0, pi/2),
color='green', thickness=2) + \
parametric_plot3d([cos(ch), -sin(ch), -acos(sin(ch))+pi], (ch, 0, pi/2),
color='green', thickness=2)
graph += poincare_hor
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['W','X','tau'])
# The Poincaré patch in the alternative cylindrical view of AdS spacetime based on the
# $(T,X,Y)$ coordinates of $\mathbb{R}^5$:
# In[89]:
graph = X_conf.restrict(MP).plot(X5, ambient_coords=(X,Y,T), mapping=Theta,
fixed_coords={th: 0.9*pi/2},
ranges={tat: (-pi,pi), ch: (0,pi/2), ph:(0,2*pi)},
number_values=6, parameters={l:1},
color={tat: 'red', ch: 'grey', ph: 'orange'},
label_axes=False)
show(graph+graphE, aspect_ratio=(1,1,0.5), viewer=viewer3D, online=True,
axes_labels=['X','Y','tau'])
# We define the Poincaré coordinates $(t,x,y,u)$ on $\mathcal{M}_{\rm P}$ as
# In[90]:
X_Poinc. = MP.chart('t x y u:(0,+oo)')
X_Poinc
# In[91]:
X_Poinc.coord_range()
# The link between the conformal coordinates and the Poincaré ones is
# In[92]:
conf_to_Poinc = X_conf.restrict(MP).transition_map(X_Poinc,
[l*sin(tat)/(cos(tat) - sin(ch)*sin(th)*cos(ph)),
l*sin(ch)*sin(th)*sin(ph)/(cos(tat) - sin(ch)*sin(th)*cos(ph)),
l*sin(ch)*cos(th)/(cos(tat) - sin(ch)*sin(th)*cos(ph)),
l*(cos(tat) - sin(ch)*sin(th)*cos(ph))/cos(ch)])
conf_to_Poinc.display()
# In[93]:
conf_to_Poinc.set_inverse(atan2(2*l*t, x^2+y^2-t^2+l^2*(1+l^2/u^2)),
acos(2*l^3/u/sqrt((x^2+y^2-t^2+l^2*(1+l^2/u^2))^2 + 4*l^2*t^2)),
acos(2*l*y/sqrt((x^2+y^2-t^2+l^2*(1+l^2/u^2))^2
+ 4*l^2*(t^2-l^4/u^2))),
atan2(2*l*x, x^2+y^2-t^2-l^2*(1-l^2/u^2)),
verbose=True)
# The test is passed, modulo some lack of simplification in the `arctan2` and `arccos` functions.
# In[94]:
conf_to_Poinc.inverse().display()
# The isometric immersion $\Phi$ expressed in terms of Poincaré coordinates:
# In[95]:
Phi.restrict(MP).display(X_Poinc, X23)
# We see that the coordinate $u$ is simply $U-X$:
# In[96]:
U1 = Phi.restrict(MP).expr(X_Poinc, X23)[0]
X1 = Phi.restrict(MP).expr(X_Poinc, X23)[2]
(U1 - X1).simplify_full()
# so that the Poincaré horizon corresponds to $u\rightarrow 0$.
# ### Metric in Poincaré coordinates
#
# Let us ask Sage to compute the metric components in terms of the Poincaré coordinates:
# In[97]:
g.display(X_Poinc.frame(), X_Poinc)
# We notice that the metric restricted to the hypersurfaces $u=\mathrm{const}$ (i.e. the intersection of the hyperboloid with hyperplanes $U-X = \mathrm{const}$) is nothing but the Minkowski metric (up to some constant factor $u^2/\ell^2$):
# $$ \left. g \right| _{u=\mathrm{const}}= \frac{u^2}{\ell^2} \left(
# -\mathrm{d}t\otimes\mathrm{d}t +
# \mathrm{d}x\otimes\mathrm{d}x + \mathrm{d}y\otimes\mathrm{d}y \right).$$
# $(t,x,y)$ appear then as Minkowskian coordinates of these hypersurfaces. We may say that $\mathcal{M}_{\rm P}$ is sliced by a family, parametrized by $u$, of flat 3-dimensional spacetimes.
# In[98]:
Poinc_to_stat = stat_to_conf.inverse().restrict(MP) * conf_to_Poinc.inverse()
Poinc_to_stat.display()
# Plot of the Poincaré coordinates $(t,x)$ in terms of the static coordinates $(\tau, R)$ for $y=0$ and $u=1$:
# In[99]:
graph = X_Poinc.plot(X_stat.restrict(MP), ambient_coords=(R, ta), fixed_coords={y:0, u:1},
number_values=9, parameters={l:1}, plot_points=200,
color={t: 'red', x: 'gold', y: 'orange', u: 'cyan'})
show(graph)
# Plot of the Poincaré coordinates $(t,u)$ in terms of $(U,V,X)$ for $(x,y)=(0,0)$:
# In[100]:
graph = X_Poinc.plot(X23, mapping=Phi.restrict(MP), ambient_coords=(V,X,U),
fixed_coords={x:0, y:0},
ranges={t:(-1,1), x:(-1,1), y:(-1,1), u:(0.1, 6)},
number_values=13,
color={t:'red', x:'gold', y:'orange', u: 'cyan'},
thickness=1, parameters={l:1}, label_axes=False)
graph += hyperboloid
show(graph, aspect_ratio=1, viewer=viewer3D, online=True,
axes_labels=['V','X','U'])
# Plot of the Poincaré coordinates $(t,x,u)$ in terms of $(T,X,Y)$ for $y=0$:
# - the red lines are those along which $t$ varies at fixed $(x,u)$
# - the gold lines are those along which $x$ varies at fixed $(t,u)$
# - the cyan lines are those along which $u$ varies at fixed $(t,x)$
# In[101]:
graph = X_Poinc.plot(X5, ambient_coords=(X,Y,T), mapping=Theta.restrict(MP),
fixed_coords={y:0},
ranges={t:(-3,3), x:(-3,3), y:(-3,3), u:(0.01, 6)},
number_values=7,
color={t:'red', x:'gold', y:'orange', u: 'cyan'},
parameters={l:1}, label_axes=False)
graph += graphE
show(graph, aspect_ratio=1, viewer=viewer3D, online=True)
# ### Variant of Poincaré coordinates
#
# Instead of $u$, we may use the coordinate
# $$ z = \frac{\ell^2}{u}$$
# In[102]:
X_Poinc_z. = MP.chart('t x y z:(0,+oo)')
X_Poinc_z
# In[103]:
X_Poinc_z.coord_range()
# In[104]:
Poinc_to_Poinc_z = X_Poinc.transition_map(X_Poinc_z, [t, x, y, l^2/u])
Poinc_to_Poinc_z.display()
# In[105]:
Poinc_to_Poinc_z.inverse().display()
# In terms of the coordinates $(t,x,y,z)$, the AdS metric looks like the metric of the 4-dimensional hyperbolic space in ["half-plane" Poincaré coordinates](http://nbviewer.jupyter.org/github/sagemanifolds/SageManifolds/blob/master/Worksheets/v1.0/SM_hyperbolic_plane.ipynb), except for the change of signature from $(+,+,+,+)$ to $(-,+,+,+)$:
# In[106]:
g.display(X_Poinc_z.frame(), X_Poinc_z)
# This justifies the name *Poincaré coordinates* given to $(t,x,y,u)$.
# The isometric immersion in $\mathbb{R}^{2,3}$ in terms of the Poincaré coordinates $(t,x,y,z)$:
# In[107]:
Phi.restrict(MP).display(X_Poinc_z, X23)
# ### Exponential Poincaré coordinates
#
# Another variant of Poincaré coordinates is by using $r$ instead of $u$, such that
# $$ u = \ell e^{r/\ell}$$
# In[108]:
X_Poinc_exp. = MP.chart()
X_Poinc_exp
# In[109]:
X_Poinc_exp.coord_range()
# In[110]:
Poinc_to_Poinc_exp = X_Poinc.transition_map(X_Poinc_exp, [t, x, y, l*ln(u/l)])
Poinc_to_Poinc_exp.display()
# In[111]:
Poinc_to_Poinc_exp.inverse().display()
# In[112]:
g.display(X_Poinc_exp.frame(), X_Poinc_exp)
# The isometric immersion in $\mathbb{R}^{2,3}$ in terms of the coordinates $(t,x,y,r)$:
# In[113]:
Phi.restrict(MP).display(X_Poinc_exp, X23)
# ## Summary
#
# 10 charts have been defined on the $\mathrm{AdS}_4$ spacetime:
# In[114]:
M.atlas()
# There are actually 7 main charts, the other ones being subcharts:
# In[115]:
M.top_charts()
# Except for $(\tau,x_\rho,y_\rho,z_\rho)$ (which has been introduced only for graphical purposes), the expression of the metric tensor in each of these chart is
# In[116]:
for chart in M.top_charts():
try:
show(g.display(chart.frame(), chart))
except:
pass
# In[ ]: