bartorch.linop.FieldCorrected#
- bartorch.linop.FieldCorrected(encoding, field_map=None, readout_time=None, *, mask=None, segments=-1, method='svd', coefficients=None)#
An encoding with off-resonance during the readout, by time segmentation.
A voxel off resonance by
faccrues a phaseexp(-i 2 pi f t)by the timetof each sample, so the exact operator is a different transform per sample and no transform at all in the usual sense. Time segmentation approximates it as a short sum of ordinary encodings, each with a spatial weight before it and a sample weight after:A = sum_l diag(b_l) . E . diag(c_l)which is
linop_plusoverlinop_chain: one BART operator, whateverEis. So this wraps any encoding –CartesianSense(),WaveSense(), orNoncartesianSense– and the last of those is what mirtorch callsGmri.The coefficients are
mri-nufft’s: the fit is a least-squares problem over a histogram of the field map, not something BART has a primitive for and not something to write twice.- Parameters:
encoding (LinearOperator) – The encoding without off-resonance.
field_map (tensor) – Off-resonance in Hz, broadcastable to the encoding’s domain.
readout_time (tensor) – When each sample is taken, in seconds, broadcastable to the encoding’s codomain. Reciprocal units to
field_map.mask (tensor, optional) – Where the field map is meaningful; everywhere by default. The fit weights the histogram by it, so a mask that excludes air spends the segments on tissue. A map with a single value under the mask is refused: there is nothing to segment, and the correction is one phase.
segments (int) – How many terms the sum has.
-1letsmri-nufftchoose from the spread of the field map and the readout length.method (str) –
"svd","mti"or"mfi",mri-nufft’s three factorizations.coefficients (tuple of tensor, optional) –
(b, c)already computed, of shapes(L, *codomain)and(L, *domain)up to broadcasting. Given these, nothing is fitted andfield_mapis not needed.
Notes
The normal operator is the sum applied twice rather than anything cheaper: a segmented encoding has no Toeplitz form, because the spatial weights do not commute with the transform. More segments is a better approximation and proportionally more work.
Examples
>>> E = CartesianSense(maps, (coils, y, x), pattern=mask) >>> A = FieldCorrected(E, b0_hz, readout_time=times, segments=6)