Skip to content

Lyα MCRT

How does THOR stack up against established Lyα radiative-transfer codes on accuracy and speed?

Desktop

Lyα MCRT benchmark — per-code throughput, THOR on GPU versus the CPU codes Lyα MCRT benchmark — per-code throughput, THOR on GPU versus the CPU codes

Run on a single consumer desktop — AMD Ryzen 9 5950X and an NVIDIA RTX 3090 — at N = 10 000 photons, all -O3: THOR with clang (via AdaptiveCpp), the other codes with gcc/gfortran. The GPU bar is THOR's FP32 build at N = 10⁶ (enough to fill the card); the CPU bars are FP64.2

Laptop

Apple M3 Max Lyα MCRT throughput for THOR on Metal and CPU, RASCAS, COLT, and Iltis Apple M3 Max Lyα MCRT throughput for THOR on Metal and CPU, RASCAS, COLT, and Iltis

Metal reaches 1,700 photons/s, 35–125× the CPU codes.

Accuracy

The test is the Neufeld static sphere — a point source at the centre of a static, uniform, dust-free sphere of hydrogen — run against RASCAS, COLT and Iltis. Its emergent Lyα profile has a closed-form solution1, so each code's accuracy is just its R² against it:

\[ J(x) \;\propto\; \frac{x^2}{1 + \cosh\!\big[\sqrt{2\pi^3/27}\,|x^3|/(a\,\tau_0)\big]} \]

Canonical run: τ₀ = 10⁶, T = 2×10⁴ K, xcrit = 0 (no acceleration).

Emergent Lyα spectra of THOR (CPU and GPU), COLT, RASCAS and Iltis vs the analytic solution at τ₀ = 10⁶ Emergent Lyα spectra of THOR (CPU and GPU), COLT, RASCAS and Iltis vs the analytic solution at τ₀ = 10⁶

All four codes land on the analytic curve (R² ≈ 0.91–0.96) and agree with each other to ~1.5 %, each doing the ~10⁶ scatterings per photon expected without acceleration.

Iltis

The public cbehren/Iltis is broken for this comparison (spiky spectrum, R² ≈ 0.6 at τ₀ ≥ 10⁵), so it is not in the default run. Add it with a maintained (private) voroILTIS build — run_all.sh forwards ILTIS_URL/ILTIS_REF to the container build:

ILTIS_URL=<voroILTIS-repo> ILTIS_REF=<sha> \
  run_all.sh --build --codes "thor rascas colt iltis" --tau10 6 --out ./out

Run it

apptainer/benchmarks/neufeld/common/run_all.sh --build --tau10 6 --out ./out

TAU10 sets the optical depth; NPHOTONS, RASCAS_NRANKS and --march are the other knobs.

On an Apple Silicon Mac, use the native runner. CPU and GPU use separate binaries because the benchmark compares FP64 and FP32 builds:

brew install cmake gcc open-mpi hdf5 yaml-cpp gsl libomp
VOROILTIS_SOURCE=/path/to/voroILTIS \
  THOR_CPU_BIN=/path/to/thor-fp64 THOR_GPU_BIN=/path/to/thor-fp32 \
  apptainer/benchmarks/neufeld/common/run_all_apple.sh \
  --build --tau10 6 --out ./out-apple

References

  • Neufeld (1990), ApJ 350, 216 — ADS
  • Dijkstra, Haiman & Spaans (2006), ApJ 649, 14 — ADS
  • Byrohl & Nelson (2025), THOR code paper — see Papers

  1. Dijkstra, Haiman & Spaans (2006), after Neufeld (1990)

  2. Run 2026-06-05. Code versions — THOR 7449d06a, COLT 88429d9, RASCAS 3b18dd0, voroILTIS 9ae77da (plus local Neufeld-setup modifications not captured by the hash). The public-Iltis container recipe pins 3efd87c but is not used for these figures.