GPU-portable polychromatic CT simulator in Julia. Runs on Metal, CUDA, ROCm, oneAPI, or CPU via AcceleratedKernels.jl. Models energy-integrating and photon-counting detectors, single- and dual-kVp acquisitions, and reconstructs with FBP (FDK), OS-PWLS iterative reconstruction, and material-basis VMI.
using Pkg
Pkg.add(url="https://github.com/MolloiLab/BasisSimulator.jl")For portable device selection, add GPUSelect plus your backend:
Pkg.add("GPUSelect")
Pkg.add("Metal") # Apple Silicon
Pkg.add("CUDA") # NVIDIA
Pkg.add("AMDGPU") # AMD
Pkg.add("oneAPI") # Intelimport BasisSimulator as BS
import GPUSelect
AT = GPUSelect.Storage() # MtlArray / CuArray / ROCArray / oneArray / Array
to_gpu(x) = AT(x)
phantom_cpu = BS.create_gammex_472(n_voxels=256)
phantom = BS.Phantom(to_gpu(phantom_cpu.mask),
phantom_cpu.materials,
phantom_cpu.voxel_size)
scanner = BS.Scanner(
source_to_isocenter = 626.0, # mm
source_to_detector = 1097.0,
detector_rows = 64,
detector_cols = 832,
detector_row_size = 0.625,
detector_col_size = 1.053,
)
protocol = BS.CTProtocol(kVp=120.0, mA=200.0, views=984)
sim_opts = BS.SimOptions(fidelity=:eict)
rec_opts = BS.ReconOptions(matrix_size=(512, 512, 64), fov_cm=35.0)
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,
)SimOptions(; projector=:dd_fast) uses the fastest general-purpose projector
and is the default. Its single-pass distance-driven kernels are anti-aliased
and robust in severe beam-hardened regions while outperforming both the legacy
:dd path and :siddon for full polychromatic and spectral simulations.
:siddon remains available for comparison and compatibility, but its
point-sampled rays can alias in those regions. If you reconstruct iteratively,
pass the same projector to create_hir_recon_workspace(; projector=…) so the IR
system matrix matches the data — FDK reconstruction is unaffected.
Full API reference, getting-started guide, and eleven worked-example notebooks:
https://molloilab.github.io/BasisSimulator.jl/. Docstrings are also
available via ?Function in the Julia REPL.
MIT. Core ray tracing ported from TIGRE; calibration workflow follows CatSim/XCIST.