CudaNufftPipeline¶
class CudaNufftPipeline
Full GPU NUFFT pipeline — all intermediates stay on-device.
Both chains fold the centered-DFT fftshift/ifftshift into the index arithmetic of the kernel that already touches the grid on that side of the FFT, mirroring the Metal backend's Phase 2 fold (see MetalNufftPipeline.mm's nufft_forward_impl/nufft_adjoint_impl). There are no standalone shift kernel launches in either chain below — each arrow that would otherwise be a circshift pass is a shift baked into the adjacent kernel's read or write index instead:
Forward (image → k-space): deapodize → zero_pad(+ifftshift write) → cuFFT → gridding_forward(+fftshift read)
Adjoint (k-space → image): gridding_adjoint(+ifftshift write) → cuIFFT → crop_center(+fftshift read) → deapodize
Write-side folds (zero_pad, gridding_adjoint scatter) apply the shift as-is to the destination index; gather-side folds (gridding_forward, crop_center) apply the inverted offset (dim − s) % dim to the source index, computed at the call site in forward_device()/adjoint_device().
kernel_circshift_2d/3d (CudaNufftPipeline.cu) remain defined — the pipeline itself no longer dispatches them, but they stay available for any external caller that still wants a standalone circular shift.
Only input and output cross the PCIe bus (one cudaMemcpy each direction).
Functions¶
| Name | Description |
|---|---|
| forward | Forward NUFFT: host pointers (copies H2D and D2H) |
| adjoint | Adjoint NUFFT: host pointers (copies H2D and D2H) |
| forward_device | Forward NUFFT: device pointers (no transfers — data stays on GPU) |
| adjoint_device | Adjoint NUFFT: device pointers (no transfers — data stays on GPU) |
| forward_device_batched | Batched forward NUFFT: numBatch independent transforms through one batched cuFFT plan + batched support/gridding kernel launches. Device layout mirrors CudaDftPipeline's batched contract: slice b's image lives at d_imagesIn + b2imageNumElems (interleaved complex, contiguous), slice b's samples at d_samplesOut + b2numSamples. numBatch == 1 is legal but forward_device() is the direct path for that case. |
| adjoint_device_batched | Batched adjoint NUFFT: numBatch independent transforms, contiguous per-slice device layout (see forward_device_batched). Slice b's samples at d_samplesIn + b2numSamples, slice b's image output at d_imagesOut + b2imageNumElems. |
Function Details¶
adjoint¶
void adjoint(const float* samplesIn, float* imageOut)
Adjoint NUFFT: host pointers (copies H2D and D2H)
adjoint_device¶
void adjoint_device(const float* d_samplesIn, float* d_imageOut)
Adjoint NUFFT: device pointers (no transfers — data stays on GPU)
adjoint_device_batched¶
void adjoint_device_batched(const float* d_samplesIn, float* d_imagesOut, int numBatch)
Batched adjoint NUFFT: numBatch independent transforms, contiguous per-slice device layout (see forward_device_batched). Slice b's samples at d_samplesIn + b2numSamples, slice b's image output at d_imagesOut + b2imageNumElems.
forward¶
void forward(const float* imageIn, float* samplesOut)
Forward NUFFT: host pointers (copies H2D and D2H)
forward_device¶
void forward_device(const float* d_imageIn, float* d_samplesOut)
Forward NUFFT: device pointers (no transfers — data stays on GPU)
forward_device_batched¶
void forward_device_batched(const float* d_imagesIn, float* d_samplesOut, int numBatch)
Batched forward NUFFT: numBatch independent transforms through one batched cuFFT plan + batched support/gridding kernel launches.
Device layout mirrors CudaDftPipeline's batched contract: slice b's image lives at d_imagesIn + b2imageNumElems (interleaved complex, contiguous), slice b's samples at d_samplesOut + b2numSamples. numBatch == 1 is legal but forward_device() is the direct path for that case.