RayTraceGR.jl

A ray-tracer for curved spacetimes
Author eschnett
Popularity
13 Stars
Updated Last
1 Year Ago
Started In
April 2020

RayTraceGR.jl

GitHub CI

ray-traced Euclidean sphere ray-traced relativistic sphere

This is a relativistic ray tracer. The examples below show how spheres look, either in a flat spacetime or near a black hole.

Examples

Example 1: Sphere in a flat spacetime

using RayTraceGR
RayTraceGR.example1()

The output is a PNG file scenes/sphere.png.

Example 2: Sphere near a black hole

using RayTraceGR
RayTraceGR.example2()

The output is a PNG file scenes/sphere2.png.

The code is multi-threaded. If you start Julia with the environment variable JULIA_NUM_THREADS set correspondingly, the code should run faster.

Algorithm

A scene consists of a background spacetime, several objects that emit light, and a screen that captures photons.

In the basic tay tracing algorithm, one starts from the pixels of the screen where the photons are absorbed, and traces the rays backwards in time to see where they emanated.

  • The spacetime is defined by its metric, which defines how light rays move. A flat spacetime is trivial (light rays move along straight lines). Other spacetimes may describe black holes, wormholes, or more exotic settings.

  • The objects are the light sources, i.e. the things that are visible in a scene. When a light ray intersects an object, one calculates where on the object it intersects. By defining which part of an object has what colour, one thus knows what colour the photon is.

  • The screen consists of a rectangular array of pixels. The screen is probably slightly curved, so that you get a certain field of view.

Light rays are traced by solving the geodesic equation with an ODE solver. This is the physically correct way to trace light rays, and it works with arbitrary metrics.

If I find the time, I might trace rays in a numerically calculated spacetime, such as coalescing binary black holes as e.g. calculated via the Einstein Toolkit.

Modifying the scene

It is not (yet?) possible to specify a scene via a parameter file. Instead, the scene is described as Julia code.

The code has two metrics built in, a flat spacetime (minkowski) and a rotating black hole (kerr_schild). The black hole can have a varying mass (M) and spin (a).

You specify the objects and their locations, as well as the screen. For example, example2 specifies:

  • 3 Objects: A large sphere as background sky (caelum) with radius 10, a cut-off plane in the past (frustum) at time -20, and a visible sphere (sphere) sitting net to the black hole
  • A screen with a certain width and height, with a view angle of 90°

Implementation details

Coordinates

The code uses Cartesian coordinates t, x, y, z since these have no coordinate singularities. Many black hole metrics are specified in spherical coordinates t, r, θ, ϕ, since the metric looks then much simpler. However, this makes the z axis a considerable source of headache.

Derivatives

Specifying the metric of the spacetime is difficult enough (it's eight lines of equations for the black hole metric), but one also needs the derivatives of the metric for the Christoffel symbols in the geodesic equation. I implemented dual numbers for this, which makes is straightforward to calculate derivatives (see the function dmetric).

The Julia package DualNumbers.jl is not generic enough, as it doesn't allow using vectors as the dual part. The package ForwardDiff.jl seems to support this; I should probably use it instead of my home-grown code.

Parallelization

Ray tracing is "naturally parallel", and it would be a shame to run it serially. I experimented with distributed programming, but got stuck ensuring that the other Julia kernels see both the source code and its dependencies (external packages). Multi-threading was much easier to set up, so I did that.