Skip to main content

run_field_mapping

Function run_field_mapping 

Source
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 mask
  • metadata - Scan metadata (dims, voxel size, echo times in seconds, field strength)
  • config - Field mapping configuration
  • progress - 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()
};