GPU-Accelerated Ray Tracing with OpenCL

As of version 1.4.0, the module supports GPU-accelerated batch ray tracing via OpenCL. When tracing large numbers of rays (100k–1M+) through an optical system, the GPU can provide 10–100x speedup over the pure-Python path.

Installation

OpenCL support is optional. Install pyopencl to enable it:

pip install pyopencl

The rest of the module works without it. If pyopencl is not installed or no GPU is available, traceMany() silently falls back to native Python tracing.

How it works

The standard Ray class stores data in Python attributes on the heap. This is convenient but incompatible with GPU programming, where all data must live in a single contiguous block of memory.

The compact module solves this with a view pattern:

  • CompactRays allocates one flat numpy structured array that holds all ray data side by side in memory (24 bytes per ray), exactly like a C array of structs.

  • CompactRay is a lightweight view into that buffer: it looks and behaves like a regular Ray (same properties: y, theta, z, etc.) but every read and write goes directly into the shared buffer.

This way, Python code can keep using the familiar ray.y syntax while the underlying memory layout is ready to be sent to the GPU in a single transfer.

Quick example

from raytracing import *
from raytracing.compact import CompactRays

# Build an optical system
path = ImagingPath()
path.append(Space(d=10))
path.append(Lens(f=50, diameter=25))
path.append(Space(d=100))
path.append(Lens(f=50, diameter=25))
path.append(Space(d=10))
group = MatrixGroup(path.transferMatrices())

# Create 1 million rays in a contiguous buffer
rays = CompactRays(maxCount=1_000_000)
rays.fillWithRandomUniform(yMax=5)

# Trace through the system (uses GPU if available, falls back to CPU)
traces = group.traceMany(rays)

# Display the output profile
traces.lastRays.display("Output profile")

Key methods

traceMany(inputRays, useOpenCL=True)

The main entry point. Tries the GPU path first; if anything fails (missing pyopencl, no GPU, kernel error), it silently falls back to traceManyNative(). Works with both regular Rays and CompactRays.

traceManyOpenCL(inputRays)

Traces rays on the GPU. Requires CompactRays input and pyopencl. Raises a clear RuntimeError if dependencies are missing.

traceManyNative(inputRays)

Pure-Python fallback. Works with any iterable of rays.

Output classes

CompactRaytrace

A view into a slice of the output buffer representing one ray’s path through all optical elements. No data is copied.

CompactRaytraces

Organises the flat GPU output buffer into individual traces. traces.lastRays returns a Rays collection of the final ray from each trace, ready for display() or histogram analysis.

RayTrace / RayTraces

The equivalent classes for native (non-GPU) tracing, providing the same interface.

Performance tips

  • Use CompactRays with large ray counts (100k+) to benefit from GPU acceleration. Smaller batches may be slower due to transfer overhead.

  • CompactRays.yValues and CompactRays.thetaValues read directly from the numpy array, avoiding per-ray Python overhead.

  • fillWithRandomUniform() uses vectorized numpy operations internally.

See also