EinsteinPy - Making Einstein possible in Python

EinsteinPy logo

EinsteinPy is an open-source pure Python package dedicated to the study of problems arising in General Relativity and gravitational physics. Using EinsteinPy, it is possible to approach problems symbolically as well as numerically.

On the symbolic side, EinsteinPy provides a robust API, which allows users to access several predefined metrics or to define custom metrics and perform symbolic calculations on them. Computation of quantities, such as terms of metric tensors, Christoffel symbols, Riemann Curvature tensor, Ricci tensor, stress-energy tensor and more are all supported and extensible, since the symbolic modules are built on top of SymPy.

On the numerical side, EinsteinPy provides tools to calculate and visualize geodesics, metric singularities and hypersurface embeddings in certain spacetimes. We hope to extend the package to include more features in the future.

EinsteinPy works on recent versions of Python and is released under the MIT license, hence allowing commercial use of the library.

Motivation

Most of the general relativity packages currently available in the gravitational physics research community demand knowledge of paid-for software / computer algebra systems or programming experience in languages like C/C++. Many of the people working in the field of gravitational physics come from a theoretical background and have little programming experience. As such, they find using these libraries difficult. EinsteinPy is motivated by these problems and aims to provide a high level of abstraction, that enables anyone to do general relativity calculations without being bogged down by the implementation details or obscure errors. Since the library is written in Python, it is easy to use and understand, which also makes it a perfect fit for teaching purposes.

Moreover, EinsteinPy being FOSS also helps interested users understand the code and modify it to suit their needs, which in turn grows the project and positively adds to the research community.


EinsteinPy is developed by an open community. Hence, all contributions are more than welcome! Visit our GitHub to view EinsteinPy’s source code and to report errors or suggest improvements. For information on contributing code to the project, head to the developer guide.

element Join the chat at https://gitter.im/EinsteinPy-Project/EinsteinPy

Please join our Element channel or Gitter chat room for general discussions and further queries. Release announcements take place on our mailing list.

If you still have a doubt, write to us directly at all@einsteinpy.org.

Please use the links below or on the navigation bar to explore some examples or the API documentation. If you want to view the documentation for a specific version, please use the pop-up menu on the bottom-right corner of the page.


Contents

General Relativity Primer

This page provides a high-level overview of some of the concepts in General Relativity. For more detailed treatments, see the references at the end of this page.

Einstein’s Field Equations

Einstein’s Field Equations (EFE) relate local spacetime curvature with local energy and momentum. In short, these equations determine the metric tensor of a spacetime, given the arrangement of stress-energy. The EFE are given as follows:

\[\boxed{R_{\mu\nu} - \frac{1}{2}Rg_{\mu\nu} + \Lambda g_{\mu\nu} = \frac{8\pi G}{c^4}T_{\mu\nu}}.\]

Here, \(R_{\mu\nu}\) is the Ricci tensor, \(R\) is the scalar curvature (trace of Ricci tensor), \(g_{\mu\nu}\) is the metric tensor, \(\Lambda\) is the cosmological constant and lastly, \(T_{\mu\nu}\) denotes the stress-energy tensor. All other variables hold their usual meaning. If we introduce the Einstein tensor \(G_{\mu\nu} = R_{\mu\nu} - \frac{1}{2}Rg_{\mu\nu}\), then the EFE can be written as:

\[\boxed{G_{\mu\nu} = \frac{8\pi G}{c^4}T_{\mu\nu} - \Lambda g_{\mu\nu}}.\]

These equations form a ten-component tensor equation, which collectively denotes a system of coupled non-linear partial differential equations. These are usually intractable to approach analytically. However, under certain conditions, the EFE can be simplified and solved to yield exact solutions. For example, if the Einstein tensor is assumed to vanish, which implies that the stress-energy tensor also vanishes, then the EFE reduces to the vacuum Einstein equations, whose solutions are called vacuum solutions. The Minkowski, Schwarzschild and Kerr spacetimes are some examples of vacuum solutions.

Similarly, if an electromagnetic field is assumed to be present and also the only source of non-gravitational energy, then the EFE reduces to the source-free Maxwell-Einstein equations, whose exact solutions are termed electrovacuum solutions. The Kerr-Newman and Reissner-Nordström spacetimes are examples of electrovacuum solutions.

Metric Tensor

The metric tensor denotes a solution to the EFE. As such, it is a fundamental entity in general relativity, that captures the geometry of spacetime. It is a symmetric, indefinite rank-2 tensor, which can be represented by a matrix. It can be thought of as characterizing the differential line element for a given geometry:

\[\mathrm{d} s^2 = g_{\mu\nu}\mathrm{d}x^{\mu}\mathrm{d}x^{\nu}\]

To get the matrix representation, the coefficients, \(g_{\mu\nu}\), in the above equation are substituted into the corresponding places designated by the indices, \(\mu\) and \(\nu\), in a matrix. For example, the metric tensor in the spherical-polar coordinate system can be written as:

\[\begin{split}g_{\mu\nu} = \begin{pmatrix} 1 & 0 & 0 \\ 0 & r^2 & 0 \\ 0 & 0 & r^2\sin^2\theta \end{pmatrix}\end{split}\]

Note that the off-diagonal components are 0, since we are using an orthogonal basis. However, it is not always the case and in general, \(g_{\mu\nu} \ne 0\), for \(\mu \ne \nu\).

The metric tensor is also used to define the operations of lowering and raising indices. For this, we also need the inverse metric tensor, \(g^{\mu\nu}\) (or contravariant metric tensor to be precise), which is defined using the following identity:

\[g^{\mu\nu}g_{\nu\lambda} = \delta^{\mu}_{\lambda}\]

The inverse metric tensor can then be used to raise indices, while the metric tensor can be used to lower indices.

Notion of Curved Space

Imagine a bug traveling on a sheet of paper folded into a cone. The bug can’t see up and down. So, it lives in a 2D world. But it still experiences the curvature of the surface (space), as, after a long journey, it would return to the starting position.

Mathematically, the curvature of space is characterized by the rank-4 Riemann Curvature tensor, whose contraction gives the rank-2 Ricci tensor. Taking the trace of the Ricci tensor yields the rank-0 Ricci Scalar or Scalar Curvature.

Straight lines in Curved Space

Straight lines are used to describe the shortest path between two points in Euclidean space. Geodesics extend this notion of “shortest path” to curved spaces. In GR, geodesics represent the shortest path between two points in a possibly curved spacetime. They are completely characterized by the metric tensor and its derivatives, resulting in a set of coupled ordinary differential equations:

\[\boxed{\frac{\mathrm{d}^2x^{\mu}}{\mathrm{d}s^2} + \Gamma^{\mu}_{\alpha\beta}\frac{\mathrm{d}x^{\alpha}}{\mathrm{d}s}\frac{\mathrm{d}x^{\beta}}{\mathrm{d}s} = 0}\]

Here, \(x\) denotes the geodesic and the derivatives are taken with respect to \(s\), an affine parameter that uniquely parameterizes \(x\). \(\Gamma^{\mu}_{\alpha\beta}\) denotes Christoffel symbols of the second kind, which is essentially an array of partial derivatives of the metric tensor, computed with respect to the coordinate basis. It can be thought of as a “connection” between the derivates of nearby points along the geodesic and is given as:

\[\Gamma^{\mu}_{\alpha\beta} = \frac{1}{2}g^{\mu\gamma}\left(\frac{\partial g_{\alpha\beta}}{\partial x^{\gamma}} + \frac{\partial g_{\alpha\gamma}}{\partial x^{\beta}} - \frac{\partial g_{\beta\gamma}}{\partial x^{\alpha}}\right)\]

The Riemann Curvature tensor encapsulates the idea of curvature in GR. It can be written in a condensed notation using the Christoffel symbols and their derivaties:

\[\boxed{R^{\mu}_{\alpha\beta\gamma} = \partial_\gamma\Gamma^{\mu}_{\alpha\beta} - \partial_\beta\Gamma^{\mu}_{\alpha\gamma} + \Gamma^{\mu}_{\alpha\delta}\Gamma^{\delta}_{\beta\gamma} - \Gamma^{\mu}_{\beta\delta}\Gamma^{\delta}_{\alpha\gamma}}\]

A space with zero curvature implies that the Riemann tensor is zero and vice-versa. Since, we are dealing with tensors, i.e. objects that operate independently of basis choice, this statement holds for any coordinate system, i.e. \(R = 0\) in one coordinate system implies \(R = 0\) and by extension, zero curvature in all coordinate systems.

The Ricci tensor is another geometrical object in GR that is related to curvature. It can be obtained by contracting the first and third indices of the Riemann tensor:

\[R_{\mu\nu} = R^{\rho}_{\mu\rho\nu}\]

\(R_{\mu\nu}\) can be thought of as quantifying the deformation of a shape as it is translated along a given geodesic. The trace of the Ricci tensor gives the Scalar Curvature, \(R\):

\[R = g^{\mu\nu}R_{\mu\nu}\]

\(R\) relates the volume of infinitesimal geodesic balls in curved space to that in Euclidean space.

With this, we end our short and superficial look into some of the basic quantities that are used to characterize the structure of spacetime in General Relativity. Readers, who are interested in gaining a deeper understanding, are strongly recommended to peruse the resources listed below.


References

Installation

Stable version

You can install the most recent stable version of EinsteinPy in the following ways. At the moment, using pip is recommended, since the package on conda-forge is currently a version behind PyPI. We are working on updating it.

  • Using pip:

    $ pip install einsteinpy
    
  • Using conda:

    $ conda install -c conda-forge einsteinpy
    
Latest version

For installing the latest version, you can use any of the following methods:

  • Installation from clone:

    $ git clone https://github.com/einsteinpy/einsteinpy.git
    $ cd einsteinpy/
    $ pip install .
    
  • Install using pip:

    $ pip install git+https://github.com/einsteinpy/einsteinpy.git
    

Note that the latest version is not guaranteed to be stable.

Development version

If you want to contribute to EinsteinPy, please see the Developer Guide for instructions on how to set up your development environment and start contributing.


First run

Now that you have EinsteinPy installed, you can try out some of the examples listed in the Examples section. Below, we demonstrate a simple example of plotting a precessing timelike geodesic in Schwarzschild spacetime.

from einsteinpy.plotting import StaticGeodesicPlotter
from einsteinpy.examples import precession

gpl = StaticGeodesicPlotter()
gpl.plot2D(precession())
gpl.show()
Precession in Schwarzschild spacetime

Introduction

This page gives a brief overview of some of the features of EinsteinPy. For more complete hands-on tutorials, please refer to the Jupyter notebooks in Examples.

metric Module

EinsteinPy provides a way to define the background geometry for relativistic dynamics. This geometry has a central operating quantity known as the Metric tensor, that encapsulates all the geometrical and topological information about the 4D spacetime.

  • EinsteinPy provides a BaseMetric class, that has various utility functions and a proper template, that can be used to define custom Metric classes. All predefined classes in metric derive from this class.

  • The central quantities required to simulate the trajectory of a particle in a gravitational field are the metric derivatives, that can be succinctly written using Christoffel Symbols. EinsteinPy provides an easy-to-use interface to calculate these symbols for the predefined metrics. To perform calculations for general metrics, see the symbolic module.

  • BaseMetric also provides support for f_vec and perturbation, where f_vec corresponds to the RHS of the geodesic equation and perturbation is a linear Kerr-Schild Perturbation that can be defined on the underlying metric. Note that EinsteinPy does not perform physical checks on perturbation currently. Users should exercise caution while using it.


geodesic Module

EinsteinPy provides an intuitive interface for calculating timelike and nulllike geodesics for vacuum solutions. Below, we calculate the orbit of a precessing particle in Schwarzschild spacetime.

First, we import all the relevant modules and classes and define the initial conditions for our test particle, such as its initial 3-position in spherical coordinates and corresponding 3-momentum (or 3-velocity, given that we are working in geometric units with \(M = 1\)).

import numpy as np
from einsteinpy.geodesic import Timelike
from einsteinpy.plotting.geodesic import StaticGeodesicPlotter


position = [40., np.pi / 2, 0.]
momentum = [0., 0., 3.83405]
a = 0. # Spin = 0 for a Schwarzschild black hole
steps = 5500 # Number of steps to be taken by the solver
delta = 1 # Step size

After defining our initial conditions, we can use Timelike to create a Geodesic object, that automatically calculates the trajectory.

geod = Timelike(
    metric="Schwarzschild",
    metric_params=(a,),
    position=position,
    momentum=momentum,
    steps=steps,
    delta=delta,
    suppress_warnings=True,
    return_cartesian=True
)
print(geod)
Geodesic Object:(
    Type : (Time-like),
    Metric : (Schwarzschild),
    Metric Parameters : ((0.0,)),
    Initial 4-Position : ([ 0.         40.          1.57079633  0.        ]),
    Initial 4-Momentum : ([-0.97914661  0.          0.          3.83405   ]),
    Trajectory = (
        (array([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,
                13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
                26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
                ...
                468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480,
                481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493,
                494, 495, 496, 497, 498, 499]),
        array([[ 1.03068069e+00,  3.99997742e+01,  9.58510673e-02, ...,
                -3.87363444e-04,  5.62571365e-19,  3.83405000e+00],
                [ 2.06136190e+00,  3.99987445e+01,  1.91699898e-01, ...,
                -9.48048366e-04,  1.12515772e-18,  3.83404999e+00],
                ...,
                [ 5.71172446e+02,  1.55983863e+01,  1.49940531e+01, ...,
                1.65861080e-01,  3.12992232e-15,  3.83405010e+00],
                [ 5.72250940e+02,  1.55832138e+01,  1.52252617e+01, ...,
                1.64780132e-01,  3.13183198e-15,  3.83404993e+00]]))
    ),
    Output Position Coordinate System = (Cartesian)
))

We can also obtain a static plot of the geodesic using StaticGeodesicPlotter.

# Use InteractiveGeodesicPlotter() to get interactive plots
sgpl = StaticGeodesicPlotter()
sgpl.plot2D(geod)
sgpl.show()
_images/precess.png

coordinates Module

EinsteinPy currently supports 3 coordinate systems, namely, Cartesian, Spherical and Boyer-Lindquist. The coordinates module provides a way to convert between these coordinate systems. Below, we show how to convert 4-positions and velocities (defined alongside positions) between Cartesian and Boyer-Lindquist coordinates.

import numpy as np
from astropy import units as u
from einsteinpy.coordinates import BoyerLindquistDifferential, CartesianDifferential, Cartesian, BoyerLindquist

M = 1e20 * u.kg
a = 0.5 * u.one

# 4-Position
t = 1. * u.s
x = 0.2 * u.km
y = 0.15 * u.km
z = 0. * u.km

_4pos_cart = Cartesian(t, x, y, z)

# The keyword arguments, M & a are required for conversion to & from Boyer-Lindquist coordinates
_4pos_bl = _4pos_cart.to_bl(M=M, a=a)
print(_4pos_bl)

cartsn_pos = _4pos_bl.to_cartesian(M=M, a=a)
print(cartsn_pos)

# With position & velocity
v_x = 150 * u.km / u.s
v_y = 250 * u.km / u.s
v_z = 0. * u.km / u.s

pos_vel_cart = CartesianDifferential(t, x, y, z, v_x, v_y, v_z)

# Converting to Boyer-Lindquist coordinates
pos_vel_bl = pos_vel_cart.bl_differential(M=M, a=a)
print(pos_vel_bl)

# Converting back to Cartesian coordinates
pos_vel_cart = pos_vel_bl.cartesian_differential(M=M, a=a)
print(pos_vel_cart)
Boyer-Lindquist Coordinates:
    t = (1.0 s), r = (250.0 m), theta = (1.5707963267948966 rad), phi = (0.6435011087932844 rad)
Cartesian Coordinates:
    t = (1.0 s), x = (200.0 m), y = (150.0 m), z = (1.5308084989341916e-14 m)
Boyer-Lindquist Coordinates:
    t = (1.0 s), r = (250.0 m), theta = (1.5707963267948966 rad), phi = (0.6435011087932844 rad)
    v_t: None, v_r: 270000.0 m / s, v_th: -0.0 rad / s, v_p: 440.0 rad / s
Cartesian Coordinates:
    t = (1.0 s), x = (200.0 m), y = (150.0 m), z = (1.5308084989341916e-14 m)
    v_t: None, v_x: 150000.0 m / s, v_y: 250000.0 m / s, v_z: 1.6532731788489268e-11 m / s

You can also pass a einsteinpy.metric.* object to the differential object to set v_t. For usage without units, see the functions in einsteinpy.coordinates.util.


symbolic Module

EinsteinPy also supports a robust symbolic module that allows users to access several predefined metrics, or to define custom metrics and perform symbolic calculations. A short example with a predefined metric is shown below.

from sympy import simplify
from einsteinpy.symbolic import Schwarzschild, ChristoffelSymbols, EinsteinTensor

m = Schwarzschild()
ch = ChristoffelSymbols.from_metric(m)
G1 = EinsteinTensor.from_metric(m)
print(f"ch(1, 2, k) = {simplify(ch[1, 2, :])}") # k is an index in [0, 1, 2, 3]
print(G1.arr)
ch(1, 2, k) = [0, 0, -r + r_s, 0]
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Utility functions

EinsteinPy provides a great set of utility functions in many of the modules which are frequently used in general and numerical relativity.

  • Utils in coordinates, that allow:
    • Unitless conversion between coordinate systems for both position & velocity in the following systems:
      • Cartesian

      • Spherical

      • Boyer-Lindquist

    • Calculation of Lorentz factor

    • Calculation of timelike component of 4-velocity in any pseudo-Riemannian metric

  • Utils in geodesic that can be used to calculate quantities related to the vacuum solutions, such as:
    • \(\rho^2 = r^2 + a^2\cos^2(\theta)\) or \(\Delta = r^2 - r_s r + a^2 + r_Q^2\)

    • Calculation of particle 4-momentum


Future Plans
  • Support for null-geodesics in different geometries
    • Partial support is available for vacuum solutions since version 0.4.0.

  • Ultimate goal is to provide numerical solutions for Einstein’s equations for arbitrarily complex matter distributions.

  • Relativistic hydrodynamics

Examples

Here, we have listed some Jupyter notebooks that exemplify the usage of various features offered by EinsteinPy. We have broadly divided them into two categories: Symbolic and Numerical computations. To run these notebooks on the web, please use the binder link provided below.

mybinder

Symbolic computations
Einstein Tensor calculations using Symbolic module
[1]:
import sympy
from sympy import symbols, sin, cos, sinh
from einsteinpy.symbolic import EinsteinTensor, MetricTensor

sympy.init_printing()
Defining the Anti-de Sitter spacetime Metric
[2]:
syms = sympy.symbols("t chi theta phi")
t, ch, th, ph = syms
m = sympy.diag(-1, cos(t) ** 2, cos(t) ** 2 * sinh(ch) ** 2, cos(t) ** 2 * sinh(ch) ** 2 * sin(th) ** 2).tolist()
metric = MetricTensor(m, syms)
Calculating the Einstein Tensor (with both indices covariant)
[3]:
einst = EinsteinTensor.from_metric(metric)
einst.tensor()
[3]:
$\displaystyle \left[\begin{matrix}-3.0 & 0 & 0 & 0\\0 & 3.0 \cos^{2}{\left(t \right)} & 0 & 0\\0 & 0 & 3.0 \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)} & 0\\0 & 0 & 0 & 3.0 \sin^{2}{\left(\theta \right)} \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)}\end{matrix}\right]$
Lambdify in symbolic module
Importing required modules
[1]:
import sympy
from sympy import symbols
from einsteinpy.symbolic import BaseRelativityTensor

sympy.init_printing()
Calculating a Base Relativity Tensor
[2]:
syms = symbols("x y")
x, y = syms
T = BaseRelativityTensor([[x, 1],[0, x+y]], syms, config="ll")
Calling the lambdify function
[3]:
args, func = T.tensor_lambdify()
args
[3]:
$\displaystyle \left( x, \ y\right)$

args indicates the order in which arguments should be passed to the returned function func

Executing the returned function for some value
[4]:
func(2, 1)
[4]:
$\displaystyle \left[ \left[ 2, \ 1\right], \ \left[ 0, \ 3\right]\right]$
Contravariant & Covariant indices in Tensors (Symbolic)
[1]:
import sympy
from einsteinpy.symbolic import ChristoffelSymbols, RiemannCurvatureTensor
from einsteinpy.symbolic.predefined import Schwarzschild

sympy.init_printing()
Analysing the schwarzschild metric along with performing various operations
[2]:
sch = Schwarzschild()
sch.tensor()
[2]:
$\displaystyle \left[\begin{matrix}1 - \frac{r_{s}}{r} & 0 & 0 & 0\\0 & - \frac{1}{c^{2} \left(1 - \frac{r_{s}}{r}\right)} & 0 & 0\\0 & 0 & - \frac{r^{2}}{c^{2}} & 0\\0 & 0 & 0 & - \frac{r^{2} \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right]$
[3]:
sch_inv = sch.inv()
sch_inv.tensor()
[3]:
$\displaystyle \left[\begin{matrix}\frac{r}{r - r_{s}} & 0 & 0 & 0\\0 & \frac{c^{2} \left(- r + r_{s}\right)}{r} & 0 & 0\\0 & 0 & - \frac{c^{2}}{r^{2}} & 0\\0 & 0 & 0 & - \frac{c^{2}}{r^{2} \sin^{2}{\left(\theta \right)}}\end{matrix}\right]$
[4]:
sch.order
[4]:
$\displaystyle 2$
[5]:
sch.config
[5]:
'll'
Obtaining Christoffel Symbols from Metric Tensor
[6]:
chr = ChristoffelSymbols.from_metric(sch_inv) # can be initialized from sch also
chr.tensor()
[6]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & \frac{r_{s}}{2 r^{2} \left(1 - \frac{r_{s}}{r}\right)} & 0 & 0\\\frac{r_{s}}{2 r^{2} \left(1 - \frac{r_{s}}{r}\right)} & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}- \frac{r_{s} \left(- \frac{c^{2}}{2} + \frac{r_{s} c^{2}}{2 r}\right)}{r^{2}} & 0 & 0 & 0\\0 & \frac{r_{s} \left(- \frac{c^{2}}{2} + \frac{r_{s} c^{2}}{2 r}\right)}{r^{2} c^{2} \left(1 - \frac{r_{s}}{r}\right)^{2}} & 0 & 0\\0 & 0 & \frac{2 r \left(- \frac{c^{2}}{2} + \frac{r_{s} c^{2}}{2 r}\right)}{c^{2}} & 0\\0 & 0 & 0 & \frac{2 r \left(- \frac{c^{2}}{2} + \frac{r_{s} c^{2}}{2 r}\right) \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & \frac{1}{r} & 0\\0 & \frac{1}{r} & 0 & 0\\0 & 0 & 0 & - \sin{\left(\theta \right)} \cos{\left(\theta \right)}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & \frac{1}{r}\\0 & 0 & 0 & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}}\\0 & \frac{1}{r} & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}} & 0\end{matrix}\right]\end{matrix}\right]$
[7]:
chr.config
[7]:
'ull'
Changing the first index to covariant
[8]:
new_chr = chr.change_config('lll') # changing the configuration to (covariant, covariant, covariant)
new_chr.tensor()
[8]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & \frac{r_{s}}{2 r^{2}} & 0 & 0\\\frac{r_{s}}{2 r^{2}} & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}- \frac{r_{s}}{2 r^{2}} & 0 & 0 & 0\\0 & \frac{r_{s}}{2 c^{2} \left(r - r_{s}\right)^{2}} & 0 & 0\\0 & 0 & \frac{r}{c^{2}} & 0\\0 & 0 & 0 & \frac{r \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & - \frac{r}{c^{2}} & 0\\0 & - \frac{r}{c^{2}} & 0 & 0\\0 & 0 & 0 & \frac{r^{2} \sin{\left(2 \theta \right)}}{2 c^{2}}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & - \frac{r \sin^{2}{\left(\theta \right)}}{c^{2}}\\0 & 0 & 0 & - \frac{r^{2} \sin{\left(2 \theta \right)}}{2 c^{2}}\\0 & - \frac{r \sin^{2}{\left(\theta \right)}}{c^{2}} & - \frac{r^{2} \sin{\left(2 \theta \right)}}{2 c^{2}} & 0\end{matrix}\right]\end{matrix}\right]$
[9]:
new_chr.config
[9]:
'lll'
Any arbitary index configuration would also work!
[10]:
new_chr2 = new_chr.change_config('lul')
new_chr2.tensor()
[10]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & \frac{r_{s}}{2 r \left(r - r_{s}\right)} & 0 & 0\\\frac{r_{s} c^{2} \left(- r + r_{s}\right)}{2 r^{3}} & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}- \frac{r_{s}}{2 r \left(r - r_{s}\right)} & 0 & 0 & 0\\0 & - \frac{r_{s}}{2 r \left(r - r_{s}\right)} & 0 & 0\\0 & 0 & - \frac{1}{r} & 0\\0 & 0 & 0 & - \frac{1}{r}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & r - r_{s} & 0\\0 & \frac{1}{r} & 0 & 0\\0 & 0 & 0 & - \frac{1}{\tan{\left(\theta \right)}}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & \left(r - r_{s}\right) \sin^{2}{\left(\theta \right)}\\0 & 0 & 0 & \frac{\sin{\left(2 \theta \right)}}{2}\\0 & \frac{1}{r} & \frac{1}{\tan{\left(\theta \right)}} & 0\end{matrix}\right]\end{matrix}\right]$
Obtaining Riemann Tensor from Christoffel Symbols and manipulating it’s indices
[11]:
rm = RiemannCurvatureTensor.from_christoffels(new_chr2)
rm[0,0,:,:]
[11]:
$\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]$
[12]:
rm.config
[12]:
'ulll'
[13]:
rm2 = rm.change_config("uuuu")
rm2[0,0,:,:]
[13]:
$\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]$
[14]:
rm3 = rm2.change_config("lulu")
rm3[0,0,:,:]
[14]:
$\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]$
[15]:
rm4 = rm3.change_config("ulll")
rm4.simplify()
rm4[0,0,:,:]
[15]:
$\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]$
It is seen that rm and rm4 are same as they have the same configuration
Predefined Metrics in Symbolic Module
Importing some of the predefined tensors. All the metrics are comprehensively listed in EinsteinPy documentation.
[1]:
import sympy
from sympy import simplify
from einsteinpy.symbolic import RicciScalar
from einsteinpy.symbolic.predefined import Schwarzschild, DeSitter, AntiDeSitter, Minkowski, find

sympy.init_printing()  # for pretty printing
Printing the metrics for visualization

All the functions return instances of :py:class:~einsteinpy.symbolic.metric.MetricTensor

[2]:
sch = Schwarzschild()
sch.tensor()
[2]:
$\displaystyle \left[\begin{matrix}1 - \frac{r_{s}}{r} & 0 & 0 & 0\\0 & - \frac{1}{c^{2} \left(1 - \frac{r_{s}}{r}\right)} & 0 & 0\\0 & 0 & - \frac{r^{2}}{c^{2}} & 0\\0 & 0 & 0 & - \frac{r^{2} \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right]$
[3]:
Minkowski(c=1).tensor()
[3]:
$\displaystyle \left[\begin{matrix}-1 & 0 & 0 & 0\\0 & 1.0 & 0 & 0\\0 & 0 & 1.0 & 0\\0 & 0 & 0 & 1.0\end{matrix}\right]$
[4]:
DeSitter().tensor()
[4]:
$\displaystyle \left[\begin{matrix}-1 & 0 & 0 & 0\\0 & e^{\frac{2 x}{\alpha}} & 0 & 0\\0 & 0 & e^{\frac{2 x}{\alpha}} & 0\\0 & 0 & 0 & e^{\frac{2 x}{\alpha}}\end{matrix}\right]$
[5]:
AntiDeSitter().tensor()
[5]:
$\displaystyle \left[\begin{matrix}-1 & 0 & 0 & 0\\0 & \cos^{2}{\left(t \right)} & 0 & 0\\0 & 0 & \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)} & 0\\0 & 0 & 0 & \sin^{2}{\left(\theta \right)} \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)}\end{matrix}\right]$
Calculating the scalar (Ricci) curavtures

They should be constant for De-Sitter and Anti-De-Sitter spacetimes.

[6]:
scalar_curvature_de_sitter = RicciScalar.from_metric(DeSitter())
scalar_curvature_anti_de_sitter = RicciScalar.from_metric(AntiDeSitter())
[7]:
scalar_curvature_de_sitter.expr
[7]:
$\displaystyle - \frac{2 e^{- \frac{2 x}{\alpha}}}{\alpha^{2}}$
[8]:
scalar_curvature_anti_de_sitter.expr
[8]:
$\displaystyle -12$

On simplifying the expression we got above, we indeed obtain a constant

[9]:
simplify(scalar_curvature_anti_de_sitter.expr)
[9]:
$\displaystyle -12$
Searching for a predefined metric

find function returns a list of available functions

[10]:
find("sitter")
[10]:
['AntiDeSitter', 'AntiDeSitterStatic', 'DeSitter']
Ricci Tensor and Scalar Curvature calculations using Symbolic module
[1]:
import sympy
from einsteinpy.symbolic import RicciTensor, RicciScalar
from einsteinpy.symbolic.predefined import AntiDeSitter

sympy.init_printing()
Defining the Anti-de Sitter spacetime Metric
[2]:
metric = AntiDeSitter()
metric.tensor()
[2]:
$\displaystyle \left[\begin{matrix}-1 & 0 & 0 & 0\\0 & \cos^{2}{\left(t \right)} & 0 & 0\\0 & 0 & \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)} & 0\\0 & 0 & 0 & \sin^{2}{\left(\theta \right)} \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)}\end{matrix}\right]$
Calculating the Ricci Tensor(with both indices covariant)
[3]:
Ric = RicciTensor.from_metric(metric)
Ric.tensor()
[3]:
$\displaystyle \left[\begin{matrix}3 & 0 & 0 & 0\\0 & - 3 \cos^{2}{\left(t \right)} & 0 & 0\\0 & 0 & - 3 \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)} & 0\\0 & 0 & 0 & - 3 \sin^{2}{\left(\theta \right)} \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)}\end{matrix}\right]$
Calculating the Ricci Scalar(Scalar Curvature) from the Ricci Tensor
[4]:
R = RicciScalar.from_riccitensor(Ric)
R.simplify()
R.expr
[4]:
$\displaystyle -12$

The curavture is -12 which is in-line with the theoretical results

Symbolically Understanding Christoffel Symbol and Riemann Curvature Tensor using EinsteinPy
[1]:
import sympy
from einsteinpy.symbolic import MetricTensor, ChristoffelSymbols, RiemannCurvatureTensor

sympy.init_printing()  # enables the best printing available in an environment
Defining the metric tensor for 3d spherical coordinates
[2]:
syms = sympy.symbols('r theta phi')
# define the metric for 3d spherical coordinates
metric = [[0 for i in range(3)] for i in range(3)]
metric[0][0] = 1
metric[1][1] = syms[0]**2
metric[2][2] = (syms[0]**2)*(sympy.sin(syms[1])**2)
# creating metric object
m_obj = MetricTensor(metric, syms)
m_obj.tensor()
[2]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & r^{2} & 0\\0 & 0 & r^{2} \sin^{2}{\left(\theta \right)}\end{matrix}\right]$
Calculating the christoffel symbols
[3]:
ch = ChristoffelSymbols.from_metric(m_obj)
ch.tensor()
[3]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & 0 & 0\\0 & - r & 0\\0 & 0 & - r \sin^{2}{\left(\theta \right)}\end{matrix}\right] & \left[\begin{matrix}0 & \frac{1}{r} & 0\\\frac{1}{r} & 0 & 0\\0 & 0 & - \sin{\left(\theta \right)} \cos{\left(\theta \right)}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & \frac{1}{r}\\0 & 0 & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}}\\\frac{1}{r} & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}} & 0\end{matrix}\right]\end{matrix}\right]$
[4]:
ch.tensor()[1,1,0]
[4]:
$\displaystyle \frac{1}{r}$
Calculating the Riemann Curvature tensor
[5]:
# Calculating Riemann Tensor from Christoffel Symbols
rm1 = RiemannCurvatureTensor.from_christoffels(ch)
rm1.tensor()
[5]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\end{matrix}\right]$
[6]:
# Calculating Riemann Tensor from Metric Tensor
rm2 = RiemannCurvatureTensor.from_metric(m_obj)
rm2.tensor()
[6]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\end{matrix}\right]$
Calculating the christoffel symbols for Schwarzschild Spacetime Metric
  • The expressions are unsimplified

[7]:
syms = sympy.symbols("t r theta phi")
G, M, c, a = sympy.symbols("G M c a")
# using metric values of schwarschild space-time
# a is schwarzschild radius
list2d = [[0 for i in range(4)] for i in range(4)]
list2d[0][0] = 1 - (a / syms[1])
list2d[1][1] = -1 / ((1 - (a / syms[1])) * (c ** 2))
list2d[2][2] = -1 * (syms[1] ** 2) / (c ** 2)
list2d[3][3] = -1 * (syms[1] ** 2) * (sympy.sin(syms[2]) ** 2) / (c ** 2)
sch = MetricTensor(list2d, syms)
sch.tensor()
[7]:
$\displaystyle \left[\begin{matrix}- \frac{a}{r} + 1 & 0 & 0 & 0\\0 & - \frac{1}{c^{2} \left(- \frac{a}{r} + 1\right)} & 0 & 0\\0 & 0 & - \frac{r^{2}}{c^{2}} & 0\\0 & 0 & 0 & - \frac{r^{2} \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right]$
[8]:
# single substitution
subs1 = sch.subs(a,0)
subs1.tensor()
[8]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & 0\\0 & - \frac{1}{c^{2}} & 0 & 0\\0 & 0 & - \frac{r^{2}}{c^{2}} & 0\\0 & 0 & 0 & - \frac{r^{2} \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right]$
[9]:
# multiple substitution
subs2 = sch.subs([(a,0), (c,1)])
subs2.tensor()
[9]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & 0\\0 & -1 & 0 & 0\\0 & 0 & - r^{2} & 0\\0 & 0 & 0 & - r^{2} \sin^{2}{\left(\theta \right)}\end{matrix}\right]$
[10]:
sch_ch = ChristoffelSymbols.from_metric(sch)
sch_ch.tensor()
[10]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & \frac{a}{2 r^{2} \left(- \frac{a}{r} + 1\right)} & 0 & 0\\\frac{a}{2 r^{2} \left(- \frac{a}{r} + 1\right)} & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}- \frac{a \left(\frac{a c^{2}}{2 r} - \frac{c^{2}}{2}\right)}{r^{2}} & 0 & 0 & 0\\0 & \frac{a \left(\frac{a c^{2}}{2 r} - \frac{c^{2}}{2}\right)}{c^{2} r^{2} \left(- \frac{a}{r} + 1\right)^{2}} & 0 & 0\\0 & 0 & \frac{2 r \left(\frac{a c^{2}}{2 r} - \frac{c^{2}}{2}\right)}{c^{2}} & 0\\0 & 0 & 0 & \frac{2 r \left(\frac{a c^{2}}{2 r} - \frac{c^{2}}{2}\right) \sin^{2}{\left(\theta \right)}}{c^{2}}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & \frac{1}{r} & 0\\0 & \frac{1}{r} & 0 & 0\\0 & 0 & 0 & - \sin{\left(\theta \right)} \cos{\left(\theta \right)}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & \frac{1}{r}\\0 & 0 & 0 & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}}\\0 & \frac{1}{r} & \frac{\cos{\left(\theta \right)}}{\sin{\left(\theta \right)}} & 0\end{matrix}\right]\end{matrix}\right]$
Calculating the simplified expressions
[11]:
simplified = sch_ch.simplify()
simplified
[11]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & \frac{a}{2 r \left(- a + r\right)} & 0 & 0\\\frac{a}{2 r \left(- a + r\right)} & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}\frac{a c^{2} \left(- a + r\right)}{2 r^{3}} & 0 & 0 & 0\\0 & \frac{a}{2 r \left(a - r\right)} & 0 & 0\\0 & 0 & a - r & 0\\0 & 0 & 0 & \left(a - r\right) \sin^{2}{\left(\theta \right)}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & \frac{1}{r} & 0\\0 & \frac{1}{r} & 0 & 0\\0 & 0 & 0 & - \frac{\sin{\left(2 \theta \right)}}{2}\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & \frac{1}{r}\\0 & 0 & 0 & \frac{1}{\tan{\left(\theta \right)}}\\0 & \frac{1}{r} & \frac{1}{\tan{\left(\theta \right)}} & 0\end{matrix}\right]\end{matrix}\right]$
Weyl Tensor calculations using Symbolic module
[1]:
import sympy
from sympy import cos, sin, sinh
from einsteinpy.symbolic import MetricTensor, WeylTensor

sympy.init_printing()
Defining the Anti-de Sitter spacetime Metric
[2]:
syms = sympy.symbols("t chi theta phi")
t, ch, th, ph = syms
m = sympy.diag(-1, cos(t) ** 2, cos(t) ** 2 * sinh(ch) ** 2, cos(t) ** 2 * sinh(ch) ** 2 * sin(th) ** 2).tolist()
metric = MetricTensor(m, syms)
Calculating the Weyl Tensor (with all indices covariant)
[3]:
weyl = WeylTensor.from_metric(metric)
weyl.tensor()
[3]:
$\displaystyle \left[\begin{matrix}\left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]\\\left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] & \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right]\end{matrix}\right]$
[4]:
weyl.config
[4]:
'llll'

These notebooks demonstrate the features of the symbolic module in EinsteinPy. You can use this module to access several pre-defined metrics or define custom ones, and calculate quantities such as the Christoffel symbols, Ricci tensor, Ricci scalar, Riemann curvature tensor, Einstein tensor and Weyl tensor. Since this module is based on SymPy, you can also use the lambdify() function to convert EinsteinPy’s symbolic expressions into NumPy-compatible functions. Indicial operations are also possible using this module, as shown in the notebook on contravariant and covariant indices.

Numerical computations
Animations in EinsteinPy
Importing required modules
[1]:
import numpy as np

from einsteinpy.geodesic import Timelike
from einsteinpy.plotting import StaticGeodesicPlotter
Defining various parameters
  • Initial position & momentum of the test partcle

  • Spin of the Kerr Black Hole in metric_params

  • Other solver parameters

Note that, we are working in M-Units (\(G = c = M = 1\)).

[2]:
# Constant Radius Orbit
position = [4, np.pi / 3, 0.]
momentum = [0., 0.767851, 2.]
a = 0.99
steps = 400.
delta = 0.5
Calculating geodesic
[3]:
geod = Timelike(
    metric="Kerr",
    metric_params=(a,),
    position=position,
    momentum=momentum,
    steps=steps,
    delta=delta,
    return_cartesian=True
)
Animating
[4]:
%matplotlib widget
# Use %matplotlib ipympl instead if you are working in Visual Studio Code.
# You may need to `pip install ipympl` first.
sgpl = StaticGeodesicPlotter()
sgpl.animate(geod, interval=1)
sgpl.show()
Saving animation as .gif
[5]:
# You may need to install imagemagick separately to save the animation as a gif
# sgpl.ani.save('animation.gif', writer='imagemagick', fps=30)
Plotting Spatial Hypersurface Embedding for Schwarzschild Spacetime
[1]:
from einsteinpy.hypersurface import SchwarzschildEmbedding
from einsteinpy.plotting import HypersurfacePlotter
from astropy import units as u

Declaring embedding object with specified mass of the body and plotting the embedding hypersurface for Schwarzschild spacetime

[2]:
surface_obj = SchwarzschildEmbedding(5.927e23 * u.kg)
[3]:
surface = HypersurfacePlotter(embedding=surface_obj, plot_type='surface')
surface.plot()
surface.show()
_images/examples_Plotting_Spatial_Hypersurface_Embedding_for_Schwarzschild_Spacetime_4_0.png

The plotted embedding has initial Schwarzschild radial coordinate to be greater than schwarzschild radius but the embedding can be defined for coordinates greater than 9m/4. The Schwarzschild spacetime is a static spacetime and thus the embeddings can be obtained by considering fermat’s surfaces of stationary time coordinate and thus this surface also represent the spacial geometry on which light rays would trace their paths along geodesics of this surface (spacially)!

Shadow cast by a thin emission disk around a Schwarzschild black hole
[1]:
import astropy.units as u

from einsteinpy.rays import Shadow
from einsteinpy.plotting import ShadowPlotter

Defining the conditions

[2]:
mass = 1 * u.kg
fov = 30 * u.km
# What field of view is the user expecting
[3]:
shadow = Shadow(mass=mass, fov=fov, n_rays=1000)
[4]:
obj = ShadowPlotter(shadow=shadow, is_line_plot=True)
obj.plot()
obj.show()
_images/examples_Shadow_cast_by_a_thin_emission_disk_around_a_Schwarzschild_black_hole_5_0.png
[5]:
obj = ShadowPlotter(shadow=shadow, is_line_plot=False)
obj.plot()
obj.show()
_images/examples_Shadow_cast_by_a_thin_emission_disk_around_a_Schwarzschild_black_hole_6_0.png
Using Geodesics (Back-ends & Plotting)
[12]:
import numpy as np

from einsteinpy.geodesic import Geodesic, Timelike, Nulllike
from einsteinpy.plotting import GeodesicPlotter, StaticGeodesicPlotter, InteractiveGeodesicPlotter
Example 1: Exploring Schwarzschild Time-like Spiral Capture, using Python Backend and GeodesicPlotter
Defining initial conditions
[13]:
# Initial Conditions
position = [4., np.pi / 3, 0.]
momentum = [0., 0., -1.5]
a = 0. # Schwarzschild Black Hole
Calculating Geodesic
[14]:
geod = Timelike(
    metric = "Schwarzschild",
    metric_params = (a,),
    position=position,
    momentum=momentum,
    steps=15543, # As close as we can get before the integration becomes highly unstable
    delta=0.0005,
    return_cartesian=True,
    omega=0.01, # Small omega values lead to more stable integration
    suppress_warnings=True, # Uncomment to view the tolerance warning
)

geod
[14]:
Geodesic Object:(
            Type : (Time-like),
            Metric : (Schwarzschild),
            Metric Parameters : ((0.0,)),
            Initial 4-Position : ([0.         4.         1.04719755 0.        ]),
            Initial 4-Momentum : ([-0.77055175  0.          0.         -1.5       ]),
            Trajectory = (
                (array([    0,     1,     2, ..., 15540, 15541, 15542]), array([[ 7.70551750e-04,  3.46410160e+00, -2.16506351e-04, ...,
        -5.07812502e-05,  5.41265877e-05, -1.50000000e+00],
       [ 1.54110350e-03,  3.46410157e+00, -4.33012700e-04, ...,
        -1.01562501e-04,  1.08253176e-04, -1.50000000e+00],
       [ 2.31165526e-03,  3.46410152e+00, -6.49519046e-04, ...,
        -1.52343754e-04,  1.62379763e-04, -1.50000000e+00],
       ...,
       [ 2.10892615e+01,  5.06915642e-01, -1.93331152e+00, ...,
        -7.67875285e+01,  8.37708122e-01, -1.50000000e+00],
       [ 2.11285953e+01,  5.06465005e-01, -1.93307239e+00, ...,
        -7.82825155e+01,  8.37749353e-01, -1.50000000e+00],
       [ 2.11686915e+01,  5.06014321e-01, -1.93283308e+00, ...,
        -7.98370238e+01,  8.37790569e-01, -1.50000000e+00]]))
            ),
            Output Position Coordinate System = (Cartesian)
        ))
Plotting using GeodesicPlotter

Note that GeodesicPlotter automatically switches between “Static” and “Interactive” plots. Since we are in a Jupyter Notebook or Interactive Environment, it uses the “Interactive” backend.

[15]:
gpl = GeodesicPlotter()
[16]:
gpl.plot(geod, color="green", title="Geodesic Plot", aspect="auto")
gpl.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

[17]:
gpl.clear() # In Interactive mode, `clear()` must be called before drawing another plot, to avoid overlap
gpl.plot2D(geod, coordinates=(1, 2), color="green", title="Top/Bottom View") # "top" / "bottom" view
gpl.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

[18]:
gpl.clear()
gpl.plot2D(geod, coordinates=(1, 3), color="green", title="Face-On View") # "face-on" view
gpl.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

Each interactive plot instance (gpl) has a fig attribute that is a plotly.graph_objs._figure.Figure object. So, one can easily make modifications to the plots as they would to any plotly figure. For instance, we can update the title to clarify that the plot above is showing a face-on view.

[19]:
gpl.fig.layout.title = {
    'text': 'Face-On View', 'x': 0.46, 'xanchor': 'center', 'y': 0.9, 'yanchor': 'top'
}
gpl.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

[20]:
gpl.clear()
gpl.parametric_plot(geod, colors=("red", "green", "blue"))
gpl.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

Visualizing Event Horizon and Ergosphere (Singularities) of Kerr Metric or Black Hole
Importing required modules
[1]:
import astropy.units as u
import numpy as np
import astropy.units as u
import matplotlib.pyplot as plt

from einsteinpy.coordinates import BoyerLindquistDifferential
from einsteinpy.metric import Kerr
Defining black holes and obtaining singularities
[2]:
# Metric or Black Hole parameters - Mass, M and Spin Parameter, a
M = 4e30 * u.kg
a1 = 0.4 * u.one
a2 = 0.9 * u.one # Extremal Kerr Black Hole

# Coordinate object to initialize metric with
# Note that, for this example
# the coordinate values below are irrelevant
bl = BoyerLindquistDifferential(
    t=0. * u.s,
    r=1e3 * u.m,
    theta=np.pi / 2 * u.rad,
    phi=np.pi * u.rad,
    v_r=0. * u.m / u.s,
    v_th=0. * u.rad / u.s,
    v_p=0. * u.rad / u.s,
)

# Defining two Kerr Black Holes, one with a higher spin parameter
kerr1 = Kerr(coords=bl, M=M, a=a1)
kerr2 = Kerr(coords=bl, M=M, a=a2)

# Getting the list of singularities
sing_dict1 = kerr1.singularities()
sing_dict2 = kerr2.singularities()

# Let's check the contents of the dicts
# 'ergosphere' entries should be functions
print(sing_dict1, sing_dict2, sep="\n\n")
{'inner_ergosphere': <function BaseMetric.singularities.<locals>._in_ergo at 0x7f733c8b0f70>, 'inner_horizon': 247.98878315867296, 'outer_horizon': 5692.939432136259, 'outer_ergosphere': <function BaseMetric.singularities.<locals>._out_ergo at 0x7f730f324af0>}

{'inner_ergosphere': <function BaseMetric.singularities.<locals>._in_ergo at 0x7f733c062310>, 'inner_horizon': 1675.668821582463, 'outer_horizon': 4265.259393712469, 'outer_ergosphere': <function BaseMetric.singularities.<locals>._out_ergo at 0x7f733c0620d0>}
Preparing singularities for plotting
[3]:
# Sampling Polar Angle for plotting in Polar Coordinates
theta = np.linspace(0, 2 * np.pi, 100)

# Ergospheres
# These are functions
Ei1, Eo1 = sing_dict1["inner_ergosphere"], sing_dict1["outer_ergosphere"]
Ei2, Eo2 = sing_dict2["inner_ergosphere"], sing_dict2["outer_ergosphere"]

# Creating lists of points on Ergospheres for different polar angles, for both black holes
Ei1_list, Eo1_list = Ei1(theta), Eo1(theta)
Ei2_list, Eo2_list = Ei2(theta), Eo2(theta)

# For Black Hole 1 (a = 0.4)
Xei1 = Ei1_list * np.sin(theta)
Yei1 = Ei1_list * np.cos(theta)

Xeo1 = Eo1_list * np.sin(theta)
Yeo1 = Eo1_list * np.cos(theta)

# For Black Hole 2 (a = 0.9)
Xei2 = Ei2_list * np.sin(theta)
Yei2 = Ei2_list * np.cos(theta)

Xeo2 = Eo2_list * np.sin(theta)
Yeo2 = Eo2_list * np.cos(theta)

# Event Horizons
Hi1, Ho1 = sing_dict1["inner_horizon"], sing_dict1["outer_horizon"]
Hi2, Ho2 = sing_dict2["inner_horizon"], sing_dict2["outer_horizon"]

# For Black Hole 1 (a = 0.4)
Xhi1 = Hi1 * np.sin(theta)
Yhi1 = Hi1 * np.cos(theta)

Xho1 = Ho1 * np.sin(theta)
Yho1 = Ho1 * np.cos(theta)

# For Black Hole 2 (a = 0.9)
Xhi2 = Hi2 * np.sin(theta)
Yhi2 = Hi2 * np.cos(theta)

Xho2 = Ho2 * np.sin(theta)
Yho2 = Ho2 * np.cos(theta)
Plotting both black holes
[4]:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,7.5))

ax1.fill(Xei1, Yei1, 'b', Xeo1, Yeo1, 'r', Xhi1, Yhi1, 'b', Xho1, Yho1, 'r', alpha=0.3)
ax1.set_title(f"$M = {M}, a = {a1}$", fontsize=18)
ax1.set_xlabel("X", fontsize=18)
ax1.set_ylabel("Y", fontsize=18)
ax1.set_xlim([-6100, 6100])
ax1.set_ylim([-6100, 6100])

ax2.fill(Xei2, Yei2, 'b', Xeo2, Yeo2, 'r', Xhi2, Yhi2, 'b', Xho2, Yho2, 'r', alpha=0.3)
ax2.set_title(f"$M = {M}, a = {a2}$", fontsize=18)
ax2.set_xlabel("X", fontsize=18)
ax2.set_ylabel("Y", fontsize=18)
ax2.set_xlim([-6100, 6100])
ax2.set_ylim([-6100, 6100])
[4]:
(-6100.0, 6100.0)
_images/examples_Visualizing_Event_Horizon_and_Ergosphere_%28Singularities%29_of_Kerr_Metric_or_Black_Hole_7_1.png
  • The surfaces are clearly visible in the plots. Going radially inward, we have Outer Ergosphere, Outer Event Horizon, Inner Event Horizon and Inner Ergosphere. We can also observe the following:

    • As \(a \to 1\) (its maximum attainable value), the individual singularities become prominent.

    • As \(a \to 0\), some singularities appear to fade away, leaving us with a single surface, that is the Event Horizon of a Schwarzschild black hole.

Visualizing Frame Dragging in Kerr Spacetime
Importing required modules
[6]:
import numpy as np

from einsteinpy.geodesic import Nulllike
from einsteinpy.plotting import StaticGeodesicPlotter
Setting up the system
  • Initial position & momentum of the test partcle

  • Spin of the Kerr Black Hole

  • Other solver parameters

Note that, we are working in M-Units (\(G = c = M = 1\)). Also, setting momentum’s \(\phi\)-component to negative, implies an initial retrograde trajectory.

[7]:
position = [2.5, np.pi / 2, 0.]
momentum = [0., 0., -2.]
a = 0.99
steps = 7440  # As close as we can get before the integration becomes highly unstable
delta = 0.0005
omega = 0.01
suppress_warnings = True

Here, omega, the coupling between the hamiltonian flows, needs to be decreased in order to decrease numerical errors and increase integration stability. Reference: https://arxiv.org/abs/2010.02237.

Also, suppress_warnings has been set to True, as the error would grow exponentially, very close to the black hole.

Calculating the geodesic
[8]:
geod = Nulllike(
    metric="Kerr",
    metric_params=(a,),
    position=position,
    momentum=momentum,
    steps=steps,
    delta=delta,
    return_cartesian=True,
    omega=omega,
    suppress_warnings=suppress_warnings
)
Plotting the geodesic in 3D
[9]:
sgpl = StaticGeodesicPlotter(bh_colors=("red", "blue"))
sgpl.plot(geod, color="indigo", title="3D View", aspect="equal")
sgpl.show()
_images/examples_Visualizing_Frame_Dragging_in_Kerr_Spacetime_8_0.png
Plotting the geodesic in 2D
[10]:
sgpl = StaticGeodesicPlotter(bh_colors=("red", "blue"))
sgpl.plot2D(geod, coordinates=(1, 2), figsize=(10, 10), color="indigo") # Plot X vs Y
sgpl.show()
_images/examples_Visualizing_Frame_Dragging_in_Kerr_Spacetime_10_0.png

As can be seen in the plot above, the photon’s trajectory is reversed, due to frame-dragging effects, so that, it moves in the direction of the black hole’s spin, before eventually falling into the black hole.

Also, the last few steps seem to have a larger delta, but that is simply because of huge numerical errors, as the particle has crossed the Event Horizon.

Visualizing Precession in Schwarzschild Spacetime
Importing required modules
[10]:
import numpy as np

from einsteinpy.geodesic import Timelike
from einsteinpy.plotting.geodesic import StaticGeodesicPlotter
Setting up the system
  • Initial position & momentum of the test partcle

  • Spin of the Schwarzschild Black Hole (= 0)

  • Other solver parameters

Note that, we are working in M-Units (\(G = c = M = 1\)). Also, since the Schwarzschild spacetime has spherical symmetry, the values of the angular components do not affect the end result (We can always rotate our coordinate system to bring the geodesic in the equatorial plane). Hence, we set \(\theta = \pi / 2\) (equatorial plane), with initial \(p_\theta = 0\), which implies, that the geodesic should stay in the equatorial plane.

[11]:
position = [40., np.pi / 2, 0.]
momentum = [0., 0., 3.83405]
a = 0.
steps = 5500
delta = 1.
Calculating the geodesic
[12]:
geod = Timelike(
    metric="Schwarzschild",
    metric_params=(a,),
    position=position,
    momentum=momentum,
    steps=steps,
    delta=delta,
    return_cartesian=True
)
Plotting the geodesic
[13]:
sgpl = StaticGeodesicPlotter()
sgpl.plot(geod)
sgpl.show()
_images/examples_Visualizing_Precession_in_Schwarzschild_Spacetime_7_0.png

Apsidal Precession is easily observed through the plot, above, and as expected, the geodesic is confined to the equatorial plane. We can visualize this better, with a few 2D plots.

[5]:
sgpl.clear()
sgpl.plot2D(geod, coordinates=(1, 2)) # Plot X & Y
sgpl.show()
_images/examples_Visualizing_Precession_in_Schwarzschild_Spacetime_9_0.png
[16]:
sgpl.clear()
sgpl.plot2D(geod, coordinates=(1, 3)) # Plot X & Z
sgpl.show()
_images/examples_Visualizing_Precession_in_Schwarzschild_Spacetime_10_0.png
[17]:
sgpl.clear()
sgpl.plot2D(geod, coordinates=(2, 3)) # Plot Y & Z
sgpl.show()
_images/examples_Visualizing_Precession_in_Schwarzschild_Spacetime_11_0.png

Let’s see, how the coordinates change, with \(\lambda\) (Affine Parameter).

[18]:
sgpl.clear()
sgpl.parametric_plot(geod, colors=("cyan", "magenta", "lime")) # Plot X, Y, Z vs Lambda (Affine Parameter)
sgpl.show()
_images/examples_Visualizing_Precession_in_Schwarzschild_Spacetime_13_0.png

The lag between \(X1\) (\(x\)-component) and \(X2\) (\(y\)-component), in the parametric plot, reaffirms the results from above. Also, \(X3 \approx 0\) (\(z\)-component) in this plot, which is expected, as the geodesic never leaves the equatorial plane.

These notebooks show how to use the various numerical methods offered by EinsteinPy. Using these, you can compute and plot geodesics for manifolds described by (electro-)vacuum solutions to Einstein’s field equations. You can also calculate and view manifold singularities in these cases or calculate black hole shadows and hypersurface embeddings for certain spacetimes. EinsteinPy’s plotting module also enables making animations like these:

Kerr Singularities for different values of spin parameter Geodesic Animation in extremal Kerr Spacetime

EinsteinPy API

Welcome to the API documentation of EinsteinPy. Please navigate through the given modules to get to know the API of the classes and methods. If you find anything missing, please open an issue in the repo .

digraph {
    "einsteinpy" -> "integrators", "metric", "utils", "plotting", "constant", "units", "coordinates", "geodesic", "bodies", "hypersurface", "symbolic", "rays"

}
Integrators

This module contains methods for solving Ordinary Differential Equations in Numerical Relativity.

Runge Kutta module
class einsteinpy.integrators.runge_kutta.RK4naive(fun, t0, y0, t_bound, stepsize)[source]

Bases: object

Class for Defining Runge-Kutta 4th Order ODE solving method

Initialization

Parameters:
  • fun (function) – Should accept t, y as parameters, and return same type as y

  • t0 (float) – Initial t

  • y0 (array or float) – Initial y

  • t_bound (float) – Boundary time - the integration won’t continue beyond it. It also determines the direction of the integration.

  • stepsize (float) – Size of each increment in t

step()[source]

Updates the value of self.t and self.y

class einsteinpy.integrators.runge_kutta.RK45(fun, t0, y0, t_bound, stepsize, rtol=None, atol=None)[source]

Bases: RK45

This Class inherits ~scipy.integrate.RK45 Class

Initialization

Parameters:
  • fun (function) – Should accept t, y as parameters, and return same type as y

  • t0 (float) – Initial t

  • y0 (array or float) – Initial y

  • t_bound (float) – Boundary time - the integration won’t continue beyond it. It also determines the direction of the integration.

  • stepsize (float) – Size of each increment in t

  • rtol (float) – Relative tolerance, defaults to 0.2*stepsize

  • atol (float) – Absolute tolerance, defaults to rtol/0.8e3

step()[source]

Updates the value of self.t and self.y

FANTASY

This module uses Forward Mode Automatic Differentiation to calculate metric derivatives. Currently, integrators of orders 2, 4, 6 and 8 have been implemented.

class einsteinpy.integrators.fantasy.GeodesicIntegrator(metric, metric_params, q0, p0, time_like=True, steps=100, delta=0.5, rtol=0.01, atol=0.01, order=2, omega=1.0, suppress_warnings=False)[source]

Bases: object

Geodesic Integrator, based on [1]. This module uses Forward Mode Automatic Differentiation to calculate metric derivatives to machine precision leading to stable simulations.

References

Constructor

Parameters:
  • metric (callable) – Metric Function. Currently, these metrics are supported: 1. Schwarzschild 2. Kerr 3. KerrNewman

  • metric_params (array_like) – Tuple of parameters to pass to the metric E.g., (a,) for Kerr

  • q0 (array_like) – Initial 4-Position

  • p0 (array_like) – Initial 4-Momentum

  • time_like (bool, optional) – Determines type of Geodesic True for Time-like geodesics False for Null-like geodesics Defaults to True

  • steps (int) – Number of integration steps Defaults to 50

  • delta (float) – Initial integration step-size Defaults to 0.5

  • rtol (float) – Relative Tolerance Defaults to 1e-2

  • atol (float) – Absolute Tolerance Defaults to 1e-2

  • order (int) – Integration Order Defaults to 2

  • omega (float) – Coupling between Hamiltonian Flows Smaller values imply smaller integration error, but too small values can make the equation of motion non-integrable. For non-capture trajectories, omega = 1.0 is recommended. For trajectories, that either lead to a capture or a grazing geodesic, a decreased value of 0.01 or less is recommended. Defaults to 1.0

  • suppress_warnings (bool) – Whether to suppress warnings during simulation Warnings are shown for every step, where numerical errors exceed specified tolerance (controlled by rtol and atol) Defaults to False

Raises:

NotImplementedError – If order is not in [2, 4, 6, 8]

step()[source]

Advances integration by one step

Metric module

This module contains the basic classes of different metrics for various space-time geometries including schwarzschild, kerr etc.

base-metric module

This module contains the class, that defines a general spacetime. All other metric classes derive from it. It has methods, that can be used as utility functions. Users are recommended to inherit this class to create user-defined metric classes.

Docstring for base_metric.py module

This module defines the BaseMetric class, which is the base class for all metrics in EinsteinPy. This class contains several utilities, that are used in einsteinpy.metric to define classes for vacuum solutions. Users are advised to inherit this class, while defining their own metric classes. Two parameters to note are briefly described below:

  • metric_cov: User-supplied function, defining the covariant form of the metric tensor. Users need to supply just this to completely determine the metric tensor, as the contravariant form is calculated and accessed through a predefined method, metric_contravariant().

  • perturbation: User-supplied function, defining a perturbation to the metric. Currently, no checks are performed to ascertain the physicality of the resulting perturbed metric. Read the documentation on metric_covariant() below, to learn more.

Also, note that, users should call metric_covariant to access the perturbed, covariant form of the metric. For unperturbed underlying metric, users should call metric_cov, which returns the metric, that they had supplied.

class einsteinpy.metric.base_metric.BaseMetric(coords, M, a=<Quantity 0.>, Q=<Quantity 0. C>, name='Base Metric', metric_cov=None, christoffels=None, f_vec=None, perturbation=None)[source]

Bases: object

For defining a general Metric

Constructor

Parameters:
  • coords (*) – Coordinate system, in which Metric is to be represented

  • M (Quantity) – Mass of gravitating body, e.g. Black Hole

  • a (Quantity) – Dimensionless Spin Parameter Defaults to 0

  • Q (Quantity) – Charge on gravitating body, e.g. Black Hole Defaults to 0 C

  • name (str, optional) – Name of the Metric Tensor. Defaults to "Base Metric"

  • metric_cov (callable, optional) – Function, defining Covariant Metric Tensor It should return a real-valued tensor (2D Array), at supplied coordinates Defaults to None Consult pre-defined classes for function definition

  • christoffels (callable, optional) – Function, defining Christoffel Symbols It should return a real-valued (4,4,4) array, at supplied coordinates Defaults to None Consult pre-defined classes for function definition

  • f_vec (callable, optional) – Function, defining RHS of Geodesic Equation It should return a real-valued (8) vector, at supplied coordinates Defaults to None Consult pre-defined classes for function definition

  • perturbation (callable, optional) – Function, defining Covariant Perturbation Tensor It should return a real-valued tensor (2D Array), at supplied coordinates Defaults to None Function definition similar to metric_cov

static sigma(r, theta, M, a)[source]

Returns the value of r**2 + alpha**2 * cos(theta)**2 Specific to Boyer-Lindquist coordinates Applies to Kerr Geometry

Parameters:
Returns:

The value of r**2 + alpha**2 * cos(theta)**2

Return type:

float

static delta(r, M, a, Q=0)[source]

Returns the value of r**2 - r_s * r + alpha**2 + r_Q**2 Specific to Boyer-Lindquist coordinates Applies to Kerr & Kerr-Newman Geometries

Parameters:
Returns:

The value of r**2 - r_s * r + alpha**2 + r_Q**2

Return type:

float

static rho(r, theta, M, a)[source]

Returns the value of sqrt(r**2 + alpha**2 * cos(theta)**2) == sqrt(sigma) Specific to Boyer-Lindquist coordinates Applies to Kerr-Newman Geometry

Parameters:
Returns:

The value of sqrt(r**2 + alpha**2 * cos(theta)**2) == sqrt(sigma)

Return type:

float

static schwarzschild_radius(M)[source]

Returns Schwarzschild Radius

Parameters:

M (float or Quantity) – Mass of gravitating body

Returns:

Schwarzschild Radius for a given mass

Return type:

float

static alpha(M, a)[source]

Returns Rotational Length Parameter (alpha) that is used in the Metric. Following equations are relevant: alpha = J / Mc a = Jc / GM**2 alpha = GMa / c**2 where, ‘a’ is the dimensionless Spin Parameter (0 <= a <= 1)

Parameters:
Returns:

Rotational Length Parameter

Return type:

float

Raises:

ValueError – If a is not between 0 and 1

singularities()[source]

Returns the Singularities of the Metric Depends on the choice of Coordinate Systems Applies to Kerr and Kerr-Newman Geometries

Returns:

Dictionary of singularities in the geometry { "inner_ergosphere": function(theta), "inner_horizon": float, "outer_horizon": float, "outer_ergosphere": function(theta) }

Return type:

dict

Raises:

CoordinateError – If einsteinpy.metric.* does not have the metric in the coordinate system, the metric object has been instantiated with

metric_covariant(x_vec)[source]

Returns Covariant Metric Tensor Adds Kerr-Schild (Linear) Perturbation to metric, if perturbation is defined in Metric object Currently, this does not consider Gauge Fixing or any physical checks for the perturbation matrix. Please exercise caution while using perturbation.

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Metric Tensor Numpy array of shape (4,4)

Return type:

ndarray

metric_contravariant(x_vec)[source]

Returns Contravariant Metric Tensor Adds Kerr-Schild (Linear) Perturbation to metric, if perturbation is not None in Metric object Currently, this does not consider Gauge Fixing or any physical checks for the perturbation matrix. Please exercise caution while using perturbation.

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Contravariant Metric Tensor

Return type:

ndarray

calculate_trajectory(start_lambda=0.0, end_lambda=10.0, stop_on_singularity=True, OdeMethodKwargs={'stepsize': 0.001}, return_cartesian=False)[source]

Deprecated in 0.4.0. Please use einsteinpy.Geodesic.

Calculate trajectory in manifold according to geodesic equation

schwarzschild module

This module contains the class, defining Schwarzschild Spacetime:

class einsteinpy.metric.schwarzschild.Schwarzschild(coords, M)[source]

Bases: BaseMetric

Class for defining Schwarzschild Geometry

Constructor

Parameters:
  • coords (*) – Coordinate system, in which Metric is to be represented

  • M (Quantity) – Mass of gravitating body, e.g. Black Hole

metric_covariant(x_vec)[source]

Returns Covariant Schwarzschild Metric Tensor in chosen Coordinates

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Schwarzschild Metric Tensor in chosen Coordinates Numpy array of shape (4,4)

Return type:

ndarray

kerr module

This module contains the class, defining Kerr Spacetime:

class einsteinpy.metric.kerr.Kerr(coords, M, a)[source]

Bases: BaseMetric

Class for defining the Kerr Geometry

Constructor

Parameters:
  • coords (*) – Coordinate system, in which Metric is to be represented

  • M (Quantity) – Mass of gravitating body, e.g. Black Hole

  • a (Quantity) – Spin Parameter

metric_covariant(x_vec)[source]

Returns Covariant Kerr Metric Tensor in chosen Coordinates

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Kerr Metric Tensor in chosen Coordinates Numpy array of shape (4,4)

Return type:

ndarray

Raises:

CoordinateError – Raised, if the metric is not available in the supplied Coordinate System

static nonzero_christoffels()[source]

Returns a list of tuples consisting of indices of non-zero Christoffel Symbols in Kerr Metric, computed in real-time

Returns:

List of tuples Each tuple (i,j,k) represents Christoffel Symbols, with i as upper index and j, k as lower indices.

Return type:

list

kerr-newman module

This module contains the class, defining Kerr-Newman Spacetime:

class einsteinpy.metric.kerrnewman.KerrNewman(coords, M, a, Q, q=<Quantity 0. C / kg>)[source]

Bases: BaseMetric

Class for defining Kerr-Newman Goemetry

Constructor

Parameters:
  • coords (*) – Coordinate system, in which Metric is to be represented

  • M (Quantity) – Mass of gravitating body, e.g. Black Hole

  • a (Quantity) – Spin Parameter

  • Q (Quantity) – Charge on gravitating body, e.g. Black Hole

  • q (Quantity, optional) – Charge, per unit mass, of the test particle Defaults to 0 C / kg

metric_covariant(x_vec)[source]

Returns Covariant Kerr-Newman Metric Tensor in chosen Coordinates

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Kerr-Newman Metric Tensor in chosen Coordinates Numpy array of shape (4,4)

Return type:

ndarray

Raises:

CoordinateError – Raised, if the metric is not available in the supplied Coordinate System

em_potential_covariant(x_vec)[source]

Returns Covariant Electromagnetic 4-Potential Specific to Kerr-Newman Geometries

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Electromagnetic 4-Potential Numpy array of shape (4,)

Return type:

ndarray

em_potential_contravariant(x_vec)[source]

Returns Contravariant Electromagnetic 4-Potential Specific to Kerr-Newman Geometries

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Contravariant Electromagnetic 4-Potential Numpy array of shape (4,)

Return type:

ndarray

em_tensor_covariant(x_vec)[source]

Returns Covariant Electromagnetic Tensor Specific to Kerr-Newman Geometries

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Covariant Electromagnetic Tensor Numpy array of shape (4, 4)

Return type:

ndarray

em_tensor_contravariant(x_vec)[source]

Returns Contravariant Electromagnetic Tensor Specific to Kerr-Newman Geometries

Parameters:

x_vec (array_like) – Position 4-Vector

Returns:

Contravariant Electromagnetic Tensor Numpy array of shape (4, 4)

Return type:

ndarray

Symbolic Relativity Module

This module contains the classes for performing symbolic calculations related to General Relativity.

Predefined Metrics

This module contains various pre-defined space-time metrics in General Relativity.

All Available Metrics

All the currently available pre-defined metrics are listed here.

Minkowski Space-Time
einsteinpy.symbolic.predefined.minkowski.MinkowskiCartesian(c=c)[source]

Minkowski(flat) space-time in Cartesian coordinates. Space-time without any curvature or matter.

Parameters:

c (Basic or int or float) – Any value to assign to speed of light. Defaults to ‘c’.

einsteinpy.symbolic.predefined.minkowski.Minkowski(c=c)

Minkowski(flat) space-time in Cartesian coordinates. Space-time without any curvature or matter.

Parameters:

c (Basic or int or float) – Any value to assign to speed of light. Defaults to ‘c’.

einsteinpy.symbolic.predefined.minkowski.MinkowskiPolar(c=c)[source]

Minkowski(flat) space-time in Polar coordinates. Space-time without any curvature or matter.

Parameters:

c (Basic or int or float) – Any value to assign to speed of light. Defaults to ‘c’.

Vacuum Solutions
einsteinpy.symbolic.predefined.vacuum_solutions.Schwarzschild(c=c, sch=r_s)[source]

Schwarzschild exterior metric in curvature coordinates Schwarzschild, Sitz. Preuss. Akad. Wiss., p189, (1916) Stephani (13.19) p157

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to c.

  • sch (Basic or int or float) – Any value to assign to Schwarzschild Radius of the central object. Defaults to r_s.

einsteinpy.symbolic.predefined.vacuum_solutions.Kerr(c=c, sch=r_s, a=a)[source]

Kerr Metric in Boyer Lindquist coordinates.

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to c.

  • sch (Basic or int or float) – Any value to assign to Schwarzschild Radius of the central object. Defaults to r_s.

  • a (Basic or int or float) – Spin factor of the heavy body. Usually, given by J/(Mc), where J is the angular momentum. Defaults to a.

einsteinpy.symbolic.predefined.vacuum_solutions.KerrNewman(c=c, G=G, eps_0=eps_0, sch=r_s, a=a, Q=Q)[source]

Kerr-Newman Metric in Boyer Lindquist coordinates.

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to c.

  • G (Basic or int or float) – Any value to assign to the Newton’s (or gravitational) constant. Defaults to G.

  • eps_0 (Basic or int or float) – Any value to assign to the electric constant or permittivity of free space. Defaults to eps_0.

  • sch (Basic or int or float) – Any value to assign to Schwarzschild Radius of the central object. Defaults to r_s.

  • a (Basic or int or float) – Spin factor of the heavy body. Usually, given by J/(Mc), where J is the angular momentum. Defaults to a.

  • Q (Basic or int or float) – Any value to assign to eletric charge of the central object. Defaults to Q.

einsteinpy.symbolic.predefined.vacuum_solutions.ReissnerNordstorm(c=c, G=G, eps_0=eps_0, sch=r_s, Q=Q)[source]

The Reissner-Nordström metric in spherical coordinates A static solution to the Einstein-Maxwell field equations, which corresponds to the gravitational field of a charged, non-rotating, spherically symmetric body of mass M.

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to c.

  • G (Basic or int or float) – Any value to assign to the Newton’s (or gravitational) constant. Defaults to G.

  • eps_0 (Basic or int or float) – Any value to assign to the electric constant or permittivity of free space. Defaults to eps_0.

  • sch (Basic or int or float) – Any value to assign to Schwarzschild Radius of the central object. Defaults to r_s.

  • Q (Basic or int or float) – Any value to assign to eletric charge of the central object. Defaults to Q.

De Sitter and Anti De Sitter

This module contains pre-defined functions to obtain instances of various forms of Anti-De-Sitter and De-Sitter space-times.

einsteinpy.symbolic.predefined.de_sitter.AntiDeSitter()[source]

Anti-de Sitter space

Hawking and Ellis (5.9) p131

einsteinpy.symbolic.predefined.de_sitter.AntiDeSitterStatic()[source]

Static form of Anti-de Sitter space

Hawking and Ellis (5.9) p131

einsteinpy.symbolic.predefined.de_sitter.DeSitter()[source]

de Sitter space

Hawking and Ellis p125

C-Metric
einsteinpy.symbolic.predefined.cmetric.CMetric()[source]

The C-metric Stephani (Table 16.2) p188

Godel
einsteinpy.symbolic.predefined.godel.Godel()[source]

Godel metric Rev. Mod. Phys., v21, p447, (1949) Stephani (10.25) 122

Davidson
einsteinpy.symbolic.predefined.davidson.Davidson()[source]

Davidson’s cylindrically symmetric radiation perfect fluid universe Davidson, J. Math. Phys., v32, p1560, (1991)

Bessel Gravitational Wave
einsteinpy.symbolic.predefined.bessel_gravitational_wave.BesselGravitationalWave(C=C)[source]

Exact gravitational wave solution without diffraction. Class. Quantum Grav., 16:L75-78, 1999. D. Kramer.

An exact solution describing an axisymmetric gravitational wave propagating in the z-direction in closed form. This solution to Einstein’s vacuum field equations has the remarkable property that the curvature invariants decrease monotonically with increasing radial distance from the axis and vanish at infinity. The solution is regular at the symmetry axis.

Parameters:

C (Basic or int or float) – Constant for Bessel metric, the choice of the constant is not really relavent for details see the paper. Defaults to ‘C’.

Barriola Vilekin
einsteinpy.symbolic.predefined.barriola_vilenkin.BarriolaVilekin(c=c, k=k)[source]

Barriola-Vilekin monopol metric Phys. Rev. Lett. 63, 341 Manuel Barriola and Alexander Vilenkin Published 24 July 1989

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to ‘c’.

  • k (Basic or int or float) – The scaling factor responsible for the deficit/surplus angle Defaults to k.

Bertotti Kasner
einsteinpy.symbolic.predefined.bertotti_kasner.BertottiKasner(c=c, k=k, lambd=l)[source]

Birkhoff’s theorem with Λ-term and Bertotti-Kasner space Phys. Lett. A, 245:363-365, 1998 W. Rindler

Parameters:
  • c (Basic or int or float) – Any value to assign to speed of light. Defaults to ‘c’.

  • lambd (Basic or int or float) – The cosmological constant, note it must be postive. Defaults to l.

Ernst
einsteinpy.symbolic.predefined.ernst.Ernst(B=B, M=M)[source]

Black holes in a magnetic universe. J. Math. Phys., 17:54-56, 1976. Frederick J. Ernst.

Parameters:
  • M (Basic or int or float) – Mass of the black hole. Defaults to M.

  • B (Basic or int or float) – The magnetic field strength Defaults to B.

Janis Newman Winicour
einsteinpy.symbolic.predefined.janis_newman_winicour.JanisNewmanWinicour(c=c, G=G, gam=gam, M=M)[source]

Reality of the Schwarzschild singularity. Phys. Rev. Lett., 20:878-880, 1968. A. I. Janis, E. T. Newman, and J. Winicour.

Parameters:
  • M (Basic or int or float) – Mass parameter, this is used for defining the schwarzschild metric. Defaults to M.

  • gam (Basic or int or float) – Parameter for scaling Schwarzschild radius, for gamma=1 this will return the Schwarzschild metric Defaults to gam.

find

This module contains the function find to search for list of possible metrics.

einsteinpy.symbolic.predefined.find.find(search_string)[source]

Performs a find operation on available functions.

Parameters:

search_string (str) – Name of the function to be searched.

Returns:

A list of available functions related to search_string.

Return type:

list

Helper Function and Classes
einsteinpy.symbolic.helpers.simplify_sympy_array(arr)[source]

Function to simplify sympy expression or array.

This function is explicitely defined as native simplify function within sympy stopped working with sympy version change.

Parameters:

arr (NDimArray or Expr) – Any sympy array or expression.

Returns:

Simplified sympy array or expression.

Return type:

sympy.tensor.array.ndim_array.NDimArray or Expr

einsteinpy.symbolic.helpers.sympy_to_np_array(arr)[source]

Function to convert sympy to numpy array

Parameters:

arr (NDimArray) – Sympy Array

Returns:

Numpy Array

Return type:

ndarray

class einsteinpy.symbolic.helpers.TransformationMatrix(iterable, old_coords, new_coords, shape=None, old2new=None, new2old=None, **kwargs)[source]

Bases: ImmutableDenseNDimArray

Class for defining transformation matrix for basis change of vectors and tensors.

Constructor.

Parameters:
  • iterable (iterable-object) – 2D list or array to pass a matrix.

  • old_coords (list or tuple) – list of old coordinates. For example, [x, y].

  • new_coords (list or tuple) – list of new coordinates. For example, [r, theta].

  • shape (tuple, optional) – shape of the transformation matrix. Usually, not required. Defaults to None.

  • old2new (list or tuple, optional) – List of expressions for new coordinates in terms of old coordinates. For example, [x**2+y**2, atan2(y, x)].

  • new2old (list or tuple, optional) – List of expressions for old coordinates in terms of new coordinates. For example, [r*cos(theta), r*sin(theta)].

Raises:

ValueError – Raised when tensor has a rank not equal to 2. This is because, a matrix is expected.

classmethod from_new2old(old_coords, new_coords, new2old, **kwargs)[source]

Classmethod to obtain transformation matrix from old coordinates expressed as a function of new coordinates.

Parameters:
  • old_coords (list or tuple) – list of old coordinates. For example, [x, y].

  • new_coords (list or tuple) – list of new coordinates. For example, [r, theta].

  • new2old (list or tuple, optional) – List of expressions for old coordinates in terms of new coordinates. For example, [r*cos(theta), r*sin(theta)].

inv()[source]

Returns inverse of the transformation matrix

Returns:

Inverse of the matrix.

Return type:

NDimArray

Symbolic Constants Module

This module contains common constants used in physics/relativity and classes used to define them:

class einsteinpy.symbolic.constants.SymbolicConstant(name, descriptive_name=None, **assumptions)[source]

Bases: Symbol

This class inherits from ~sympy.core.symbol.Symbol

Constructor and Initializer

Parameters:
  • name (str) – Short, commonly accepted name of the constant. For example, ‘c’ for Speed of light.

  • descriptive_name (str) – The extended name of the constant. For example, ‘Speed of Light’ for ‘c’. Defaults to None.

property descriptive_name

Returns the extended name of the constant

einsteinpy.symbolic.constants.get_constant(name)[source]

Returns a symbolic instance of the constant

Parameters:

name (str) – Name of the constant. Currently available names are ‘c’, ‘G’, ‘Cosmo_Const’, ‘eps_0’.

Returns:

An instance of the required constant

Return type:

SymbolicConstant

Tensor Module

This module contains Tensor class which serves as the base class for more specific Tensors in General Relativity:

einsteinpy.symbolic.tensor.tensor_product(tensor1, tensor2, i=None, j=None)[source]

Tensor Product of tensor1 and tensor2

Parameters:
  • tensor1 (BaseRelativityTensor) –

  • tensor2 (BaseRelativityTensor) –

  • i (int, optional) – contract i``th index of ``tensor1

  • j (int, optional) – contract j``th index of ``tensor2

Returns:

tensor of appropriate rank

Return type:

BaseRelativityTensor

Raises:

ValueError – Raised when i and j both indicate ‘u’ or ‘l’ indices

class einsteinpy.symbolic.tensor.Tensor(arr, config='ll', name=None)[source]

Bases: object

Base Class for Tensor manipulation

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array, multi-dimensional list containing Sympy Expressions, or Sympy Expressions or int or float scalar

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • name (str or None) – Name of the tensor.

Raises:
  • TypeError – Raised when arr is not a list or sympy array

  • TypeError – Raised when config is not of type str or contains characters other than ‘l’ or ‘u’

  • ValueError – Raised when config implies order of Tensor different than that indicated by shape of arr

property order

Returns the order of the Tensor

property config

Returns the configuration of covariant and contravariant indices

tensor()[source]

Returns the sympy Array

Returns:

Sympy Array object

Return type:

ImmutableDenseNDimArray

subs(*args)[source]

Substitute the variables/expressions in a Tensor with other sympy variables/expressions.

Parameters:

args (one argument or two argument) –

  • two arguments, e.g foo.subs(old, new)

  • one iterable argument, e.g foo.subs([(old1, new1), (old2, new2)]) for multiple substitutions at once.

Returns:

Tensor with substituted values

Return type:

Tensor

simplify(set_self=True)[source]

Returns a simplified Tensor

Parameters:

set_self (bool) – Replaces the tensor contained the class with its simplified version, if True. Defaults to True.

Returns:

Simplified Tensor

Return type:

Tensor

class einsteinpy.symbolic.tensor.BaseRelativityTensor(arr, syms, config='ll', parent_metric=None, variables=[], functions=[], name='GenericTensor')[source]

Bases: Tensor

Generic class for defining tensors in General Relativity. This would act as a base class for other Tensorial quantities in GR.

arr

Raw Tensor in sympy array

Type:

ImmutableDenseNDimArray

syms

List of symbols denoting space and time axis

Type:

list or tuple

dims

dimension of the space-time.

Type:

int

variables

free variables in the tensor expression other than the variables describing space-time axis.

Type:

list

functions

Undefined functions in the tensor expression.

Type:

list

name

Name of the tensor. Defaults to “GenericTensor”.

Type:

str or None

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – List of crucial symbols dentoting time-axis and/or spacial axis. For example, in case of 4D space-time, the arrangement would look like [t, x1, x2, x3].

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • parent_metric (MetricTensor or None) – Metric Tensor for some particular space-time which is associated with this Tensor.

  • variables (tuple or list or set) – List of symbols used in expressing the tensor, other than symbols associated with denoting the space-time axis. Calculates in real-time if left blank.

  • functions (tuple or list or set) – List of symbolic functions used in epressing the tensor. Calculates in real-time if left blank.

  • name (str or None) – Name of the Tensor. Defaults to “GenericTensor”.

Raises:
  • TypeError – Raised when arr is not a list, sympy array or numpy array.

  • TypeError – Raised when config is not of type str or contains characters other than ‘l’ or ‘u’

  • TypeError – Raised when arguments syms, variables, functions have data type other than list, tuple or set.

  • TypeError – Raised when argument parent_metric does not belong to MetricTensor class and isn’t None.

  • ValueError – Raised when argument syms does not agree with shape of argument arr

property parent_metric

Returns the Metric from which Tensor was derived/associated, if available.

symbols()[source]

Returns the symbols used for defining the time & spacial axis

Returns:

tuple containing (t,x1,x2,x3) in case of 4D space-time

Return type:

tuple

tensor_lambdify(*args)[source]

Returns lambdified function of symbolic tensors. This means that the returned functions can accept numerical values and return numerical quantities.

Parameters:

*args – The variable number of arguments accept sympy symbols. The returned function accepts arguments in same order as initially defined in *args. Uses sympy symbols from class attributes syms and variables (in the same order) if no *args is passed Leaving *args empty is recommended.

Returns:

  • tuple – arguments to be passed in the returned function in exact order.

  • function – Lambdified function which accepts and returns numerical quantities.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor(or vector)

Return type:

BaseRelativityTensor

Vector module

This module contains the class GenericVector to represent a vector in arbitrary space-time symbolically

class einsteinpy.symbolic.vector.GenericVector(arr, syms, config='u', parent_metric=None, name='GenericVector')[source]

Bases: BaseRelativityTensor

Class to represent a vector in arbitrary space-time symbolically

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray) – Sympy Array containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘u’.

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Generic Vector. Defaults to None.

  • name (str) – Name of the Vector. Defaults to “GenericVector”.

Raises:
change_config(newconfig='u', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘u’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Defaults to None.

Returns:

New tensor with new configuration.

Return type:

GenericVector

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the vector.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed vector

Return type:

GenericVector

Metric Tensor Module

This module contains the class for defining a Metric of an arbitrary spacetime, symbolically. Note that, only the coordinate symbols are to be supplied to the syms parameter, while arr takes the metric (as a SymPy array), which may contain several constants. The symbols in syms define the basis to perform several operations on the metric, such as symbolic differentiation. Symbols, for the constants in the metric, should be defined independently and used directly in the specification of arr. Please check the metric definitions in einsteinpy.symbolic.predefined for examples of doing this.

class einsteinpy.symbolic.metric.MetricTensor(arr, syms, config='ll', name='GenericMetricTensor')[source]

Bases: BaseRelativityTensor

Class to define a metric tensor for a space-time

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • name (str) – Name of the Metric Tensor. Defaults to “GenericMetricTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 2 indices

change_config(newconfig='uu')[source]

Changes the index configuration(contravariant/covariant)

Parameters:

newconfig (str) – Specify the new configuration. Defaults to ‘uu’

Returns:

New Metric with new configuration. Defaults to ‘uu’

Return type:

MetricTensor

Raises:

ValueError – Raised when new configuration is not ‘ll’ or ‘uu’. This constraint is in place because we are dealing with Metric Tensor.

inv()[source]

Returns the inverse of the Metric. Returns contravariant Metric if it is originally covariant or vice-versa.

Returns:

New Metric which is the inverse of original Metric.

Return type:

MetricTensor

lower_config()[source]

Returns a covariant instance of the given metric tensor.

Returns:

same instance if the configuration is already lower or inverse of given metric if configuration is upper

Return type:

MetricTensor

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

MetricTensor

Christoffel Symbols Module

This module contains the class for obtaining Christoffel Symbols related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.christoffel.ChristoffelSymbols(arr, syms, config='ull', parent_metric=None, name='ChristoffelSymbols')[source]

Bases: BaseRelativityTensor

Class for defining christoffel symbols.

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ull’.

  • parent_metric (MetricTensor) – Metric Tensor from which Christoffel symbol is calculated. Defaults to None.

  • name (str) – Name of the Christoffel Symbols Tensor. Defaults to “ChristoffelSymbols”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 3 indices

classmethod from_metric(metric)[source]

Get Christoffel symbols calculated from a metric tensor

Parameters:

metric (MetricTensor) – Space-time Metric from which Christoffel Symbols are to be calculated

change_config(newconfig='lll', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘lll’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if not initialized with ‘from_metric’. Defaults to None.

Returns:

New tensor with new configuration. Defaults to ‘lll’

Return type:

ChristoffelSymbols

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

ChristoffelSymbols

Riemann Tensor Module

This module contains the class for obtaining Riemann Curvature Tensor related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.riemann.RiemannCurvatureTensor(arr, syms, config='ulll', parent_metric=None, name='RiemannCurvatureTensor')[source]

Bases: BaseRelativityTensor

Class for defining Riemann Curvature Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ulll’.

  • parent_metric (MetricTensor) – Metric Tensor related to this Riemann Curvature Tensor.

  • name (str) – Name of the Tensor. Defaults to “RiemannCurvatureTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 4 indices

classmethod from_christoffels(chris, parent_metric=None)[source]

Get Riemann Tensor calculated from Christoffel Symbols. Reimann Tensor is given as:

\[R^{t}{}_{s r n}=\Gamma^{t}{}_{s n, r} - \Gamma^{t }{}_{s r, n } + \Gamma^{p}{}_{s n}\Gamma^{t}{}_{p r} - \Gamma^{p}{}_{s r}\Gamma^{t}{}_{p n}\]
Parameters:
  • chris (ChristoffelSymbols) – Christoffel Symbols from which Riemann Curvature Tensor to be calculated

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Riemann Tensor. None if it should inherit the Parent Metric of Christoffel Symbols. Defaults to None.

classmethod from_metric(metric)[source]

Get Riemann Tensor calculated from a Metric Tensor

Parameters:

metric (MetricTensor) – Metric Tensor from which Riemann Curvature Tensor to be calculated

change_config(newconfig='llll', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘llll’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if not initialized with ‘from_metric’. Defaults to None.

Returns:

New tensor with new configuration. Configuration defaults to ‘llll’

Return type:

RiemannCurvatureTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

RiemannCurvatureTensor

Ricci Module

This module contains the basic classes for obtaining Ricci Tensor and Ricci Scalar related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.ricci.RicciTensor(arr, syms, config='ll', parent_metric=None, name='RicciTensor')[source]

Bases: BaseRelativityTensor

Class for defining Ricci Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Tensor. Defaults to None.

  • name (str) – Name of the Tensor. Defaults to “RicciTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 2 indices

classmethod from_riemann(riemann, parent_metric=None)[source]

Get Ricci Tensor calculated from Riemann Tensor

Parameters:
  • riemann (RiemannCurvatureTensor) – Riemann Tensor

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Tensor. None if it should inherit the Parent Metric of Riemann Tensor. Defaults to None.

classmethod from_christoffels(chris, parent_metric=None)[source]

Get Ricci Tensor calculated from Christoffel Tensor

Parameters:
  • chris (ChristoffelSymbols) – Christoffel Tensor

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Tensor. None if it should inherit the Parent Metric of Christoffel Symbols. Defaults to None.

classmethod from_metric(metric)[source]

Get Ricci Tensor calculated from Metric Tensor

Parameters:

metric (MetricTensor) – Metric Tensor

change_config(newconfig='ul', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘ul’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if somehow does not have a parent metric. Defaults to None.

Returns:

New tensor with new configuration. Defaults to ‘ul’

Return type:

RicciTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

RicciTensor

class einsteinpy.symbolic.ricci.RicciScalar(arr, syms, parent_metric=None)[source]

Bases: BaseRelativityTensor

Class for defining Ricci Scalar

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array, multi-dimensional list containing Sympy Expressions, or Sympy Expressions or int or float scalar

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Scalar. Defaults to None.

Raises:

TypeError – Raised when syms is not a list or tuple

property expr

Retuns the symbolic expression of the Ricci Scalar

classmethod from_riccitensor(riccitensor, parent_metric=None)[source]

Get Ricci Scalar calculated from Ricci Tensor

Parameters:
  • riccitensor (RicciTensor) – Ricci Tensor

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Scalar. Defaults to None.

classmethod from_riemann(riemann, parent_metric=None)[source]

Get Ricci Scalar calculated from Riemann Tensor

Parameters:
classmethod from_christoffels(chris, parent_metric=None)[source]

Get Ricci Scalar calculated from Christoffel Tensor

Parameters:
  • chris (ChristoffelSymbols) – Christoffel Tensor

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Ricci Scalar. Defaults to None.

classmethod from_metric(metric)[source]

Get Ricci Scalar calculated from Metric Tensor

Parameters:

metric (MetricTensor) – Metric Tensor

Einstein Tensor Module

This module contains the class for obtaining Einstein Tensor related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.einstein.EinsteinTensor(arr, syms, config='ll', parent_metric=None, name='EinsteinTensor')[source]

Bases: BaseRelativityTensor

Class for defining Einstein Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Einstein Tensor. Defaults to None.

  • name (str) – Name of the Tensor. Defaults to “EinsteinTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 2 indices

change_config(newconfig='ul', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘ul’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if somehow does not have a parent metric. Defaults to None.

Returns:

New tensor with new configuration. Defaults to ‘ul’

Return type:

EinsteinTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

EinsteinTensor

Stress Energy Momentum Tensor Module

This module contains the class for obtaining Stress Energy Momentum Tensor related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.stress_energy_momentum.StressEnergyMomentumTensor(arr, syms, config='ll', parent_metric=None, name='StressEnergyMomentumTensor')[source]

Bases: BaseRelativityTensor

Class for defining Stress-Energy Coefficient Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • parent_metric (MetricTensor or None) – Corresponding Metric for the Stress-Energy Coefficient Tensor. Defaults to None.

  • name (str) – Name of the Tensor. Defaults to “StressEnergyMomentumTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 2 indices

change_config(newconfig='ul', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘ul’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if somehow does not have a parent metric. Defaults to None.

Returns:

New tensor with new configuration. Defaults to ‘ul’

Return type:

StressEnergyMomentumTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

StressEnergyMomentumTensor

Weyl Tensor Module

This module contains the class for obtaining Weyl Tensor related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.weyl.WeylTensor(arr, syms, config='ulll', parent_metric=None, name='WeylTensor')[source]

Bases: BaseRelativityTensor

Class for defining Weyl Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ulll’.

  • parent_metric (WeylTensor) – Corresponding Metric for the Weyl Tensor. Defaults to None.

  • name (str) – Name of the Tensor. Defaults to “WeylTensor”

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 4 indices

classmethod from_metric(metric)[source]

Get Weyl tensor calculated from a metric tensor

Parameters:

metric (MetricTensor) – Space-time Metric from which Christoffel Symbols are to be calculated

Raises:

ValueError – Raised when the dimension of the tensor is less than 3

change_config(newconfig='llll', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘llll’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if not initialized with ‘from_metric’. Defaults to None.

Returns:

New tensor with new configuration. Configuration defaults to ‘llll’

Return type:

WeylTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor(or vector)

Return type:

WeylTensor

Schouten Module

This module contains the basic classes for obtaining Schouten Tensor related to a Metric belonging to any arbitrary space-time symbolically:

class einsteinpy.symbolic.schouten.SchoutenTensor(arr, syms, config='ll', parent_metric=None, name='SchoutenTensor')[source]

Bases: BaseRelativityTensor

Class for defining Schouten Tensor

Constructor and Initializer

Parameters:
  • arr (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

  • syms (tuple or list) – Tuple of crucial symbols denoting time-axis, 1st, 2nd, and 3rd axis (t,x1,x2,x3)

  • config (str) – Configuration of contravariant and covariant indices in tensor. ‘u’ for upper and ‘l’ for lower indices. Defaults to ‘ll’.

  • parent_metric (MetricTensor) – Corresponding Metric for the Schouten Tensor. Defaults to None.

  • name (str) – Name of the Tensor. Defaults to “SchoutenTensor”.

Raises:
  • TypeError – Raised when arr is not a list or sympy Array

  • TypeError – syms is not a list or tuple

  • ValueError – config has more or less than 2 indices

classmethod from_metric(metric)[source]

Get Schouten tensor calculated from a metric tensor

Parameters:

metric (MetricTensor) – Space-time Metric from which Christoffel Symbols are to be calculated

Raises:

ValueError – Raised when the dimension of the tensor is less than 3

change_config(newconfig='ul', metric=None)[source]

Changes the index configuration(contravariant/covariant)

Parameters:
  • newconfig (str) – Specify the new configuration. Defaults to ‘ul’

  • metric (MetricTensor or None) – Parent metric tensor for changing indices. Already assumes the value of the metric tensor from which it was initialized if passed with None. Compulsory if not initialized with ‘from_metric’. Defaults to None.

Returns:

New tensor with new configuration. Configuration defaults to ‘ul’

Return type:

SchoutenTensor

Raises:

Exception – Raised when a parent metric could not be found.

lorentz_transform(transformation_matrix)[source]

Performs a Lorentz transform on the tensor.

Parameters:

transformation_matrix (ImmutableDenseNDimArray or list) – Sympy Array or multi-dimensional list containing Sympy Expressions

Returns:

lorentz transformed tensor

Return type:

SchoutenTensor

Hypersurface module

This module contains Classes to calculate and plot hypersurfaces of various geometries.

Schwarzschild Embedding Module

Class for Utility functions for Schwarzschild Embedding surface to implement gravitational lensing:

class einsteinpy.hypersurface.schwarzschildembedding.SchwarzschildEmbedding(M)[source]

Bases: object

Class for Utility functions for Schwarzschild Embedding surface to implement gravitational lensing

input_units

list of input units of M

Type:

list

units_list

customized units to handle values of M and render plots within grid range

Type:

list

r_init
Type:

m

Constructor Initialize mass and embedding initial radial coordinate in appropiate units in order to render the plots of the surface in finite grid. The initial r is taken to be just greater than schwarzschild radius but it is important to note that the embedding breaks at r < 9m/4.

Parameters:

M (kg) – Mass of the body

gradient(r)[source]

Calculate gradient of Z coordinate w.r.t r to update the value of r and thereby get value of spherical radial coordinate R.

Parameters:

r (float) – schwarzschild coordinate at which gradient is supposed to be obtained

Returns:

gradient of Z w.r.t r at the point r (passed as argument)

Return type:

float

radial_coord(r)[source]

Returns spherical radial coordinate (of the embedding) from given schwarzschild coordinate.

Parameters:

r (float) –

Returns:

spherical radial coordinate of the 3d embedding

Return type:

float

get_values(alpha)[source]

Obtain the Z coordinate values and corrosponding R values for range of r as 9m/4 < r < 9m.

Parameters:

alpha (float) – scaling factor to obtain the step size for incrementing r

Returns:

(list, list) : values of R (x_axis) and Z (y_axis)

Return type:

tuple

get_values_surface(alpha)[source]

Obtain the same values as of the get_values function but reshapes them to obtain values for all points on the solid of revolution about Z axis (as the embedding is symmetric in angular coordinates).

Parameters:

alpha (float) – scaling factor to obtain the step size for incrementing r

Returns:

(~numpy.array of X, ~numpy.array of Y, ~numpy.array of Z) values in cartesian coordinates obtained after applying solid of revolution

Return type:

tuple

Rays module

This module contains Classes to calculate and plot trajectories and other interactions of light with heavy objects.

Shadow Module

Module for calculating Shadow cast by an thin emission disk around schwarzschild spacetime.

class einsteinpy.rays.shadow.Shadow(mass, n_rays, fov, limit=0.001)[source]

Bases: object

Class for plotting the shadow of Schwarzschild Black Hole surrounded by a thin accreting emission disk as seen by a distant observer.

smoothen(points=500)[source]

Sets the interpolated values for the intensities for smoothening of the plot using ~scipy.interpolate.interp1d

Utils

This module stores the common utilities of the project, such as a DualNumber class, that defines dual numbers, used for Forward Mode Auto Differentiation.

Dual Number

This module adds support for Dual Numbers and Forward Mode Auto Differentiation.

class einsteinpy.utils.dual.DualNumber(val, deriv)[source]

Bases: object

Numbers of the form, \(a + b\epsilon\), where \(\epsilon^2 = 0\) and \(\epsilon \ne 0\). Their addition and multiplication properties make them suitable for Automatic Differentiation (AD). EinsteinPy uses AD for solving Geodesics in arbitrary spacetimes. This module is based on [1].

References

Constructor

Parameters:
  • val (float) – Value

  • deriv (float) – Directional Derivative

Scalar Factor
einsteinpy.utils.scalar_factor.scalar_factor(t, era='md', tuning_param=1.0)[source]

Acceleration of the universe in cosmological models of Robertson Walker Flat Universe.

Parameters:
  • era (string) – Can be chosen from ‘md’ (Matter Dominant), ‘rd’ (Radiation Dominant) and ‘ded’ (Dark Energy Dominant)

  • t (s) – Time for the event

  • tuning_param (float, optional) – Unit scaling factor, defaults to 1

Returns:

Value of scalar factor at time t.

Return type:

float

:raises ValueError : If era is not ‘md’ , ‘rd’, and ‘ded’.:

einsteinpy.utils.scalar_factor.scalar_factor_derivative(t, era='md', tuning_param=1.0)[source]

Derivative of acceleration of the universe in cosmological models of Robertson Walker Flat Universe.

Parameters:
  • era (string) – Can be chosen from ‘md’ (Matter Dominant), ‘rd’ (Radiation Dominant) and ‘ded’ (Dark Energy Dominant)

  • t (s) – Time for the event

  • tuning_param (float, optional) – Unit scaling factor, defaults to 1

Returns:

Value of derivative of scalar factor at time t.

Return type:

float

:raises ValueError : If era is not ‘md’ , ‘rd’, and ‘ded’.:

Exceptions module

Docstring for exceptions.py module

This module defines the BaseError class which is the base class for all custom Errors in EinsteinPy, and the CoordinateError class, which is a child class used for raising exceptions when the geometry does not support the supplied coordinate system.

exception einsteinpy.utils.exceptions.BaseError(*args, **kwargs)[source]

Base class for custom errors

Constructor
Joins args into a message string
Parameters:
  • *args (iterable) – Other arguments

  • **kwargs (dict) – Keyword arguments

exception einsteinpy.utils.exceptions.CoordinateError(*args, **kwargs)[source]

Error class for invalid coordinate operations

Constructor
Joins args into a message string
Parameters:
  • *args (iterable) – Other arguments

  • **kwargs (dict) – Keyword arguments

Plotting

This module contains classes for producing static and interactive plots for geodesics, hypersurface embeddings and black hole shadows.

Plotting Geodesics

This module contains classes to produce static and interactive, 2D and 3D geodesic plots.

Core

This module allows for automatic plotting-backend switching.

class einsteinpy.plotting.geodesic.core.GeodesicPlotter(ax=None, bh_colors=('#000', '#FFC'), draw_ergosphere=True)[source]

Bases: StaticGeodesicPlotter

Class for automatically switching between Matplotlib and Plotly depending on platform used.

Constructor

Parameters:
  • ax (Axes) – Matplotlib Axes object To be deprecated in Version 0.5.0 Since Version 0.4.0, StaticGeodesicPlotter automatically creates a new Axes Object. Defaults to None

  • bh_colors (tuple, optional) – 2-Tuple, containing hexcodes (Strings) for the colors, used for the Black Hole Event Horizon (Outer) and Ergosphere (Outer) Defaults to ("#000", "#FFC")

  • draw_ergosphere (bool, optional) – Whether to draw the ergosphere Defaults to True

Static Plotting

This module contains a backend for producing 2D and 3D static geodesic plots, using matplotlib.

Interactive Plotting

This module contains a backend for producing 2D and 3D interactive geodesic plots, using plotly.

Hypersurface plotting module

This module contains the hypersurface plotting.

class einsteinpy.plotting.hypersurface.core.HypersurfacePlotter(embedding, plot_type='wireframe', alpha=100)[source]

Bases: object

Class for plotting and visualising hypersurfaces

Constructor for plotter.

Parameters:
  • embedding (SchwarzschildEmbedding) – The embedding of the hypersurface.

  • plot_type (str, optional) – type of texture for the plots - wireframe / surface, defaults to ‘wireframe’

  • alpha (float, optional) – scaling factor to obtain the step size for incrementing r, defaults to 100

plot()[source]

Plots the surface thus obtained for the embedding.

show()[source]

Shows the plot.

Rays Plotting module

This module contains classes and sub-modules for light interactions with heavy bodies.

Shadow plotting module

This module contains the black hole shadow plotting class.

class einsteinpy.plotting.rays.shadow.ShadowPlotter(shadow, is_line_plot=True)[source]

Bases: object

Class for plotting and visualising shadows

Constructor for plotter.

Parameters:
  • shadow (Shadow) – The shadow object

  • is_line_plot (bool, optional) – If the plot is a line plot or a contour plot. Defaults to True.

plot()[source]

Plots the shadow.

show()[source]

Shows the plot.

Coordinates module

This module contains the classes for various coordinate systems and their position and velocity transformations.

core module

This module contains the basic classes for coordinate systems and their position transformation:

class einsteinpy.coordinates.core.Cartesian(t, x, y, z)[source]

Bases: CartesianConversion

Class for defining 3-Position & 4-Position in Cartesian Coordinates using SI units

Constructor

Parameters:
  • t (float) – Time

  • x (float) – x-Component of 3-Position

  • y (float) – y-Component of 3-Position

  • z (float) – z-Component of 3-Position

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

to_spherical(**kwargs)[source]

Method for conversion to Spherical Polar Coordinates

Parameters:

**kwargs (dict) – Keyword Arguments

Returns:

Spherical representation of the Cartesian Coordinates

Return type:

Spherical

to_bl(**kwargs)[source]

Method for conversion to Boyer-Lindquist (BL) Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of gravitating body Required to calculate alpha, the rotational length parameter

  • a (float) – Spin Parameter of gravitating body 0 <= a <= 1 Required to calculate alpha, the rotational length parameter

Returns:

Boyer-Lindquist representation of the Cartesian Coordinates

Return type:

BoyerLindquist

class einsteinpy.coordinates.core.Spherical(t, r, theta, phi)[source]

Bases: SphericalConversion

Class for defining 3-Position & 4-Position in Spherical Polar Coordinates using SI units

Constructor

Parameters:
  • t (float) – Time

  • r (float) – r-Component of 3-Position

  • theta (float) – theta-Component of 3-Position

  • phi (float) – phi-Component of 3-Position

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

to_cartesian(**kwargs)[source]

Method for conversion to Cartesian Coordinates

Parameters:

**kwargs (dict) – Keyword Arguments

Returns:

Cartesian representation of the Spherical Polar Coordinates

Return type:

Cartesian

to_bl(**kwargs)[source]

Method for conversion to Boyer-Lindquist (BL) Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of gravitating body Required to calculate alpha, the rotational length parameter

  • a (float) – Spin Parameter of gravitating body 0 <= a <= 1 Required to calculate alpha, the rotational length parameter

Returns:

Boyer-Lindquist representation of the Spherical Polar Coordinates

Return type:

BoyerLindquist

class einsteinpy.coordinates.core.BoyerLindquist(t, r, theta, phi)[source]

Bases: BoyerLindquistConversion

Class for defining 3-Position & 4-Position in Boyer-Lindquist Coordinates using SI units

Constructor

Parameters:
  • t (float) – Time

  • r (float) – r-Component of 3-Position

  • theta (float) – theta-Component of 3-Position

  • phi (float) – phi-Component of 3-Position

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

to_cartesian(**kwargs)[source]

Method for conversion to Cartesian Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of gravitating body Required to calculate alpha, the rotational length parameter

  • a (float) – Spin Parameter of gravitating body 0 <= a <= 1 Required to calculate alpha, the rotational length parameter

Returns:

Cartesian representation of the Boyer-Lindquist Coordinates

Return type:

Cartesian

to_spherical(**kwargs)[source]

Method for conversion to Spherical Polar Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of gravitating body Required to calculate alpha, the rotational length parameter

  • a (float) – Spin Parameter of gravitating body 0 <= a <= 1 Required to calculate alpha, the rotational length parameter

Returns:

Spherical Polar representation of the Boyer-Lindquist Coordinates

Return type:

Spherical

differential module

This module contains the basic classes for time differentials of coordinate systems and the transformations:

class einsteinpy.coordinates.differential.CartesianDifferential(t, x, y, z, v_x, v_y, v_z)[source]

Bases: CartesianConversion

Class for defining 3-Velocity & 4-Velocity in Cartesian Coordinates using SI units

Constructor

Parameters:
  • t (Quantity) – Time

  • x (Quantity) – x-Component of 3-Position

  • y (Quantity) – y-Component of 3-Position

  • z (Quantity) – z-Component of 3-Position

  • v_x (Quantity, optional) – x-Component of 3-Velocity

  • v_y (Quantity, optional) – y-Component of 3-Velocity

  • v_z (Quantity, optional) – z-Component of 3-Velocity

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

property v_t

Returns the Timelike component of 4-Velocity

velocity(metric)[source]

Returns Velocity 4-Vector in SI units

Parameters:

metric (*) – Metric object, in which the coordinates are defined

Returns:

4-Tuple, containing Velocity 4-Vector in SI units

Return type:

tuple

spherical_differential(**kwargs)[source]

Converts to Spherical Polar Coordinates

Parameters:

**kwargs (dict) – Keyword Arguments

Returns:

Spherical Polar representation of velocity

Return type:

SphericalDifferential

bl_differential(**kwargs)[source]

Converts to Boyer-Lindquist Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of the gravitating body, around which, spacetime has been defined

  • a (float) – Spin Parameter of the gravitating body, around which, spacetime has been defined

Returns:

Boyer-Lindquist representation of velocity

Return type:

BoyerLindquistDifferential

class einsteinpy.coordinates.differential.SphericalDifferential(t, r, theta, phi, v_r, v_th, v_p)[source]

Bases: SphericalConversion

Class for defining 3-Velocity & 4-Velocity in Spherical Polar Coordinates using SI units

Constructor

Parameters:
  • t (float) – Time

  • r (float) – r-Component of 3-Position

  • theta (float) – theta-Component of 3-Position

  • phi (float) – phi-Component of 3-Position

  • v_r (float, optional) – r-Component of 3-Velocity

  • v_th (float, optional) – theta-Component of 3-Velocity

  • v_p (float, optional) – phi-Component of 3-Velocity

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

property v_t

Returns the Timelike component of 4-Velocity

velocity(metric)[source]

Returns Velocity 4-Vector in SI units

Parameters:

metric (*) – Metric object, in which the coordinates are defined

Returns:

4-Tuple, containing Velocity 4-Vector in SI units

Return type:

tuple

cartesian_differential(**kwargs)[source]

Converts to Cartesian Coordinates

Parameters:

**kwargs (dict) – Keyword Arguments

Returns:

Cartesian representation of velocity

Return type:

CartesianDifferential

bl_differential(**kwargs)[source]

Converts to Boyer-Lindquist coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of the gravitating body, around which, spacetime has been defined

  • a (float) – Spin Parameter of the gravitating body, around which, spacetime has been defined

Returns:

Boyer-Lindquist representation of velocity

Return type:

BoyerLindquistDifferential

class einsteinpy.coordinates.differential.BoyerLindquistDifferential(t, r, theta, phi, v_r, v_th, v_p)[source]

Bases: BoyerLindquistConversion

Class for defining 3-Velocity & 4-Velocity in Boyer-Lindquist Coordinates using SI units

Constructor.

Parameters:
  • t (float) – Time

  • r (float) – r-Component of 3-Position

  • theta (float) – theta-Component of 3-Position

  • phi (float) – phi-Component of 3-Position

  • v_r (float, optional) – r-Component of 3-Velocity

  • v_th (float, optional) – theta-Component of 3-Velocity

  • v_p (float, optional) – phi-Component of 3-Velocity

position()[source]

Returns Position 4-Vector in SI units

Returns:

4-Tuple, containing Position 4-Vector in SI units

Return type:

tuple

property v_t

Returns the Timelike component of 4-Velocity

velocity(metric)[source]

Returns Velocity 4-Vector in SI units

Parameters:

metric (*) – Metric object, in which the coordinates are defined

Returns:

4-Tuple, containing Velocity 4-Vector in SI units

Return type:

tuple

cartesian_differential(**kwargs)[source]

Converts to Cartesian Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of the gravitating body, around which, spacetime has been defined

  • a (float) – Spin Parameter of the gravitating body, around which, spacetime has been defined

Returns:

Cartesian representation of velocity

Return type:

CartesianDifferential

spherical_differential(**kwargs)[source]

Converts to Spherical Polar Coordinates

Parameters:
  • **kwargs (dict) – Keyword Arguments Expects two arguments, M and ``a, as described below

  • M (float) – Mass of the gravitating body, around which, spacetime has been defined

  • a (float) – Spin Parameter of the gravitating body, around which, spacetime has been defined

Returns:

Spherical representation of velocity

Return type:

SphericalDifferential

Constant module
Units module
einsteinpy.units.primitive(*args)[source]

Strips out units and returns numpy.float64 values out of astropy.units.quantity.Quantity

Parameters:

*args (iterable) – astropy.units.quantity.Quantity objects, who value is required

Returns:

primitive_args – List of numpy.float64 values, obtained from Quantity objects

Return type:

list

Bodies module

Important Bodies. Contains some predefined bodies of the Solar System: * Sun (☉) * Earth (♁) * Moon (☾) * Mercury (☿) * Venus (♀) * Mars (♂) * Jupiter (♃) * Saturn (♄) * Uranus (⛢) * Neptune (♆) * Pluto (♇) and a way to define new bodies (Body class). Data references can be found in constant

class einsteinpy.bodies.Body(name='Generic Body', mass=<Quantity 0. kg>, q=<Quantity 0. C>, R=<Quantity 0. km>, differential=None, parent=None)[source]

Bases: object

Class to create a generic Body

Parameters:
  • name (string) – Name or ID of the body

  • mass (kg) – Mass of the body

  • q (C, optional) – Charge on the body

  • R (units) – Radius of the body

  • differential (*, optional) – Complete coordinates of the body

  • parent (Body, optional) – The parent object of the body Useful in case of multibody systems

Geodesic

This module contains classes for defining Time-like & Null-like Geodesics.

Geodesic

This module defines a base Geodesic class, and then extends it to define Time-like and Null-like Geodesics.

class einsteinpy.geodesic.geodesic.Geodesic(metric, metric_params, position, momentum, time_like=True, return_cartesian=True, **kwargs)[source]

Bases: object

Base Class for defining Geodesics Working in Geometrized Units (M-Units), with \(c = G = M = k_e = 1\)

Constructor

Parameters:
  • metric (str) – Name of the metric. Currently, these metrics are supported: 1. Schwarzschild 2. Kerr 3. KerrNewman

  • metric_params (array_like) – Tuple of parameters to pass to the metric E.g., (a,) for Kerr

  • position (array_like) – 3-Position 4-Position is initialized by taking t = 0.0

  • momentum (array_like) – 3-Momentum 4-Momentum is calculated automatically, considering the value of time_like

  • time_like (bool, optional) – Determines type of Geodesic True for Time-like geodesics False for Null-like geodesics Defaults to True

  • return_cartesian (bool, optional) – Whether to return calculated positions in Cartesian Coordinates This only affects the coordinates. Momenta are dimensionless quantities, and are returned in Spherical Polar Coordinates. Defaults to True

  • kwargs (dict) – Keyword parameters for the Geodesic Integrator See ‘Other Parameters’ below.

  • steps (int) – Number of integration steps Defaults to 50

  • delta (float) – Initial integration step-size Defaults to 0.5

  • rtol (float) – Relative Tolerance Defaults to 1e-2

  • atol (float) – Absolute Tolerance Defaults to 1e-2

  • order (int) – Integration Order Defaults to 2

  • omega (float) – Coupling between Hamiltonian Flows Smaller values imply smaller integration error, but too small values can make the equation of motion non-integrable. For non-capture trajectories, omega = 1.0 is recommended. For trajectories, that either lead to a capture or a grazing geodesic, a decreased value of 0.01 or less is recommended. Defaults to 1.0

  • suppress_warnings (bool) – Whether to suppress warnings during simulation Warnings are shown for every step, where numerical errors exceed specified tolerance (controlled by rtol and atol) Defaults to False

property trajectory

Returns the trajectory of the test particle

calculate_trajectory(**kwargs)[source]

Calculate trajectory in spacetime

Parameters:
  • kwargs (dict) – Keyword parameters for the Geodesic Integrator See ‘Other Parameters’ below.

  • steps (int) – Number of integration steps Defaults to 50

  • delta (float) – Initial integration step-size Defaults to 0.5

  • rtol (float) – Relative Tolerance Defaults to 1e-2

  • atol (float) – Absolute Tolerance Defaults to 1e-2

  • order (int) – Integration Order Defaults to 2

  • omega (float) – Coupling between Hamiltonian Flows Smaller values imply smaller integration error, but too small values can make the equation of motion non-integrable. For non-capture trajectories, omega = 1.0 is recommended. For trajectories, that either lead to a capture or a grazing geodesic, a decreased value of 0.01 or less is recommended. Defaults to 1.0

  • suppress_warnings (bool) – Whether to suppress warnings during simulation Warnings are shown for every step, where numerical errors exceed specified tolerance (controlled by rtol and atol) Defaults to False

Returns:

  • ~numpy.ndarray – N-element numpy array, containing step count

  • ~numpy.ndarray – Shape-(N, 8) numpy array, containing (4-Position, 4-Momentum) for each step

class einsteinpy.geodesic.geodesic.Nulllike(metric, metric_params, position, momentum, return_cartesian=True, **kwargs)[source]

Bases: Geodesic

Class for defining Null-like Geodesics

Constructor

Parameters:
  • metric (str) – Name of the metric. Currently, these metrics are supported: 1. Schwarzschild 2. Kerr 3. KerrNewman

  • metric_params (array_like) – Tuple of parameters to pass to the metric E.g., (a,) for Kerr

  • position (array_like) – 3-Position 4-Position is initialized by taking t = 0.0

  • momentum (array_like) – 3-Momentum 4-Momentum is calculated automatically, considering the value of time_like

  • return_cartesian (bool, optional) – Whether to return calculated positions in Cartesian Coordinates This only affects the coordinates. The momenta dimensionless quantities, and are returned in Spherical Polar Coordinates. Defaults to True

  • kwargs (dict) – Keyword parameters for the Geodesic Integrator See ‘Other Parameters’ below.

  • steps (int) – Number of integration steps Defaults to 50

  • delta (float) – Initial integration step-size Defaults to 0.5

  • rtol (float) – Relative Tolerance Defaults to 1e-2

  • atol (float) – Absolute Tolerance Defaults to 1e-2

  • order (int) – Integration Order Defaults to 2

  • omega (float) – Coupling between Hamiltonian Flows Smaller values imply smaller integration error, but too small values can make the equation of motion non-integrable. For non-capture trajectories, omega = 1.0 is recommended. For trajectories, that either lead to a capture or a grazing geodesic, a decreased value of 0.01 or less is recommended. Defaults to 1.0

  • suppress_warnings (bool) – Whether to suppress warnings during simulation Warnings are shown for every step, where numerical errors exceed specified tolerance (controlled by rtol and atol) Defaults to False

class einsteinpy.geodesic.geodesic.Timelike(metric, metric_params, position, momentum, return_cartesian=True, **kwargs)[source]

Bases: Geodesic

Class for defining Time-like Geodesics

Constructor

Parameters:
  • metric (str) – Name of the metric. Currently, these metrics are supported: 1. Schwarzschild 2. Kerr 3. KerrNewman

  • metric_params (array_like) – Tuple of parameters to pass to the metric E.g., (a,) for Kerr

  • position (array_like) – 3-Position 4-Position is initialized by taking t = 0.0

  • momentum (array_like) – 3-Momentum 4-Momentum is calculated automatically, considering the value of time_like

  • return_cartesian (bool, optional) – Whether to return calculated positions in Cartesian Coordinates This only affects the coordinates. The momenta dimensionless quantities, and are returned in Spherical Polar Coordinates. Defaults to True

  • kwargs (dict) – Keyword parameters for the Geodesic Integrator See ‘Other Parameters’ below.

  • steps (int) – Number of integration steps Defaults to 50

  • delta (float) – Initial integration step-size Defaults to 0.5

  • rtol (float) – Relative Tolerance Defaults to 1e-2

  • atol (float) – Absolute Tolerance Defaults to 1e-2

  • order (int) – Integration Order Defaults to 2

  • omega (float) – Coupling between Hamiltonian Flows Smaller values imply smaller integration error, but too small values can make the equation of motion non-integrable. For non-capture trajectories, omega = 1.0 is recommended. For trajectories, that either lead to a capture or a grazing geodesic, a decreased value of 0.01 or less is recommended. Defaults to 1.0

  • suppress_warnings (bool) – Whether to suppress warnings during simulation Warnings are shown for every step, where numerical errors exceed specified tolerance (controlled by rtol and atol) Defaults to False

Examples module

This module contains examples, that showcase how the various Numerical Relativity modules in EinsteinPy come together:

einsteinpy.examples.precession()[source]

An example to showcase the usage of the various modules in einsteinpy. Here, we assume a Schwarzschild spacetime and obtain a test particle orbit, that shows apsidal precession.

Returns:

geod – Timelike Geodesic, defining test particle trajectory

Return type:

Timelike

Developer Guide

As with any open-source project, we rely on the community for implementing new ideas and fixing old bugs. You can contribute to EinsteinPy in many ways, for example, by reporting errors in code or documentation, writing new code, improving documentation, or even by writing tutorials or blog posts. If you are interested in contributing to EinsteinPy, please go through the following sections.

Contributing

For starters, we recommend checking out the “good first issue” tag on the issue tracker. Those issues should be relatively easy to fix and would require minimal knowledge about the library. However, you will need to possess some knowledge about how git works. git is a decentralized version control system that preserves codebase history, keeps track of changes and allows for collaboration. If you are new to git and version control, try following the GitHub Quickstart tutorial.

If you already know all this and would like to contribute, then that’s awesome! But before coding away, please make sure your intended addition or change is in line with the project’s scope and goals. You can do this by chatting with us on Element or Gitter, or mailing us.

All code changes & additions should be accompanied by altered or new unit-tests, so that the code coverage increases or stays the same. Automated services will ensure that your code works across the various platforms that EinsteinPy supports.

Development Pipeline

Note that EinsteinPy is a Python 3-only library. So, you need to have Python 3 installed in your system and you need to be familiar with it. Then, you can follow these steps to set up a platform-agnostic development environment and start contributing to EinsteinPy:

  1. Install git.

  2. Create an account on GitHub, if you don’t already have one.

  3. Fork EinsteinPy’s repository (einsteinpy/einsteinpy).

  4. Clone your forked repository.

  5. Create a virtual environment and activate it using the following commands:

$ python -m venv <your-venv-name>
$ source <your-venv-name>/bin/activate # Linux/macOS
$ ./<your-venv-name>/Scripts/activate # Windows

Learn more about Python virtual environments here.

  1. After activating the environment, install EinsteinPy in editable or development mode like so:

$ pip install -e ./einsteinpy/[dev]

[dev] ensures that all the dependencies required for development and testing are installed, while the -e or --editable flag ensures that any changes you make to the code take effect immediately (after you save the changes).

  1. Create and switch to a new branch like so:

$ git checkout -b <your-branch-name>

Usually, the branch name should be kept similar to the issue/topic you are working on.

  1. Make changes to the code and add unit-tests (if applicable). Ensure that the code is formatted properly. See the Code Linting & Testing section below.

  2. After you are done, commit your changes and push them to your forked repository.

  3. Finally, open a Pull Request (PR) to the main branch of the einsteinpy/einsteinpy repository. You can also request a review from specific maintainers of the project. The maintainers will review your PR and might ask you to make some changes. If there are any changes required, you can make them in the same branch and push them to your forked repository. The PR will automatically update with the new changes.

  4. When your PR is approved and ready to be merged, we will ask you to update the project CHANGELOG and if needed, we might also ask you to squash your commits.

If you are facing issues with any of the above steps, please feel free to ask for help on Element or Gitter.

Code Linting & Testing

After you push your code and open a PR to the main branch, your code will be tested automatically by the continuous integration (CI) tools. If they encounter any errors, you will be notified by CI with the details about the error, which you can use to make necessary changes to fix the error. These errors usually come in the form of code quality errors, failed tests and decreased coverage.

Code quality

Code quality is an important aspect of any software project. It ensures that the code is readable, maintainable, and bug-free. The quality of a piece of code depends on its formatting, style and complexity. To maintain consistent code formatting and style, we use black, isort and mypy. For convenience, we have set up tox, which runs all these in a single, short command:

$ cd ./einsteinpy/
$ tox -e reformat

If your PR is failing quality checks, executing the above commands should fix it. Also, to ensure that the code remains understandable and maintainable over time, we enforce Cyclomatic Complexity (CC) checks on the codebase using CodeFactor/CodeClimate. CC is a measure of the complexity of a program. The lower the CC, the easier it is to understand and maintain the code. If your PR is running into CodeFactor or CodeClimate errors, you will have to refactor your code, so that its CC is below a certain threshold. To check the CC of your code locally, you can use radon:

$ radon cc ./einsteinpy/
Unit-tests & Code coverage

Since you have made changes to the codebase, it is likely that some of the unit-tests that were previously passing will now fail. CI will alert you to these failures on your PR with the error details. You can use these details to fix the errors, commit & push the changes and make the tests pass. In case you want to debug the test errors locally, you can do so by running the following command:

$ pytest --cov-report=term-missing --cov=einsteinpy ./einsteinpy/

Note that this can take a while. If the error is isolated to only one file or a few files, you can choose to test only that or those file(s). For example, to execute all the einsteinpy.metric-related tests, you can run:

$ pytest --cov-report=term-missing --cov=einsteinpy ./einsteinpy/tests/test_metric/

This command also reports the overall code coverage after all the tests are run. Code coverage is a measure of how much of the codebase is covered by the tests. It is a good practice to have a high code coverage, so that the tests can catch any bugs that might be introduced in the codebase. We use codecov to track the code coverage of the project. You can see the current code coverage of the project here. If your PR is failing coverage checks, you will have to add more tests to increase the coverage.

Documentation

After you have implemented your bugfix or your shiny new feature, you should also add some documentation, so that users, maintainers and future contributors can understand how to use or make changes to your code. All of EinsteinPy’s non-API documentation is stored in text files under docs/source. If you think anything can be improved there, please edit the files and open a PR. The API docs comprising the docstrings of the Python code follow numpydoc guidelines. If you come across any inconsistency or opportunity for improvement, feel free to edit the docstrings and submit a PR.

We use Sphinx to generate the overall API + non-API documentation, which is then hosted here, courtesy of Read the Docs. To build the docs locally, you can run the following commands:

$ pip install Sphinx nbsphinx jupyter_sphinx
$ cd ./einsteinpy/docs/
$ sphinx-build -b html source build
$ cd ./build/
$ python -m http.server 8000 --bind 127.0.0.1

This should open the built documentation website in a web browser at http://127.0.0.1:8000. If you want hot-reloading, you can use sphinx-autobuild instead of sphinx-build, after installing it using pip install sphinx-autobuild. This will automatically rebuild the docs and refresh the browser tab whenever you make changes to the source files.

In addition to the usual documentation, the GitHub Wiki for EinsteinPy is open to everybody. Please feel free to add new content there.

After your PR is merged

Great job 🎊🎊. Your PR just got approved & merged. Now how do you ensure your local main branch is up-to-date with upstream/main? Like so:

$ git remote add upstream https://github.com/einsteinpy/einsteinpy.git # Set up upstream
$ git checkout main
$ git fetch upstream
$ git merge upstream/main
$ git branch -d <your-branch-name> # Delete your branch
$ git push origin main

And now, you are all set to create another branch and contribute further to EinsteinPy. Have fun coding 😀!

Reporting bugs or suggestions

Not only can things break at any given time, but different people also have different use cases for the project. If you find anything that doesn’t work as expected or have suggestions, please refer to the issue tracker on GitHub.

What’s New

einsteinpy 0.4.0 - 2021-05-06

This major release brings a lot of improvements to the numerical module of the project. COVID19 is proving to be very difficult for India and we are trying to cope up. Please forgive us for any issues you faced with the v0.3.1 and the documentation.

Changes
  • [#506]: Tests moved outside of the package.

  • [#510]: Added a utility function for Outer Product and Contraction of Tensors in the symbolic module.

  • [#512]: Refactored metric, utils and geodesic modules, added metric.BaseMetric class

  • [#512]: Fixed #113, Fixed cyclomatic complexity issue in metric.Schwarzschild and metric.Kerr classes

  • [#512]: Fixed #141, Refactored utils and merged most utilities into metric itself

  • [#512]: Fixed #410, Improved __str__ and __repr__ messages for Geodesic objects

  • [#512]: Fixed #507, Fixed a mathematical inaccuracy in metric.Schwarzschild class

  • [#512]: Fixed #508, Removed a stray scaling factor in metric.KerrNewman class

  • [#512]: Fixed #514, Replaced Spin Parameter with Length Parameter throughout metric module

  • [#512]: Fixed #515, Renamed “maxwell” to “em”

  • [#521]: Refactored coordinates, geodesic and metric modules, added support for 4-Vectors

  • [#521]: Fixed #517, Removed Spin Parameter from bodies

  • [#521]: Fixed #524, Fixed breakage, caused due to isort changes

  • [#521]: Partially fixed #523, Fixed Schwarzschild and Kerr

  • [#527]: Added support for Null Geodesics in Kerr & Schwarzschild Spacetimes

  • [#527]: Added new features to plotting.geodesic

  • [#527]: Dropped support for Python 3.6

  • [#547]: Fixed #516, Added __all__ across modules

  • [#547]: Fixed #552, Renamed missing attributes in einsteinpy.plotting.geodesic.static

  • [#547]: Increased test coverage for einsteinpy.ijit

  • [#551]: Fixed #526, Exceptions module added, CoordinateError class implemented

  • [#565]: Fixed #549, Updated einsteinpy.symbolic Jupyter Notebooks

  • [#548]: Fixed #36, Added support for animated Geodesic plots

  • [#548]: Fixed #40, Added support for Order 4, 6 & 8 Geodesic Integrators

  • [#548]: Fixed #105, Added support for simulating Null Geodesics in Kerr & Schwarzschild geometries

  • [#548]: Fixed #122, Schwarzschild & Kerr algorithms validated

  • [#548]: Fixed #367, Scaling issues fixed for Frame Dragging

  • [#548]: Fixed #535, Moved to a pure python geodesic solver, Julia dependency removed

  • [#548]: Minor edits to documentation for geodesic and plotting.geodesic modules

  • [#571]: Fixed #570, Updated Master to Main

  • [#573]: Fixed bug in Riemann Tensor calculation from Christoffels

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat

  • Jyotirmaya Shivottam

  • Bibek Gautam

  • Qbiwan+ (GitHub Username)

  • Aditya Prashant Dalvi+

  • Aditya Prakash+

  • aweinr4+ (GitHub Username)

einsteinpy 0.3.1 - 2021-01-16

This release is a minor patch release for fixing a minor Debian issue.

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat

einsteinpy 0.3.0 - 2020-05-05

This major release would bring some very important improvements. This release fixes a very crucial bug with sympy. Fixes coordinate conversions so they don’t fail on edge cases anymore.

EinsteinPy now uses GitHub Actions for macOS builds. Big changes to the plotting module.

The release comes for the paper of EinsteinPy. The release marks the beginning of Google Summer of Code 2020. The release also brings a new rays module, which will form the base for null geodesics in future releases.

Features
  • Loads of Predefined Metrics

  • Sympy version incompatibilities handled

  • Numba as a default installation

  • Lorentz Transform for Einstein Tensor

  • Lorentz Transform to Tensor Class

  • Hypersurface Plotting API similar to the common plotting API

  • Find Function in Predefined Metrics

  • Increased Code Coverage

  • New rays module

  • Plotting Black Hole Shadows

  • Coordinate Subscripting

  • Supports Python 3.8, dropping support fpr Python 3.5

  • numpy moveaxis replaced with sympy permutedims

  • name parameter in Metric Tensor

  • Tags to Tensor names

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat

  • Ritwik Saha

  • Manvi Gupta

  • Micky Yun Chan+

  • DylanBrdt+ (GitHub Username)

  • Vineet Gandham+

  • Pratyush Kerhalkar+

  • Bhavam Vidyarthi+

  • Khalid Shaikh+

  • Rohit Sanjay+

  • Saurabh+

  • Raahul Singh+

  • Nimesh Vashishtha+

  • Shamanth R Nayak K+

  • Arnav Das+

  • Gim Seng Ng+

  • Nihar Gupte+

  • Suyash Salampuria+

  • Atul Mangat+

  • Ganesh Tarone+

  • Shreyas Kalvankar+

  • Swastik Singh+

  • Jyotirmaya Shivottam+

  • Sitara Srinivasan+

  • Aayush Gautam+

  • Zac Yauney+

  • Gagan-Shenoy+

  • Bibek Gautam+

  • Erin Allard+

  • Suyog Garg+

einsteinpy 0.2.1 - 2019-11-02

This minor release would bring improvements and new feature additions to the already existing symbolic calculations module along with performance boosts of order of 15x.

This release concludes the SOCIS 2019 projects of Sofía Ortín Vela (ortinvela.sofia@gmail.com) and Varun Singh(varunsinghs2021@gmail.com).

Part of this release is sponsored by European Space Agency, through Summer of Code in Space (SOCIS) 2019 program.

Features
  • New tensors in symbolic module

    • Ricci Scalar

    • Weyl Tensor

    • Stress-Energy-Momentum Tensor

    • Einstein Tensor

    • Schouten Tensor

  • Improvement in performance of current tensors

  • Lambdify option for tensors

  • Support for vectors at arbitrary space-time symbolically as 1st order tensor.

  • Support for scalars at arbitrary space-time symbolically as 0th order tensor.

  • Addition of constants sub-module to symbolic module

  • Improvement in speed of Geodesic plotting

  • Move away from Jupyter and Plotly Widgets

  • New Plotting Framework

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat

  • Ritwik Saha

  • Sofía Ortín Vela

  • Varun Singh

  • Arnav Das+

  • Calvin Jay Ross+

einsteinpy 0.2.0 - 2019-07-15

This release brings a lot of new features for the EinsteinPy Users.

A better API, intuitive structure and easy coordinates handling! This major release comes before Python in Astronomy 2019 workshop and brings a lots of cool stuff.

Part of this release is sponsored by ESA/ESTEC - Adv. Concepts & Studies Office (European Space Agency), through Summer of Code in Space (SOCIS) 2019 program.

This is a short-term supported version and will be supported only until December 2019. For any feature request, write a mail to developers@einsteinpy.org describing what you need.

Features
  • Kerr Metric

  • Kerr-Newman Metric

  • Coordinates Module with Boyer Lindquist Coordinates and transformation

  • Bodies Module

  • Defining Geodesics with ease!

  • Animated plots

  • Intuitive API for plotting

  • Schwarzschild Hypersurface Embedding

  • Interactive Plotting

  • Environment-aware plotting and exceptional support for iPython Notebooks!

  • Support for Tensor Algebra in General Relativity

  • Symbolic Manipulation of Metric Tensor, Riemann Tensor and Ricci Tensor

  • Support for Index Raising and Lowering in Tensors

  • Numerical Calculation and Symbolic Manipulation of Christoffel Symbols

  • Calculations of Event Horizon and Ergosphere of Kerr Black holes!

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat

  • Ritwik Saha

  • Bhavya Bhatt

  • Sofía Ortín Vela+

  • Raphael Reyna+

  • Prithvi Manoj Krishna+

  • Manvi Gupta+

  • Divya Gupta+

  • Yash Sharma+

  • Shilpi Jain+

  • Rishi Sharma+

  • Varun Singh+

  • Alpesh Jamgade+

  • Saurabh Bansal+

  • Tanmay Rustagi+

  • Abhijeet Manhas+

  • Ankit Khandelwal+

  • Tushar Tyagi+

  • Hrishikesh Sarode

  • Naman Tayal+

  • Ratin Kumar+

  • Govind Dixit+

  • Jialin Ma+

Bugs Fixed
  • Issue #115: Coordinate Conversion had naming issues that made them confusing!

  • Issue #185: Isort had conflicts with Black

  • Issue #210: Same notebook had two different listings in Example Gallery

  • Issue #264: Removing all relative imports

  • Issue #265: New modules were lacking API Docs

  • Issue #266: The logo on documentation was not rendering

  • Issue #267: Docs were not present for Ricci Tensor and Vacuum Metrics

  • Issue #277: Coordinate Conversion in plotting module was handled incorrectly

Backwards incompatible changes
  • The old StaticGeodesicPlotter has been renamed to einsteinpy.plotting.senile.StaticGeodesicPlotter, please adjust your imports accordingly

  • The old ScatterGeodesicPlotter has been renamed to einsteinpy.plotting.senile.ScatterGeodesicPlotter, please adjust your imports accordingly.

  • einsteinpy.metric.Schwarzschild, einsteinpy.metric.Kerr, and einsteinpy.metric.KerrNewman now have different signatures for class methods, and they now explicitly support einsteinpy.coordinates coordinate objects. Check out the notebooks and their respective documentation.

  • The old coordinates conversion in einsteinpy.utils has been deprecated.

  • The old symbolic module in einsteinpy.utils has been moved to einsteinpy.symbolic.

einsteinpy 0.1.0 - 2019-03-08

This is a major first release for world’s first actively maintained python library for General Relativity and Numerical methods. This major release just comes before the Annual AstroMeet of IIT Mandi, AstraX. This will be a short term support version and will be supported only until late 2019.

Features
  • Schwarzschild Geometry Analysis and trajectory calculation

  • Symbolic Calculation of various tensors in GR

  • Christoffel Symbols

  • Riemann Curvature Tensor

  • Static Geodesic Plotting

  • Velocity of Coordinate time w.r.t proper time

  • Easy Calculation of Schwarzschild Radius

  • Coordinate conversion with unit handling

  • Spherical/Cartesian Coordinates

  • Boyer-Lindquist/Cartesian Coordinates

Contributors

This is the complete list of the people that contributed to this release, with a + sign indicating first contribution.

  • Shreyas Bapat+

  • Ritwik Saha+

  • Bhavya Bhatt+

  • Priyanshu Khandelwal+

  • Gaurav Kumar+

  • Hrishikesh Sarode+

  • Sashank Mishra+

Code of Conduct

The community of participants in EinsteinPy is made up of members from around the globe with a diverse set of skills, personalities and experiences. It is through these differences that our community experiences success and continued growth. We expect everyone in our community to follow these guidelines when interacting with others both inside and outside of our community. Our goal is to keep ours a positive, inclusive, successful and growing community.

As members of the community,

  • we pledge to treat all people with respect and provide a harassment- and bullying-free environment, regardless of sex, sexual orientation and/or gender identity, disability, physical appearance, body size, race, nationality, ethnicity, and religion. In particular, sexual language and imagery, sexist, racist, or otherwise exclusionary jokes are not appropriate.

  • we pledge to respect the work of others by recognizing acknowledgment/citation requests of original authors. As authors, we pledge to be explicit about how we want our work to be cited or acknowledged.

  • we pledge to welcome those interested in joining the community, and realize that including people with a variety of opinions and backgrounds will only serve to enrich our community. In particular, discussions relating to pros/cons of various technologies, programming languages, and so on are welcome, but these should be done with respect, taking proactive measures to ensure that all participants are heard and feel confident that they can freely express their opinions.

  • we pledge to welcome questions and answer them respectfully, paying particular attention to those new to the community. We pledge to provide respectful criticisms and feedback in forums, especially in discussion threads resulting from code contributions.

  • we pledge to be conscientious of the perceptions of the wider community and to respond to criticism respectfully. We will strive to model behaviors that encourage productive debate and disagreement, both within our community and where we are criticized. We will treat those outside our community with the same respect as people within our community.

  • we pledge to help the entire community follow the code of conduct, and to not remain silent when we see violations of the code of conduct. We will take action when members of our community violate this code such as contacting shreyas@einsteinpy.org (all emails sent to this address will be treated with the strictest confidence) or talking privately with the person.

This code of conduct applies to all community situations online and offline, including mailing lists, forums, social media, conferences, meetings, associated social events, and one-to-one interactions.

Parts of this code of conduct have been adapted from the Astropy code of conduct.

The Code of Conduct for the EinsteinPy community is licensed under a Creative Commons Attribution 4.0 International License. We encourage other communities related to ours to use or adapt this code as they see fit.