Friedmann equations

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 within the SageManifolds project (version 1.3, as included in SageMath 8.3).

Click here to download the notebook 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 notebook:

In [1]:
version()
Out[1]:
'SageMath version 8.3, Release Date: 2018-08-03'

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

In [2]:
%display latex

We declare the spacetime M as a 4-dimensional Lorentzian manifold:

In [3]:
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:

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

Assuming that the speed of light c=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)$:

In [5]:
var('G, Lambda, 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:

In [6]:
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()
Out[6]:

A matrix view of the metric components:

In [7]:
g[:]
Out[7]:

The Levi-Civita connection associated with the metric is computed:

In [8]:
nabla = g.connection()
g.christoffel_symbols_display()
Out[8]:

Ricci tensor:

In [9]:
Ricci = nabla.ricci()
Ricci.display()
Out[9]:
In [10]:
Ricci.display_comp()
Out[10]:

Ricci scalar ($R^\mu_{\ \, \mu}$):

In [11]:
Ricci_scalar = g.ricci_scalar()
Ricci_scalar.display()
Out[11]:

The fluid 4-velocity:

In [12]:
u = M.vector_field('u')
u[0] = 1
u.display()
Out[12]:
In [13]:
g(u,u).expr()
Out[13]:

u.dot(u) is equivalent to g(u,u):

In [14]:
u.dot(u).expr()
Out[14]:

Perfect fluid energy-momentum tensor $T$:

In [15]:
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
Out[15]:

The trace of $T$ (we use index notation to denote the double contraction $g^{ab} T_{ab}$):

In [16]:
Ttrace = g.inverse()['^ab']*T['_ab']
Ttrace.display()
Out[16]:

Einstein equation: $R_{\mu \nu} - {1 \over 2} R g_{\mu \nu} + \Lambda g_{\mu \nu} = {8 \pi G} T_{\mu \nu}$

In [17]:
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:

Out[17]:

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)$

In [18]:
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:

Out[18]:
In [ ]: