pub enum FansiKernel {
Discrete,
Continuous,
}Expand description
The dipole kernel a FANSI-family solver (NDI, nlTV, nlTGV, L1-QSM, WH-QSM, HD-QSM) uses.
FANSI’s solvers take the kernel as an input (params.K), and every FANSI script, like the
QSM-CI wrappers of the verified originals (FANSI-toolbox 93044a3, HD-QSM c456a94), builds it
with dipole_kernel_angulated(N, voxel_size, B0_dir), whose default mode = 1 is the
discrete kernel FansiKernel::Discrete. HDQSM.m ships no kernel and is “based on” FANSI;
its wrapper uses the same function. The discrete kernel is consistent with the unit
forward differences these solvers regularise with (both come from the same E_j).
Decision (Ashley, 2026-11-02; QSM.rs#399–#403): the FANSI-family ports use FANSI’s own
discrete kernel by default, as the originals do; the continuous kernel the rest of the crate
uses is kept as an option. Measured with the continuous kernel against the verified originals
(QSM-CI parity run 41384710780, sim / KKI χ NRMSE): NDI 10.6 / 9.5 %, nlTV 11.0 / 9.5 %,
nlTGV 11.0 / 9.6 %, L1-QSM 14.4 / 15.5 %, WH-QSM 21.4 / 50.7 %, HD-QSM 9.1 / 7.1 %; a numpy
transcription of ndi.m on the original’s own inputs is 0.0001 % from it with the discrete
kernel and 10.6 % with the continuous one.
With the discrete kernel every pair is at rounding (each method’s module docs, “Parity”). The
phantom measurements quoted in the methods’ te docs were re-measured with the discrete kernel
(QSM.rs#418); the echo-time choices they support did not change.
Variants§
Discrete
FANSI’s dipole_kernel_angulated mode 1 (FANSI-toolbox 93044a3): the kernel of unit
forward differences, E_j = (1 - exp(2*pi*i*k_j/N_j)) / r_j with the voxel size r
normalised by its maximum, D = 1/3 - |sum_j E_j*b_j|^2 / sum_j |E_j|^2, D(0) = 0
(fansi_dipole_kernel).
Continuous
The continuous kernel 1/3 - (k.b)^2/|k|^2 of [crate::kernels::dipole::dipole_kernel]
(dipole_kernel_angulated mode 0 up to its k normalisation).
Implementations§
Trait Implementations§
Source§impl Clone for FansiKernel
impl Clone for FansiKernel
Source§fn clone(&self) -> FansiKernel
fn clone(&self) -> FansiKernel
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for FansiKernel
Source§impl Debug for FansiKernel
impl Debug for FansiKernel
Source§impl Default for FansiKernel
impl Default for FansiKernel
Source§fn default() -> FansiKernel
fn default() -> FansiKernel
impl Eq for FansiKernel
Source§impl PartialEq for FansiKernel
impl PartialEq for FansiKernel
Source§impl Serialize for FansiKernel
impl Serialize for FansiKernel
impl StructuralPartialEq for FansiKernel
Auto Trait Implementations§
impl Freeze for FansiKernel
impl RefUnwindSafe for FansiKernel
impl Send for FansiKernel
impl Sync for FansiKernel
impl Unpin for FansiKernel
impl UnsafeUnpin for FansiKernel
impl UnwindSafe for FansiKernel
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
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.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