Getting Started

BasisSimulator.jl runs on Julia 1.11+ and is GPU-backend-agnostic. Pick the backend that matches your hardware (Metal for Apple Silicon, CUDA for NVIDIA, AMDGPU for AMD, oneAPI for Intel), or omit it entirely to run on CPU.

Install

From the Julia REPL:

using Pkg
Pkg.add(url="https://github.com/MolloiLab/BasisSimulator.jl")

Then add GPUSelect and your GPU backend (skip the backend for CPU-only):

Pkg.add("GPUSelect")
Pkg.add("Metal")     # Apple Silicon
Pkg.add("CUDA")      # NVIDIA
Pkg.add("AMDGPU")    # AMD
Pkg.add("oneAPI")    # Intel

First simulation

The five-struct API maps to the five things every CT simulation needs to specify: what to scan, the scanner, the acquisition, simulation fidelity, and the reconstruction output.

import BasisSimulator as BS
import GPUSelect

AT = GPUSelect.Storage()  # MtlArray / CuArray / ROCArray / oneArray / Array
to_gpu(x) = AT(x)

# 1. Phantom — labeled mask + materials dict + voxel size
phantom_cpu = BS.create_gammex_472(n_voxels=256)
phantom = BS.Phantom(to_gpu(phantom_cpu.mask),
                     phantom_cpu.materials,
                     phantom_cpu.voxel_size)

# 2. Scanner — geometry, source, detector, filtration
scanner = BS.Scanner(
    source_to_isocenter = 626.0,
    source_to_detector  = 1097.0,
    detector_rows       = 64,
    detector_cols       = 832,
    detector_row_size   = 0.625,
    detector_col_size   = 1.053,
)

# 3. Protocol — kVp, mA, views, rotation time
protocol = BS.CTProtocol(kVp=120.0, mA=200.0, views=984, rotation_time=0.5)

# 4. SimOptions — physics fidelity preset (:eict | :pcct)
sim_opts = BS.SimOptions(fidelity=:eict, seed=42)

# 5. ReconOptions — output matrix and physical grid extent
rec_opts = BS.ReconOptions(matrix_size=(512, 512, 64), fov_cm=35.0)

Allocate a workspace once and reuse it on subsequent calls — simulate! writes into pre-allocated buffers and runs zero-allocation after JIT warm-up.

ws = BS.create_eict_workspace(scanner, protocol, sim_opts, rec_opts, phantom)
BS.simulate!(ws, phantom, protocol, sim_opts)

bhc = BS.calibrate_bhc_water(sim_opts, protocol; scanner=scanner, geom=ws.geom)
sino_bhc = to_gpu(BS.apply_bhc_water(ws.sinogram, bhc))
ws_fdk = BS.create_fdk_recon_workspace(sino_bhc, ws.geom, rec_opts.matrix_size)
hu = BS.to_hounsfield(
    Array(BS.reconstruct!(ws_fdk, sino_bhc, ws.geom));
    μ_water = bhc.μ_water_ref,
)

What's next

Worked examples covering the five-struct API, dual-kVp VMI, PCCT, XCAT phantoms, and a CatSim runtime comparison live on the Examples page. The full API reference is at API.