Visualizing the horizons and ergosurfaces of Kerr spacetime¶

This Jupyter notebook illustrates some applications of SageMath functionalities in general relativity, specifically in deriving and displaying the horizons and ergosurfaces of the Kerr spacetime. Most of the involved tools are part of the SageManifolds project.

Rogerio T. Cavalcanti

It requires the SageMath version at least equal to 9.2.

In [1]:
version()

Out[1]:
'SageMath version 9.4, Release Date: 2021-08-22'
In [2]:
%display latex

In [3]:
Parallelism().set(nproc=8)


Kerr spacetime in Boyer–Lindquist coordinates¶

In [4]:
a = var('a', domain='positive')
M.<t, r, th, ph> = manifolds.Kerr(m=1, a=a, coordinates='BL')
BL = M.default_chart()

In [5]:
g = M.metric()
g.display_comp()

Out[5]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\begin{array}{lcl} g_{ \, t \, t }^{ \phantom{\, t}\phantom{\, t} } & = & \frac{2 \, r}{a^{2} \cos\left({\theta}\right)^{2} + r^{2}} - 1 \\ g_{ \, t \, {\phi} }^{ \phantom{\, t}\phantom{\, {\phi}} } & = & \frac{2 \, a r \sin\left({\theta}\right)^{2}}{a^{2} \cos\left({\theta}\right)^{2} + r^{2}} \\ g_{ \, r \, r }^{ \phantom{\, r}\phantom{\, r} } & = & \frac{a^{2} \cos\left({\theta}\right)^{2} + r^{2}}{a^{2} + r^{2} - 2 \, r} \\ g_{ \, {\theta} \, {\theta} }^{ \phantom{\, {\theta}}\phantom{\, {\theta}} } & = & a^{2} \cos\left({\theta}\right)^{2} + r^{2} \\ g_{ \, {\phi} \, t }^{ \phantom{\, {\phi}}\phantom{\, t} } & = & \frac{2 \, a r \sin\left({\theta}\right)^{2}}{a^{2} \cos\left({\theta}\right)^{2} + r^{2}} \\ g_{ \, {\phi} \, {\phi} }^{ \phantom{\, {\phi}}\phantom{\, {\phi}} } & = & {\left(\frac{2 \, a^{2} r \sin\left({\theta}\right)^{2}}{a^{2} \cos\left({\theta}\right)^{2} + r^{2}} + a^{2} + r^{2}\right)} \sin\left({\theta}\right)^{2} \end{array}$

Metric singularities and ergosurfaces¶

• The $g_{tt},g_{t\phi}$ and $g_{\phi\phi}$ components are singular at the singular ring $a^2\cos^2\theta +r^2=0$, that is $r=0$ and $\theta =\frac{\pi}{2}$. It corresponds to a physical singularity, as checked below.
In [6]:
singular_ring = {r:0, th:pi/2}

• Singular surfaces on $\displaystyle ({g_{rr}})^{-1} = 0$ (Horizons)
In [7]:
horizons = solve(1/g[1,1].expr()==0,r,solution_dict=True)
horizons

Out[7]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left[\left\{r : -\sqrt{-a^{2} + 1} + 1\right\}, \left\{r : \sqrt{-a^{2} + 1} + 1\right\}\right]$
In [8]:
inner_horizon, outer_horizon = horizons

• The Ergosurfaces are the regions of vanishing $K_\mu K^\mu$, where $K = \frac{\partial}{\partial t }$ is a Killing vector field.
In [9]:
K = M.vector_field(1,0,0,0, name='K')
K.display()

Out[9]:
$\newcommand{\Bold}[1]{\mathbf{#1}}K = \frac{\partial}{\partial t }$

Checking if $K$ is a Killing vector field $(\mathcal{L}_{_K}g = 0)$

In [10]:
g.lie_derivative(K) == 0

Out[10]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\mathrm{True}$
In [11]:
g(K,K).display()

Out[11]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\begin{array}{llcl} g\left(K,K\right):& M & \longrightarrow & \mathbb{R} \\ & \left(t, r, {\theta}, {\phi}\right) & \longmapsto & \frac{2 \, r}{a^{2} \cos\left({\theta}\right)^{2} + r^{2}} - 1 \end{array}$
In [12]:
ergosurfaces = solve(g(K,K).expr(),r,solution_dict=True)
ergosurfaces

Out[12]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left[\left\{r : -\sqrt{-a^{2} \cos\left({\theta}\right)^{2} + 1} + 1\right\}, \left\{r : \sqrt{-a^{2} \cos\left({\theta}\right)^{2} + 1} + 1\right\}\right]$
In [13]:
inner_ergo, outer_ergo = ergosurfaces


List of surfaces

In [14]:
surfaces_param = [outer_ergo,outer_horizon,inner_horizon,inner_ergo,singular_ring]


Rational polynomial coordinates¶

In rational polinomial coordinates all components of the Kerr metric are rational polynomials, which in principle make it easyer to handle. We are going to use such coordinates for checking the Kretschmann scalar over the horizon and ergosurfaces of the spacetime.

In [15]:
RP.<t, r, ch, ph> = M.chart(r't:(-oo,+oo) r:(0,+oo) ch:(-1,1):\chi ph:(-pi,pi):periodic:\phi')


Transition map from Boyerâ€“Lindquist coordinates to rational polynomial coordinates and its inverse.

In [16]:
BL_to_RP = BL.transition_map(RP, [t, r, cos(th), ph])
BL_to_RP.display()

Out[16]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left\{\begin{array}{lcl} t & = & t \\ r & = & r \\ {\chi} & = & \cos\left({\theta}\right) \\ {\phi} & = & {\phi} \end{array}\right.$
In [17]:
BL_to_RP.set_inverse(t, r, acos(ch), ph)
BL_to_RP.inverse().display()

Out[17]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left\{\begin{array}{lcl} t & = & t \\ r & = & r \\ {\theta} & = & \arccos\left({\chi}\right) \\ {\phi} & = & {\phi} \end{array}\right.$
In [18]:
g.display_comp(RP.frame(),RP)

Out[18]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\begin{array}{lcl} g_{ \, t \, t }^{ \phantom{\, t}\phantom{\, t} } & = & -\frac{a^{2} {\chi}^{2} + r^{2} - 2 \, r}{a^{2} {\chi}^{2} + r^{2}} \\ g_{ \, t \, {\phi} }^{ \phantom{\, t}\phantom{\, {\phi}} } & = & -\frac{2 \, {\left(a {\chi}^{2} - a\right)} r}{a^{2} {\chi}^{2} + r^{2}} \\ g_{ \, r \, r }^{ \phantom{\, r}\phantom{\, r} } & = & \frac{a^{2} {\chi}^{2} + r^{2}}{a^{2} + r^{2} - 2 \, r} \\ g_{ \, {\chi} \, {\chi} }^{ \phantom{\, {\chi}}\phantom{\, {\chi}} } & = & -\frac{a^{2} {\chi}^{2} + r^{2}}{{\chi}^{2} - 1} \\ g_{ \, {\phi} \, t }^{ \phantom{\, {\phi}}\phantom{\, t} } & = & -\frac{2 \, {\left(a {\chi}^{2} - a\right)} r}{a^{2} {\chi}^{2} + r^{2}} \\ g_{ \, {\phi} \, {\phi} }^{ \phantom{\, {\phi}}\phantom{\, {\phi}} } & = & -\frac{a^{4} {\chi}^{4} - a^{4} {\chi}^{2} + {\left({\chi}^{2} - 1\right)} r^{4} + {\left(a^{2} {\chi}^{4} - a^{2}\right)} r^{2} - 2 \, {\left(a^{2} {\chi}^{4} - 2 \, a^{2} {\chi}^{2} + a^{2}\right)} r}{a^{2} {\chi}^{2} + r^{2}} \end{array}$

Setting the default chart and frame

In [19]:
M.set_default_chart(RP)

In [20]:
M.set_default_frame(RP.frame())


Riemann tensor, Ricci tensor and Kretschmann scalar

In [21]:
%time Riem = g.riemann()

CPU times: user 5.26 s, sys: 634 ms, total: 5.89 s
Wall time: 36.6 s

In [22]:
%time Ric = g.ricci()

CPU times: user 4.43 s, sys: 65.2 ms, total: 4.49 s
Wall time: 2.6 s

In [23]:
Ric == 0

Out[23]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\mathrm{True}$
In [24]:
%time R_up = Riem.up(g)

CPU times: user 1.54 s, sys: 236 ms, total: 1.78 s
Wall time: 21.2 s

In [25]:
%time R_down = Riem.down(g)

CPU times: user 404 ms, sys: 92.4 ms, total: 497 ms
Wall time: 3.52 s

In [26]:
%time Kretschmann_scalar = R_up['^{abcd}']*R_down['_{abcd}']

CPU times: user 49.8 s, sys: 891 ms, total: 50.7 s
Wall time: 31.7 s

In [27]:
Kretschmann_scalar.display()

Out[27]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\begin{array}{llcl} & M & \longrightarrow & \mathbb{R} \\ & \left(t, r, {\theta}, {\phi}\right) & \longmapsto & -\frac{48 \, {\left(a^{6} \cos\left({\theta}\right)^{6} - 15 \, a^{4} r^{2} \cos\left({\theta}\right)^{4} + 15 \, a^{2} r^{4} \cos\left({\theta}\right)^{2} - r^{6}\right)}}{a^{12} \cos\left({\theta}\right)^{12} + 6 \, a^{10} r^{2} \cos\left({\theta}\right)^{10} + 15 \, a^{8} r^{4} \cos\left({\theta}\right)^{8} + 20 \, a^{6} r^{6} \cos\left({\theta}\right)^{6} + 15 \, a^{4} r^{8} \cos\left({\theta}\right)^{4} + 6 \, a^{2} r^{10} \cos\left({\theta}\right)^{2} + r^{12}} \\ & \left(t, r, {\chi}, {\phi}\right) & \longmapsto & -\frac{48 \, {\left(a^{6} {\chi}^{6} - 15 \, a^{4} {\chi}^{4} r^{2} + 15 \, a^{2} {\chi}^{2} r^{4} - r^{6}\right)}}{a^{12} {\chi}^{12} + 6 \, a^{10} {\chi}^{10} r^{2} + 15 \, a^{8} {\chi}^{8} r^{4} + 20 \, a^{6} {\chi}^{6} r^{6} + 15 \, a^{4} {\chi}^{4} r^{8} + 6 \, a^{2} {\chi}^{2} r^{10} + r^{12}} \end{array}$

Getting and factoring the symbolic expression in the default chart

In [28]:
K_scalar = Kretschmann_scalar.expr().factor()
K_scalar

Out[28]:
$\newcommand{\Bold}[1]{\mathbf{#1}}-\frac{48 \, {\left(a^{2} {\chi}^{2} + 4 \, a {\chi} r + r^{2}\right)} {\left(a^{2} {\chi}^{2} - 4 \, a {\chi} r + r^{2}\right)} {\left(a {\chi} + r\right)} {\left(a {\chi} - r\right)}}{{\left(a^{2} {\chi}^{2} + r^{2}\right)}^{6}}$

Kretschmann scalar along the singular ring, horizons and ergosurfaces¶

Singular Ring $(r=0,\chi=0)$

In [29]:
K_scalar.subs(r=0)

Out[29]:
$\newcommand{\Bold}[1]{\mathbf{#1}}-\frac{48}{a^{6} {\chi}^{6}}$
In [30]:
K_scalar.subs(ch=0)

Out[30]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\frac{48}{r^{6}}$

Outer ergosurface, outer horizon and inner horizon at $\chi = 0$

In [31]:
for k in ['outer_ergo','outer_horizon','inner_horizon']:
print(k)
display(K_scalar.subs(eval(k)).subs({cos(th):ch}).subs(ch=0))

outer_ergo

$\newcommand{\Bold}[1]{\mathbf{#1}}\frac{3}{4}$
outer_horizon

$\newcommand{\Bold}[1]{\mathbf{#1}}\frac{48}{{\left(\sqrt{-a^{2} + 1} + 1\right)}^{6}}$
inner_horizon

$\newcommand{\Bold}[1]{\mathbf{#1}}\frac{48}{{\left(\sqrt{-a^{2} + 1} - 1\right)}^{6}}$

Inner ergosurface for $\chi \neq 0$ (the inner ergosurface coincides with the singular ring at $\chi = 0$)

In [32]:
K_inner_ergo = K_scalar.subs(inner_ergo).subs({cos(th):ch}).canonicalize_radical()
K_inner_ergo

Out[32]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\frac{6 \, {\left(4 \, a^{6} {\chi}^{6} - 21 \, a^{4} {\chi}^{4} + 21 \, a^{2} {\chi}^{2} + {\left(12 \, a^{4} {\chi}^{4} - 19 \, a^{2} {\chi}^{2} + 4\right)} \sqrt{a {\chi} + 1} \sqrt{-a {\chi} + 1} - 4\right)}}{a^{6} {\chi}^{6} - 18 \, a^{4} {\chi}^{4} + 48 \, a^{2} {\chi}^{2} + 2 \, {\left(3 \, a^{4} {\chi}^{4} - 16 \, a^{2} {\chi}^{2} + 16\right)} \sqrt{a {\chi} + 1} \sqrt{-a {\chi} + 1} - 32}$

Series expansion up to $O(\chi^5)$

In [33]:
K_inner_ergo.series(ch,5)

Out[33]:
$\newcommand{\Bold}[1]{\mathbf{#1}}{(-\frac{48}{a^{6}})} {\chi}^{(-6)} + {(\frac{252}{a^{4}})} {\chi}^{(-4)} + {(-\frac{252}{a^{2}})} {\chi}^{(-2)} + \frac{189}{4} + {(\frac{45}{16} \, a^{2})} {\chi}^{2} + {(\frac{45}{64} \, a^{4})} {\chi}^{4} + \mathcal{O}\left({\chi}^{5}\right)$

Setting the default chart and frame back to Boyerâ€“Lindquist

In [34]:
M.set_default_chart(BL)
M.set_default_frame(BL.frame())


Kerr coordinates¶

The Kerr original coordinates will be used as an intermediate step for introducing the Kerr-Schild coordinates.

In [35]:
Kr.<u, r, th, vph> = M.chart(r'u:(-oo,+oo) r:(0,+oo) th:(0,pi):\theta vph:(-pi,pi):periodic:\varphi')

In [36]:
f(r) = r/(a^2+r^2-2*r)
assume(a<1)
F(r) = integral(f(r),r)

In [37]:
Kr_to_BL = Kr.transition_map(BL, [u-2*F(r), r, th, vph-a*F(r)])
Kr_to_BL.display()

Out[37]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left\{\begin{array}{lcl} t & = & u - \frac{\log\left(\frac{r - \sqrt{-a^{2} + 1} - 1}{r + \sqrt{-a^{2} + 1} - 1}\right)}{\sqrt{-a^{2} + 1}} - \log\left(a^{2} + r^{2} - 2 \, r\right) \\ r & = & r \\ {\theta} & = & {\theta} \\ {\phi} & = & -\frac{1}{2} \, a {\left(\frac{\log\left(\frac{r - \sqrt{-a^{2} + 1} - 1}{r + \sqrt{-a^{2} + 1} - 1}\right)}{\sqrt{-a^{2} + 1}} + \log\left(a^{2} + r^{2} - 2 \, r\right)\right)} + {\varphi} \end{array}\right.$
In [38]:
Kr_to_BL.inverse().display()

Out[38]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left\{\begin{array}{lcl} u & = & \frac{{\left(a^{2} - 1\right)} t + {\left(a^{2} - 1\right)} \log\left(a^{2} + r^{2} - 2 \, r\right) + \sqrt{a + 1} \sqrt{-a + 1} \log\left(-\frac{a^{2} + r^{2} - 2 \, r}{a^{2} + 2 \, \sqrt{a + 1} \sqrt{-a + 1} {\left(r - 1\right)} - r^{2} + 2 \, r - 2}\right)}{a^{2} - 1} \\ r & = & r \\ {\theta} & = & {\theta} \\ {\varphi} & = & \frac{\sqrt{a + 1} a \sqrt{-a + 1} \log\left(-\frac{a^{2} + r^{2} - 2 \, r}{a^{2} + 2 \, \sqrt{a + 1} \sqrt{-a + 1} {\left(r - 1\right)} - r^{2} + 2 \, r - 2}\right) + 2 \, {\left(a^{2} - 1\right)} {\phi} + {\left(a^{3} - a\right)} \log\left(a^{2} + r^{2} - 2 \, r\right)}{2 \, {\left(a^{2} - 1\right)}} \end{array}\right.$

Showing the change of frame from BL to Kerr

In [39]:
M.change_of_frame(BL.frame(),Kr.frame())[:]

Out[39]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left(\begin{array}{rrrr} 1 & -\frac{2 \, r}{a^{2} + r^{2} - 2 \, r} & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & -\frac{a r}{a^{2} + r^{2} - 2 \, r} & 0 & 1 \end{array}\right)$

Surfaces in Kerr-Schild coordinates¶

In [40]:
KS.<u,x,y,z> = M.chart()


Change of coordinates from Kerr to Kerr-Schild

In [41]:
Kr_to_KS = Kr.transition_map(KS, [u, (r*cos(vph) - a*sin(vph))*sin(th),
(r*sin(vph) + a*cos(vph))*sin(th),
r*cos(th)])
Kr_to_KS.display()

Out[41]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\left\{\begin{array}{lcl} u & = & u \\ x & = & {\left(r \cos\left({\varphi}\right) - a \sin\left({\varphi}\right)\right)} \sin\left({\theta}\right) \\ y & = & {\left(a \cos\left({\varphi}\right) + r \sin\left({\varphi}\right)\right)} \sin\left({\theta}\right) \\ z & = & r \cos\left({\theta}\right) \end{array}\right.$

Parametrization of the surfaces in Kerr-Schild coordinates

In [42]:
surfaces_KS = [vector([s.subs(param) for s in Kr_to_KS(u, r, th, ph)[1:]]) for param in surfaces_param]


Plotting¶

In [43]:
# plotting data
surfs_data = {
'outer_ergo': {'name': 'Outer ergosurface',
'color': 'gray',
'z_label': 1,
'param_index': 0,
'phi1': 7*pi/5,
'plot_points_factor': 1},
'outer_orizon': {'name': 'Outer horizon',
'color': colormaps.Set1(1)[:3],
'z_label': .5,
'param_index': 1,
'phi1': 7*pi/5,
'plot_points_factor': 1},
'inner_horizon': {'name': 'Inner horizon',
'color': colormaps.Set1(4)[:3],
'z_label': 0,
'param_index': 2,
'phi1': 6*pi/5,
'plot_points_factor': .7},
'inner_ergo': {'name': 'Inner ergosurface',
'color': colormaps.Set1(3)[:3],
'z_label': -0.5,
'param_index': 3,
'phi1': 2*pi,
'plot_points_factor': .7}}


Python function for plotting the surfaces

In [44]:
def kerr_surfaces(surf, a=.99, print_labels=True, plot_points=30, mesh=True, **kwargs):
if a >1 or a < 0:
print("choose 'a' between 0 and 1")
return None
#     Labels
if print_labels:
Ker_BH = text3d('Kerr black hole', (-2,-5,2.5), fontsize='200%', fontfamily='serif', fontweight='bold')
sep_line = text3d(r'___', (-2,-5,1.7), fontsize='160%', fontfamily='serif', fontweight='bold')
a_label = text3d('a = ' + str(a.n(digits=5)), (-2,-5,2), fontsize='170%')
s_ring_label = text3d('Singular ring', (-2,-5,-1), color='red', fontsize='170%', fontfamily='serif')
labels = sum([text3d(S['name'],
(-2,-5,S['z_label']),
color=S['color'],
fontsize='170%',
fontfamily='serif') for S in surfs_data.values()])
labels += Ker_BH + a_label + s_ring_label + sep_line
else: labels = Graphics()
#     Surfaces
s_ring = parametric_plot3d(surf[4].subs(a=a),(ph,0,2*pi), color='red', thickness=4)
plots = sum([parametric_plot3d(surf[S['param_index']].subs(a=a),
(th,0,pi),
(ph,0,S['phi1']),
color=S['color'],
mesh=mesh,
plot_points=S['plot_points_factor']*plot_points,
frame=False,
**kwargs) for S in surfs_data.values()])
plots += s_ring
return plots+labels


In [45]:
kerr_surfaces(surfaces_KS, 0.999, viewpoint=[[-0.6557,-0.5284,-0.5394],112.41])

Out[45]:

Dark theme

In [46]:
kerr_surfaces(surfaces_KS, .9, viewpoint=[[-0.6557,-0.5284,-0.5394],112.41], theme='dark')

Out[46]:

Immersion in Euclidean space¶

We can also see the surfaces immersed in the Euclidian space $\mathbb{E}^3$.

In [47]:
E.<x,y,z> = EuclideanSpace(3)
spherical.<r, th, ph> = E.spherical_coordinates()


Differential map from Kerr coordinates to the Euclidean space

In [48]:
Kr_to_E = M.diff_map(E, {(Kr, spherical): [r,th,ph]},
name='Kr_to_E',
latex_name=r'\Phi_{_{\text{Kerr} \to \mathbb{E}^3}}')

In [49]:
Kr_to_E.display()

Out[49]:
$\newcommand{\Bold}[1]{\mathbf{#1}}\begin{array}{llcl} \Phi_{_{\text{Kerr} \to \mathbb{E}^3}}:& M & \longrightarrow & \mathbb{E}^{3} \\ & \left(t, r, {\theta}, {\phi}\right) & \longmapsto & \left(x, y, z\right) = \left(r \cos\left({\phi}\right) \sin\left({\theta}\right), r \sin\left({\phi}\right) \sin\left({\theta}\right), r \cos\left({\theta}\right)\right) \\ & \left(t, r, {\theta}, {\phi}\right) & \longmapsto & \left(r, {\theta}, {\phi}\right) = \left(r, \arctan\left(r \sin\left({\theta}\right), r \cos\left({\theta}\right)\right), \arctan\left(r \sin\left({\phi}\right) \sin\left({\theta}\right), r \cos\left({\phi}\right) \sin\left({\theta}\right)\right)\right) \\ & \left(t, r, {\chi}, {\phi}\right) & \longmapsto & \left(x, y, z\right) = \left(\sqrt{{\chi} + 1} \sqrt{-{\chi} + 1} r \cos\left({\phi}\right), \sqrt{{\chi} + 1} \sqrt{-{\chi} + 1} r \sin\left({\phi}\right), {\chi} r\right) \\ & \left(t, r, {\chi}, {\phi}\right) & \longmapsto & \left(r, {\theta}, {\phi}\right) = \left(r, \arctan\left(\sqrt{{\chi} + 1} \sqrt{-{\chi} + 1} r, {\chi} r\right), \arctan\left(\sqrt{{\chi} + 1} \sqrt{-{\chi} + 1} r \sin\left({\phi}\right), \sqrt{{\chi} + 1} \sqrt{-{\chi} + 1} r \cos\left({\phi}\right)\right)\right) \\ & \left(u, r, {\theta}, {\varphi}\right) & \longmapsto & \left(x, y, z\right) = \left(r \cos\left({\phi}\right) \sin\left({\theta}\right), r \sin\left({\phi}\right) \sin\left({\theta}\right), r \cos\left({\theta}\right)\right) \\ & \left(u, r, {\theta}, {\varphi}\right) & \longmapsto & \left(r, {\theta}, {\phi}\right) = \left(r, {\theta}, {\phi}\right) \end{array}$

Coordinates in Euclidean space

In [50]:
coordinates = Kr_to_E(M.point((u,r,th,vph), chart=Kr)).coordinates()


Surfaces in Euclidean space

In [51]:
surfaces_E = [vector([s.subs(param) for s in coordinates]) for param in surfaces_param]

In [52]:
kerr_surfaces(surfaces_E, .96, viewpoint=[[-0.8499,-0.3478,-0.396],91.88])

Out[52]: