This notebook demonstrates a few capabilities of SageMath in computations regarding cosmological spacetimes with Friedmann-Lemaître-Robertson-Walker (FLRW) metrics. The corresponding tools have been developed in the framework of the SageManifolds project.
NB: a version of SageMath at least equal to 8.2 is required to run this notebook:
version()
'SageMath version 9.6, Release Date: 2022-05-15'
First we set up the notebook to display mathematical objects using LaTeX formatting:
%display latex
We declare the spacetime $M$ as a 4-dimensional Lorentzian manifold:
M = Manifold(4, 'M', structure='Lorentzian')
print(M)
4-dimensional Lorentzian manifold M
We introduce the standard FLRW coordinates, via the method chart()
, the argument of which is a string expressing the coordinates names, their ranges (the default is $(-\infty,+\infty)$) and their LaTeX symbols:
fr.<t,r,th,ph> = M.chart(r't r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
fr
Assuming units where that the speed of light is 1, let us define a few variables: Newton's constant $G$, the cosmological constant $\Lambda$, the spatial curvature constant $k$, the scale factor $a(t)$, the fluid proper density $\rho(t)$ and the fluid pressure $p(t)$:
G = var('G', domain='real')
Lambda = var('Lambda', domain='real')
k = var('k', domain='real')
a = M.scalar_field(function('a')(t), name='a')
rho = M.scalar_field(function('rho')(t), name='rho')
p = M.scalar_field(function('p')(t), name='p')
The FLRW metric is defined by its components in the manifold's default frame, i.e. the frame associated with the FLRW coordinates:
g = M.metric()
g[0,0] = -1
g[1,1] = a*a/(1 - k*r^2)
g[2,2] = a*a*r^2
g[3,3] = a*a*(r*sin(th))^2
g.display()
A matrix view of the metric components:
g[:]
The Levi-Civita connection associated with the metric is computed:
nabla = g.connection()
g.christoffel_symbols_display()
Ricci tensor:
Ricci = nabla.ricci()
Ricci.display()
Ricci.display_comp()
Ricci scalar ($R^\mu_{\ \, \mu}$):
Ricci_scalar = g.ricci_scalar()
Ricci_scalar.display()
The fluid 4-velocity:
u = M.vector_field('u')
u[0] = 1
u.display()
g(u,u).expr()
u.dot(u)
is equivalent to g(u,u)
:
u.dot(u).expr()
Perfect fluid energy-momentum tensor $T$:
u_form = u.down(g) # the 1-form associated to u by metric duality
T = (rho+p)*(u_form*u_form) + p*g
T.set_name('T')
print(T)
T.display()
Field of symmetric bilinear forms T on the 4-dimensional Lorentzian manifold M
The trace of $T$ (we use index notation to denote the double contraction $g^{ab} T_{ab}$):
Ttrace = g.inverse()['^ab']*T['_ab']
Ttrace.display()
Einstein equation: $R_{\mu \nu} - {1 \over 2} R g_{\mu \nu} + \Lambda g_{\mu \nu} = {8 \pi G} T_{\mu \nu}$
E1 = Ricci - Ricci_scalar/2*g + Lambda*g - (8*pi*G)*T
print("First Friedmann equation:\n")
E1[0,0].expr().expand() == 0
First Friedmann equation:
Trace-reversed version of the Einstein equation: $R_{\mu \nu} - \Lambda g_{\mu \nu} = {8 \pi G} \left(T_{\mu \nu} - {1 \over 2}T\,g_{\mu \nu}\right)$
E2 = Ricci - Lambda*g - (8*pi*G)*(T - Ttrace/2*g)
print("Second Friedmann equation:\n")
E2[0,0].expr().expand() == 0
Second Friedmann equation: