pub struct L1QsmParams {
pub alpha1: f64,
pub mu1: Option<f64>,
pub mu2: f64,
pub mu3: f64,
pub lambda: f64,
pub max_iter: usize,
pub tol_update: f64,
pub tol_delta: f64,
pub b0: f64,
pub echo_times: Vec<f64>,
pub te: EchoTime,
pub kernel: FansiKernel,
}Expand description
L1-QSM algorithm parameters (FANSI nlL1TV.m defaults where it has them).
Fields§
§alpha1: f64Gradient (TV) L1 penalty weight. nlL1TV.m gives no default, and FANSI’s example says L1-QSM needs its own tuning. The default 5e-3 was chosen from an alpha1 sweep on the EMTP travelling-head data: 2e-4 streaks, 1e-2 starts to oversmooth.
mu1: Option<f64>Gradient-consistency ADMM weight; None is nlL1TV.m’s 100 * alpha1.
mu2: f64Fidelity-consistency ADMM weight.
mu3: f64L1 proximal ADMM weight.
lambda: f64Phase-rejection strength: the data weight is lambda times the normalised
magnitude. Smaller values reject more inconsistent voxels. Default 0.8, the value of
FANSI’s in-vivo demo (script_DICOM_Philips.m l. 445-447: lambda = 0.8; params.weight = lambda*params.weight/max(params.weight(:))); nlL1TV.m itself has no
default (“recommended = lambda*magnitude_data”, l. 18-19). QSM.rs previously used 1.0.
Measured against 1.0 (ROMEO field, default V-SHARP): on the qsm-forward phantom χ XSIM
0.338 → 0.339, NRMSE 78.2 → 78.1 % (on its true local field 0.808 → 0.809, NRMSE
38.8 → 39.2 %); on an in-vivo 3T Philips scan, agreement with the UK Biobank pipeline’s χ
XSIM 0.446 → 0.461, NRMSE 103.0 → 97.7 %.
max_iter: usizeNumber of outer ADMM iterations.
tol_update: f64Percent-update convergence stopping tolerance.
tol_delta: f64Inner Newton convergence tolerance.
b0: f64Field strength in Tesla (scan parameter, for the radian conversion)
echo_times: Vec<f64>Echo times in seconds, in acquisition order (scan parameter, for the radian conversion).
te: EchoTimeWhich echo time the radian conversion uses. Default EchoTime::First. FANSI’s
multi-echo example, script_DICOM_Philips.m, scales the field by deltaTE = TE(echo2) - TE(echo1) (FANSI-toolbox 93044a3, line 364) before nlL1TV (line 450), and its comment
on that line says “You may use also any individual echo time”. On the qsm-forward phantom
(echoes 4/12/20/28 ms; FANSI’s discrete kernel, measured for QSM.rs#418 with the integration tests’ settings; XSIM / NRMSE / r), the magnitude weight at the first
echo does best (0.776 / 38.9% / 0.923), against 0.764 / 46.9% / 0.889 at the echo
spacing. (With the continuous kernel, #276: 0.782 / 37.4% / 0.928 against 0.776 / 40.2% /
0.916.)
The magnitude weight is required, although nlL1TV.m weights by ones when given none
(lines 109-113): with a flat weight L1-QSM is worse on that phantom (0.767 / 42.0% / 0.912
at the first echo, 0.763 / 43.1% / 0.906 at the spacing). With the continuous kernel the
flat weight’s NRMSE exceeded 100% at either echo time (0.738 / 108% / 0.636 at the first
echo, #276).
kernel: FansiKernelThe dipole kernel. Default FansiKernel::Discrete, FANSI’s
dipole_kernel_angulated as the original is run with; FansiKernel::Continuous is
the crate’s continuous kernel (see FansiKernel for the decision and the measurements).
Trait Implementations§
Source§impl Clone for L1QsmParams
impl Clone for L1QsmParams
Source§fn clone(&self) -> L1QsmParams
fn clone(&self) -> L1QsmParams
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for L1QsmParams
impl Debug for L1QsmParams
Source§impl Default for L1QsmParams
impl Default for L1QsmParams
Auto Trait Implementations§
impl Freeze for L1QsmParams
impl RefUnwindSafe for L1QsmParams
impl Send for L1QsmParams
impl Sync for L1QsmParams
impl Unpin for L1QsmParams
impl UnsafeUnpin for L1QsmParams
impl UnwindSafe for L1QsmParams
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T> CloneAny for T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more