Skip to main content

GPU-accelerated proton radiography

Project description

prad — GPU Proton Radiography

GPU-accelerated forward modelling of proton radiographs from magnetised plasma.

Runs the full relativistic Boris orbit through measured or simulated electromagnetic fields — not a paraxial approximation — and produces synthetic radiographs in detector/film coordinates for comparison with experimental RCF data, subject to detector-response and experimental-geometry modelling.

✓ 12/12 physics validation tests passing
✓ Reproducible, self-documenting run directories
✓ CLI + GUI workflows
✓ Python API (pip install prad)
✓ Re-render without re-tracing particles

Tested platforms

Platform GPU Backend Status
macOS Apple Silicon Apple M4 MoltenVK/Vulkan Validation suite passing; ~9 B steps/s peak
Ubuntu 22.04 Linux NVIDIA RTX 4090 NVIDIA Vulkan 1.3.277 Validation suite passing; ~34 B steps/s peak

Example radiographs

Three MHD instability geometries, computed in seconds on a laptop GPU:

z-pinch kink instability sausage instability
z-pinch radiograph kink instability radiograph sausage instability radiograph

Each image is a synthetic proton radiograph — the spatial structure directly reflects the path-integrated field topology.

GUI

GUI launcher showing sausage instability run complete

Deck parameters, run status, and the 3D radiograph — all in one view.


Why this tool

Proton radiography is sensitive to the path-integrated field, not just its peak value. The mapping from field structure to film pattern is nonlinear and depends on geometry — magnification, detector distance, source divergence. Paraxial approximations fail in the strong-field, large-deflection regimes common in modern pulsed-power experiments.

This tool runs the full relativistic Boris orbit, so you can:

  • See where paraxial approximations break down and by how much
  • Forward-model field topologies and compare directly to experimental films
  • Design detector geometry before committing to a shot

Prerequisites

Dependency Purpose Install
Rust (stable) Build the engine curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
glslangValidator GLSL → SPIR-V shader compilation brew install glslang
MoltenVK (macOS) Vulkan over Metal brew install molten-vk
Python 3.9+ Validation suite, Python API system or pyenv

Quick start

# Build (also compiles shaders via build.rs)
cd rust && cargo build --release && cd ..

# Scaffold a working deck from a preset
./rust/target/release/proton_tracer init zpinch -o my_run.toml

# Inspect resolved geometry before running
./rust/target/release/proton_tracer explain my_run.toml

# Schema check
./rust/target/release/proton_tracer validate my_run.toml

# Run — produces a self-contained output directory
./rust/target/release/proton_tracer run my_run.toml -o runs/zpinch_01

macOS / MoltenVK — set these before running:

export VK_ICD_FILENAMES=/opt/homebrew/etc/vulkan/icd.d/MoltenVK_icd.json
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH

See docs/quickstart.md for the full install walkthrough.


Python API

prad is a Python wrapper around the engine. Install it with pip:

pip install prad

Run a simulation and get results as numpy arrays in three lines:

import prad

result = prad.run(
    "data/zpinch.bfld",
    energy_MeV=14.7,
    n_particles=200_000,
    source_distance_mm=80.0,
    detector_distance_mm=100.0,
)

counts = result.raw_counts          # numpy uint32, 1024×1024
print(result.diagnostics)           # hit_fraction, n_hits, …
result.show()                       # display inline (Jupyter / matplotlib)

You can also pass a field constructed from a numpy array directly:

import numpy as np, prad

B = np.zeros((64, 64, 64, 3), dtype=np.float32)
B[:, :, :, 2] = 5.0                # 5 T uniform Bz

field = prad.Field.from_array(B, bounds_m=(-0.05, 0.05, -0.05, 0.05, -0.05, 0.05))
result = prad.run(field, n_particles=100_000)

See docs/python_api.md for the full API reference.


Subcommands

Command Purpose
run <deck> [-o dir] Batch run — GPU compute, full run directory output
gui [deck] Interactive launcher with live progress
explain <deck> Print resolved geometry and step budget — no GPU
validate <deck> Schema check only — no GPU
init [preset] [-o deck.toml] Emit a starter deck (blank / zpinch / kink-strong)
demo [preset] Run a built-in preset without writing a deck
render <run_dir> Re-render radiograph from saved counts — no GPU
sweep <deck> --param k=v1,v2 Parameter sweep — one run directory per point
inspect <run_dir|sweep_dir> Print run or sweep summary
analyze <run_dir> Count statistics

Run directory layout

Every run produces a self-contained directory. Share it with a colleague and they can re-render or analyse without re-running anything.

runs/zpinch_01/
  input_deck.toml          ← exact copy of deck used
  resolved_config.json     ← fully resolved SI parameters
  metadata.json            ← hardware, git hash, field SHA-256, timing
  log.txt                  ← full terminal output mirror
  counts/
    raw_counts.bin         ← u32 [H×W] detector hit counts
    processed_counts.bin   ← f32 [H×W] after detector response
  images/
    radiograph.png

Energy spectra

Three proton source spectra are supported:

Mode Deck field Typical use
Monoenergetic energy_MeV D–T fusion protons (14.7 MeV), accelerator beams
Gaussian spread energy_spread_percent Slightly impure mono sources, calibration
Exponential / TNSA temperature_MeV, cutoff_mev Laser-accelerated proton sources
# TNSA example
[source]
temperature_MeV = 3.0
cutoff_mev      = 40.0
n_particles     = 200000

All three modes feed into the same relativistic Boris integrator — u = γv is computed exactly regardless of the drawn energy. See docs/spectra.md for details.


Parameter sweeps

# Energy scan — four runs, zipped
proton_tracer sweep zpinch.toml \
  --param source.energy_MeV=5,10,15,20

# Range syntax
proton_tracer sweep zpinch.toml \
  --param source.energy_MeV=5:20:5

# Paired sweep — same-length lists, zipped
proton_tracer sweep zpinch.toml \
  --param source.energy_MeV=5,10,15 \
  --param numerics.max_steps=10000,20000,30000

Output: runs/sweep_001/ with one run directory per point and a live sweep_manifest.json.


Performance

Measured on Apple M4 (prad v0.3.0):

Field 100,000 particles 1,000,000 particles
zero field 0.34 s 1.87 s
z-pinch 0.31 s 1.88 s
kink 0.35 s 1.92 s
sausage 0.32 s 1.91 s

Peak step throughput: 9.0 B steps/s.

vs PlasmaPy — in a matched simplified uniform-field particle-tracing benchmark (10,000 particles, uniform Bz = 1 T, same geometry), prad's GPU backend is substantially faster than a single-core PlasmaPy CPU Boris workflow. This comparison isolates the forward particle-tracing step only; PlasmaPy is a broader plasma-physics ecosystem and is not being replaced by prad.

PlasmaPy (CPU) prad (GPU)
Wall time 42.8 s 0.20 s
At-scale speedup (1 M particles) ≈ 2280×

Additional Linux/NVIDIA validation on an RTX 4090 reached ~34 B particle-steps/s on the benchmark configuration, corresponding to roughly ~2 M particles/s for the tested step budget. See benchmarks/validation/nvidia_rtx4090_ubuntu2204.txt.

See docs/benchmark.md to reproduce these numbers.


Validation

python3 validate.py           # uses existing binary
python3 validate.py --build   # build first, then validate

12 physics tests: B-only regression, zero-field straight-line projection, uniform E-field deflection (sign and magnitude), relativistic Boris energy conservation (14.7000 MeV recovered to sub-eV accuracy), pencil/point/disk source geometry, Gaussian energy spread, exponential/TNSA spectrum (mean KE ≈ T, hard cutoff enforced), Gaussian blur, Poisson noise reproducibility, and 60 MeV relativistic momentum initialisation (γ ≈ 1.064).


Documentation

Doc Contents
docs/quickstart.md Full install → first run walkthrough
docs/python_api.md Python API reference (prad.run, Field, RunResult)
docs/geometry.md Coordinate system, detector geometry, source types
docs/spectra.md Mono, Gaussian, and TNSA energy spectra
docs/input_decks.md TOML schema, all fields, --set overrides
docs/run_artifacts.md Run directory anatomy and reproducibility
docs/file_formats.md .bfld, binary count formats, metadata schema
docs/rendering.md Counts → PNG pipeline, re-render without GPU
docs/sweeps.md Parameter sweeps, syntax, sweep manifest
docs/benchmark.md Throughput scaling, physics sanity cases, PlasmaPy comparison
docs/validation.md Physics test descriptions and tolerances
docs/gui.md Deck launcher workflow
docs/limitations.md Honest constraints and known gaps

License

MIT — see LICENSE.


Citation

If you use prad in published work, please cite:

@software{dolezal2026prad,
  author       = {Dolezal, Jonas},
  title        = {{prad}: {GPU}-accelerated relativistic proton radiography},
  year         = {2026},
  version      = {0.3.0},
  url          = {https://github.com/JonasDolezal07/gpu-proton-radiography},
  license      = {MIT},
}

A CITATION.cff file is also provided for automated citation tooling (GitHub "Cite this repository").

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

prad-0.3.1-py3-none-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

prad-0.3.1-py3-none-macosx_10_13_universal2.whl (3.2 MB view details)

Uploaded Python 3macOS 10.13+ universal2 (ARM64, x86-64)

File details

Details for the file prad-0.3.1-py3-none-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: prad-0.3.1-py3-none-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 4.8 MB
  • Tags: Python 3, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for prad-0.3.1-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 77c059917323dfbad3379e53b242d0a35a332430a8869c2e4876700f4fd87c11
MD5 bda1fb05bc7c3f759051ea3610a34192
BLAKE2b-256 792f8a22f22470b91c55ab500dbb3be9245ef7c35015b476cd98595fa14b7e7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for prad-0.3.1-py3-none-manylinux_2_28_x86_64.whl:

Publisher: release.yml on JonasDolezal07/gpu-proton-radiography

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prad-0.3.1-py3-none-macosx_10_13_universal2.whl.

File metadata

  • Download URL: prad-0.3.1-py3-none-macosx_10_13_universal2.whl
  • Upload date:
  • Size: 3.2 MB
  • Tags: Python 3, macOS 10.13+ universal2 (ARM64, x86-64)
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for prad-0.3.1-py3-none-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 049b54e269b3e404edab3b3b4cbb3cb6d8a15759513b26fd6c6b46554cb58147
MD5 b07c55d3a84855ad1c61524a4dc51ca3
BLAKE2b-256 45a7763a79eca09ce478cd0db1d79a15ba0127357a353c2cb4a13209abd61c18

See more details on using hashes here.

Provenance

The following attestation bundles were made for prad-0.3.1-py3-none-macosx_10_13_universal2.whl:

Publisher: release.yml on JonasDolezal07/gpu-proton-radiography

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page