โ—† FORGE Suite
GitHubMechanical Neuroimaging Lab ยท Univ. of Delaware
Skip to content

pcSenseTimeSeg

template <typename T1> class pcSenseTimeSeg

Phase-corrected multi-shot SENSE with time-segmented field-map correction.

Combines per-shot phase correction (pcSENSE) with time-segmented off-resonance correction (TimeSegmentation), providing accurate forward and adjoint models for multi-shot non-Cartesian acquisitions with significant \(B_0\) inhomogeneity. This is the full model for techniques such as multi-shot spiral DWI.

The combined forward model applies shot-varying phase correction and time-segmented field correction together:

\[\mathbf{d}_{c,s} = A_s(P_s \circ S_c \circ \mathbf{x})\]

where \(A_s\) is the time-segmented NUFFT operator for shot \(s\) (which incorporates the off-resonance field map \(\omega(\mathbf{r})\)), \(P_s = e^{i\phi_s(\mathbf{r})}\) is the shot-specific phase map, and \(S_c\) is the coil sensitivity map.

When to use: - Use this operator when both shot-varying phase correction AND off-resonance field correction are needed (e.g., multi-shot spiral diffusion-weighted imaging). - If only phase correction is needed (short readouts, minimal off-resonance), use pcSENSE instead. - If only field correction is needed (single-shot acquisition with off-resonance), use TimeSegmentation wrapping SENSE.

pcSenseTimeSeg<float> P(kx, ky, kz, Nx, Ny, Nz, nc, tvec,
                         L, interpType, SENSEmap, fieldMap,
                         shotPhaseMap);
Col<cx_float> kdata = P * image;   // forward
Col<cx_float> recon = P / kdata;   // adjoint

See : pcSENSE

See : TimeSegmentation

See : SENSE

T1 : Floating-point precision type (float or double).

Variables

Name Description
Nd Number of k-space samples per shot.
Ni Number of image pixels.
Nc Number of receiver coils.
Ns Number of shots.
SMap Coil sensitivity maps, size Ni x Nc.
PMap Per-shot phase maps in radians, size Ni x Ns.
FMap Off-resonance field map (rad/s), length Ni.
Kx k-space x-coordinates, size (samples/shot) x Ns.
Ky k-space y-coordinates, size (samples/shot) x Ns.
Kz k-space z-coordinates, size (samples/shot) x Ns.
Tvec Readout time vector (s), size (samples/shot) x Ns.
Nx Image size in x.
Ny Image size in y.
Nz Image size in z.
Ix Image-space x-coordinates, length Ni.
Iy Image-space y-coordinates, length Ni.
Iz Image-space z-coordinates, length Ni.
i Imaginary unit constant for phase computations.
type Interpolation type: 1 = Hanning, 2 = min-max.
L Number of time segments for field-map correction.
shotSpecificSenseMap Shot-specific combined (sensitivity x phase) maps, size Ni x (Nc*Ns).
conjShotSpecificSenseMap Conjugate shot-specific maps, size Ni x (Nc*Ns).
coilChunk Coils per batched pipeline call (memory-aware; see forge_metal_coil_chunk).
shotSenseMapCols Persistent page-aligned combined (sensitivity x shot-phase) maps, one forgeCol of length Ni per (shot, coil), [shot][coil] layout: index jjNc + coil. This layout (rather than shotSpecificSenseMap's native jj + coilNs column order) makes a coil chunk within one shot contiguous, matching TimeSegmentation::forwardBatchedWeighted's mapFirst..mapFirst+count window. Standalone forgeCol allocations (not forgeMat::col() views), so every entry is independently page-aligned for zero-copy Metal dispatch.
conjShotSenseMapCols Conjugate counterpart of shotSenseMapCols (adjoint weighting), same [shot][coil] layout.
adjSliceBufs Persistent page-aligned per-coil k-space slice buffers for the batched adjoint gather (coilChunk buffers of length Nd, reused across PCG iterations and shots).
shotSenseMap_gpu Per-shot combined sensitivity+phase maps, pre-uploaded to GPU (Ns*Nc vectors).
conjShotSenseMap_gpu Conjugate per-shot maps for adjoint, pre-uploaded to GPU.
coilChunk Coils per batched TimeSegmentation call.
cudaFwdStack Persistent CUDA scratch for operatoroperator/(forgeCol), sized to coilChunk (the per-call coil batch) and allocated once in the constructor, then reused by every PCG iteration instead of being cudaMallocAsync'd/cudaFreeAsync'd per call -- see cuda/c4-shared-batching Task 3b.

Operators

Name Description
operator* Forward transform: image -> k-space with phase and field-map correction. d : Input image vector of length Ni. Return : Stacked k-space vector of length NdNsNc.
operator/ Adjoint transform: k-space -> image with phase and field-map correction. d : Input k-space vector of length NdNsNc. Return : Output image vector of length Ni.
operator* Forward transform (forgeCol overload for Metal path).
operator/ Adjoint transform (forgeCol overload for Metal path).

Functions

Name Description
pcSenseTimeSeg Default constructor.
~pcSenseTimeSeg Destructor โ€” frees per-shot NUFFT and TimeSegmentation operator arrays.
pcSenseTimeSeg Array of per-shot NUFFT operator pointers.

Variable Details

FMap

Col<T1> FMap

Off-resonance field map (rad/s), length Ni.

Ix

Col<T1> Ix

Image-space x-coordinates, length Ni.

Iy

Col<T1> Iy

Image-space y-coordinates, length Ni.

Iz

Col<T1> Iz

Image-space z-coordinates, length Ni.

Kx

Mat<T1> Kx

k-space x-coordinates, size (samples/shot) x Ns.

Ky

Mat<T1> Ky

k-space y-coordinates, size (samples/shot) x Ns.

Kz

Mat<T1> Kz

k-space z-coordinates, size (samples/shot) x Ns.

L

uword L

Number of time segments for field-map correction.

Nc

uword Nc

Number of receiver coils.

Nd

uword Nd

Number of k-space samples per shot.

Ni

uword Ni

Number of image pixels.

Ns

uword Ns

Number of shots.

Nx

uword Nx

Image size in x.

Ny

uword Ny

Image size in y.

Nz

uword Nz

Image size in z.

PMap

Mat<T1> PMap

Per-shot phase maps in radians, size Ni x Ns.

SMap

Mat<CxT1> SMap

Coil sensitivity maps, size Ni x Nc.

Tvec

Mat<T1> Tvec

Readout time vector (s), size (samples/shot) x Ns.

adjSliceBufs

mutable std::vector<forgeCol<forgeComplex<T1>>> adjSliceBufs

Persistent page-aligned per-coil k-space slice buffers for the batched adjoint gather (coilChunk buffers of length Nd, reused across PCG iterations and shots).

coilChunk

uword coilChunk

Coils per batched pipeline call (memory-aware; see forge_metal_coil_chunk).

coilChunk

uword coilChunk

Coils per batched TimeSegmentation call. Default (single-slice, the C2-era behavior): always 1. Opt-in via FORGE_CUDA_BATCHED_OPERATORS=1 (see cuda_batched_operators_enabled() in pcSenseTimeSeg.cpp): the memory-aware chunk size from forge_cuda_coil_chunk.

conjShotSenseMapCols

std::vector<forgeCol<forgeComplex<T1>>> conjShotSenseMapCols

Conjugate counterpart of shotSenseMapCols (adjoint weighting), same [shot][coil] layout.

conjShotSenseMap_gpu

std::vector<forgeCol<forgeComplex<T1>>> conjShotSenseMap_gpu

Conjugate per-shot maps for adjoint, pre-uploaded to GPU.

conjShotSpecificSenseMap

Mat<CxT1> conjShotSpecificSenseMap

Conjugate shot-specific maps, size Ni x (Nc*Ns).

cudaFwdStack

mutable forgeCol<forgeComplex<T1>> cudaFwdStack

Persistent CUDA scratch for operatoroperator/(forgeCol), sized to coilChunk (the per-call coil batch) and allocated once in the constructor, then reused by every PCG iteration instead of being cudaMallocAsync'd/cudaFreeAsync'd per call -- see cuda/c4-shared-batching Task 3b.

i

CxT1 i

Imaginary unit constant for phase computations.

shotSenseMapCols

std::vector<forgeCol<forgeComplex<T1>>> shotSenseMapCols

Persistent page-aligned combined (sensitivity x shot-phase) maps, one forgeCol of length Ni per (shot, coil), [shot][coil] layout: index jjNc + coil. This layout (rather than shotSpecificSenseMap's native jj + coilNs column order) makes a coil chunk within one shot contiguous, matching TimeSegmentation::forwardBatchedWeighted's mapFirst..mapFirst+count window. Standalone forgeCol allocations (not forgeMat::col() views), so every entry is independently page-aligned for zero-copy Metal dispatch.

shotSenseMap_gpu

std::vector<forgeCol<forgeComplex<T1>>> shotSenseMap_gpu

Per-shot combined sensitivity+phase maps, pre-uploaded to GPU (Ns*Nc vectors).

shotSpecificSenseMap

Mat<CxT1> shotSpecificSenseMap

Shot-specific combined (sensitivity x phase) maps, size Ni x (Nc*Ns).

type

uword type

Interpolation type: 1 = Hanning, 2 = min-max.

Operator Details

operator*

Col<CxT1> operator*(const Col<CxT1>& d) const

Forward transform: image -> k-space with phase and field-map correction.

d : Input image vector of length Ni.

Return : Stacked k-space vector of length NdNsNc.

forgeCol<forgeComplex<T1>> operator*(const forgeCol<forgeComplex<T1>>& d) const

Forward transform (forgeCol overload for Metal path).

d : Input image vector of length Ni.

Return : Stacked k-space vector of length NdNsNc.

operator/

Col<CxT1> operator/(const Col<CxT1>& d) const

Adjoint transform: k-space -> image with phase and field-map correction.

d : Input k-space vector of length NdNsNc.

Return : Output image vector of length Ni.

forgeCol<forgeComplex<T1>> operator/(const forgeCol<forgeComplex<T1>>& d) const

Adjoint transform (forgeCol overload for Metal path).

d : Input k-space vector of length NdNsNc.

Return : Output image vector of length Ni.

Function Details

pcSenseTimeSeg

pcSenseTimeSeg()

Default constructor.

pcSenseTimeSeg(Col<T1> kx, Col<T1> ky, Col<T1> kz, uword nx, uword ny, uword nz, uword nc, Col<T1> t, uword L, uword intType, Col<CxT1> SENSEmap, Col<T1> FieldMap, Col<T1> ShotPhaseMap, T1 gridOS = (T1)1.6)

Array of per-shot NUFFT operator pointers. Array of per-shot TimeSegmentation operator pointers. Construct a phase-corrected SENSE+time-segmentation operator.

kx : k-space x-coordinates (all shots), length Nd*Ns.

ky : k-space y-coordinates, length Nd*Ns.

kz : k-space z-coordinates, length Nd*Ns.

nx : Image size in x.

ny : Image size in y.

nz : Image size in z.

nc : Number of receiver coils.

t : Per-sample readout time (s), length Nd*Ns.

L : Number of time segments.

intType : Interpolation type: 1 = Hanning, 2 = min-max.

SENSEmap : Sensitivity maps, flat vector length Ni*Nc.

FieldMap : Off-resonance field map (rad/s), length Ni.

ShotPhaseMap : Per-shot phase maps (rad), length Ni*Ns.

gridOS : NUFFT grid oversampling factor (default 1.6, set by the post-fftshift-fold FFT-size study: fastest OS that passes both the operator-level <1% qualification bar and end-to-end NRMSE parity vs the former OS 2.0 default). Sizes with only factors of 2 and 3 run fastest on the Metal MPSGraph FFT (radix-5 sizes are slower).

~pcSenseTimeSeg

~pcSenseTimeSeg()

Destructor โ€” frees per-shot NUFFT and TimeSegmentation operator arrays.