pub fn run_field_mapping(
phases: &[&[f64]],
magnitudes: Option<&[&[f64]]>,
mask: &[u8],
metadata: &ScanMetadata,
config: &FieldMappingConfig,
progress: &mut dyn FnMut(usize, usize),
) -> Result<FieldMappingResult, PipelineError>Expand description
Run field mapping: convert per-echo phase data to a B0 field map in ppm.
§Arguments
phases- Per-echo wrapped phase arrays (in [-pi, pi])magnitudes- Per-echo magnitude arrays (optional; uniform weights if None)mask- Binary brain maskmetadata- Scan metadata (dims, voxel size, echo times in seconds, field strength)config- Field mapping configurationprogress- Progress callback (current_step, total_steps)
§Returns
FieldMappingResult with B0 field in ppm and optional phase offset
§UK Biobank’s field map
On offset-free echoes (e.g. MCPC-3D-S coil-combined), Laplacian unwrapping with
laplacian_solver: LaplacianSolver::Fft { pad: [64; 3] } and
b0_estimation: B0EstimationMethod::WeightedAvg { weighting: B0WeightType::AssumedDecay { t2star_s: 0.040 } }
reproduces the UK Biobank QSM pipeline’s field map: STI Suite’s MRPhaseUnwrap(mask .* φ)
per echo, then Σ Wφ / Σ W·TE with W = TE·exp(−TE/T2*). It matches up to a global
constant (each echo’s masked mean is removed before combining, see the direct path below),
to ≈1e-14 rad in the combined phase on in-vivo two-echo data.
use qsm_core::pipeline::{B0EstimationMethod, FieldMappingConfig, UnwrappingAlgorithm};
use qsm_core::unwrap::LaplacianSolver;
use qsm_core::utils::B0WeightType;
let ukb = FieldMappingConfig {
unwrapping_algorithm: UnwrappingAlgorithm::Laplacian,
laplacian_solver: LaplacianSolver::Fft { pad: [64; 3] },
b0_estimation: B0EstimationMethod::WeightedAvg {
weighting: B0WeightType::assumed_decay_default(),
},
..Default::default()
};§MEDI’s field map
B0EstimationMethod::ComplexFit runs MEDI’s Fit_ppm_complex on the wrapped complex echoes,
unwraps the fitted phase per echo spacing spatially with unwrapping_algorithm, and divides
by the echo spacing. It needs magnitudes and evenly spaced echoes, and also returns the
field’s noise map in FieldMappingResult::field_noise_ppm (MEDI’s N_std), and the fit
before unwrapping in FieldMappingResult::complex_fit (MEDI’s iFreq_raw and N_std, in
radians per echo spacing):
use qsm_core::fieldmap::FitPpmComplexParams;
use qsm_core::pipeline::{B0EstimationMethod, FieldMappingConfig};
let medi = FieldMappingConfig {
b0_estimation: B0EstimationMethod::ComplexFit(FitPpmComplexParams::default()),
..Default::default()
};§Motion-robust echo combination
B0EstimationMethod::RobustFit combines the echoes with
multi_echo_robust_fit on whichever path runs, so it
composes with ROMEO and Laplacian unwrapping and with phase-offset removal on or off. It
needs RobustFitParams::min_echoes echoes or
more (fewer is PipelineError::InvalidConfig) and returns its per-echo report in
FieldMappingResult::robust_fit:
use qsm_core::pipeline::{B0EstimationMethod, FieldMappingConfig};
use qsm_core::utils::RobustFitParams;
let robust = FieldMappingConfig {
b0_estimation: B0EstimationMethod::RobustFit(RobustFitParams::default()),
..Default::default()
};