Implementing a new metric
Gradus.jl is able to integrate any 3+1 dimensional metric. A new metric may be defined by implementing one of the abstract types with a concrete type, and defining a number of methods. Depending on what you want to be able to do with a metric, different functions need to be implemented.
Gradus also provides a few derivative abstract types to implement to ensure the most efficient code is executed for a given metric (see Metric parameter types below).
Example: Schwarzschild
As a minimal example, here is how the Schwarzschild metric may be implemented. First, we must define what the metric parameters for this metric are. These are effectively constants of the spacetime, representing physical quantities that appear in the metric expression. For the Schwarzschild metric, this is only the black hole mass $M$, but e.g. the Kerr metric also has the black hole spin $a$.
We can choose the integration strategy by sub-typing an abstract type representing different classes of spacetimes. For the Schwarzschild metric, we will use the static, axis-symmetric class, with the automatic differentiation (AD) backend. With AD, we only need to specify the non-zero components of the metric as Julia functions, and the rest is done for us.
For ease, we choose the Eddington-Finkelstein coordinates of the Schwarzschild solution, which may be written
\[\text{d}s^2 = - \left( 1 - \frac{2 M}{r} \right) \text{d}t^2 + \left( 1 - \frac{2 M}{r} \right)^{-1} \text{d}r^2 + r^2 \text{d}\theta^2 + r^2 \sin^2(\theta) \text{d}\phi^2.\]
Here is a possible implementation for Gradus.jl:
using Gradus
@with_kw struct EddingtonFinkelsteinAD{T} <: AbstractStaticAxisSymmetric{T}
M = 1.0
end
function Gradus.metric_components(m::EddingtonFinkelsteinAD{T}, rθ) where {T}
(r, θ) = rθ
M = m.M
tt = -(1 - (2M / r))
rr = -inv(tt)
θθ = r^2
ϕϕ = r^2 * sin(θ)^2
(tt, rr, θθ, ϕϕ, T(0.0))
end
Gradus.inner_radius(m::EddingtonFinkelsteinAD) = 2 * m.M
A few notes:
- We use
@with_kw
from Parameters.jl to define various utility constructors for us. metric_components
must return five elements forAbstractStaticAxisSymmetric
, where the last element is the off-axis $g_{t \phi}$ matrix element, which in this case is always 0.- The
inner_radius
function defines the inner-radius of integration chart. This defines where the integration should terminate to avoid running indefinitely, and is, in this case, set to the event-horizon of our metric.
That's all we need! This metric is now ready to be traced in the usual way.
For more examples of how to implement different metrics, click on the "source" button of a metric in Implemented Metrics. Alternatively, view the source code directly here.
Metric parameter types
The following types may be implemented to add new metrics. Each type has different requirements for its interface.
First-Order
Gradus.AbstractFirstOrderMetric
— TypeAbstractFirstOrderMetric{T} <: AbstractMetric{T}
Abstract type for metrics using the 1st-order integration method. The 1st-order methods reuse the velocity vector as a parameter vector, where only element vel[2]
and vel[3]
are used, and are local observer ratios $\sin \Theta$ and $\sin \Phi$ respectively.
Require implementation of
Gradus.four_velocity
— Functionfour_velocity(x, m::AbstractFirstOrderMetric, p)
Calculate the four-velocity at a point u
, given a set of metric parameters and the constants of motion in p
.
Gradus.calc_lq
— Functioncalc_lq(m::AbstractFirstOrderMetric, pos, param))
Calculate constants of motion $L$ and $Q$, given a set of metric parameters, the geodesic position, and the param
vector.
Gradus.Vr
— FunctionVr(m::AbstractFirstOrderMetric, u, p)
Effective potential in the radial direction. Used only to track sign changes.
Gradus.Vθ
— FunctionVθ(m::AbstractFirstOrderMetric, u, p)
Effective potential in the angular direction. Used only to track sign changes.
Second-Order
Gradus.metric_components
— Functionmetric_components(m::AbstractMetric{T}, x)
Return a tuple with each non-zero metric component for the metric described by m
at position x
. Note that the position need not be a four-vector, and for specific implementations may only be a subset of the total manifold coordinates. See specific implementations for subtypes of AbstractMetric
for details.
metric_components(m::AbstractStaticAxisSymmetric, rθ
Interface for AbstractStaticAxisSymmetric
. Should return a vector or tuple with the elements
\[\left( g_{tt}, g_{rr}, g_{\theta \theta}, g_{\phi \phi}, g_{t\phi} \right).\]
Gradus.AbstractStaticAxisSymmetric
— TypeAbstractStaticAxisSymmetric{T}
Specialisation for static, axis-symmetric metrics. Here, the metric is of the form
\[ g_{\mu\nu} = \left( \begin{matrix} g_{tt} & 0 & 0 & g_{t\phi} \\ 0 & g_{rr} & 0 & 0 \\ 0 & 0 & g_{\theta\theta} & 0 \\ g_{t\phi} & 0 & 0 & g_{\phi\phi} \end{matrix} \right),\]
where the only non-zero off axis elements are $g_{t\phi}$.
Required implementations: