Skip to main content

Feature

Struct Feature 

Source
pub struct Feature {
    pub hills: Vec<Hill>,
    pub charge: u8,
    pub cosine_score: f64,
    pub ppm_error: f64,
}
Expand description

A detected isotope feature: a group of hills forming an isotope envelope.

hills are sorted by mz (monoisotopic first). charge == 0 means unknown charge (single peak, no isotope partners found).

Fields§

§hills: Vec<Hill>§charge: u8§cosine_score: f64

Mean chromatographic cosine similarity (in scan/RT space) between adjacent isotope hills in the chain. Bounded [0, 1]. Measures whether the isotope hills co-elute in time — not whether their intensities match an averagine pattern.

§ppm_error: f64

Implementations§

Source§

impl Feature

Source

pub fn monoisotopic_hill(&self) -> &Hill

Source

pub fn monoisotopic_mz(&self) -> f64

Examples found in repository?
examples/streaming_api.rs (line 126)
108fn tracer_with_ms2(path: &std::path::Path, config: &KothConfig) {
109    // `run_pipeline_with_ms2` forces MS2 emission on; equivalently, set
110    // `PipelineOptions { emit_ms2: true, ..Default::default() }` on any entry.
111    let out = run_pipeline_with_ms2(path, config, &PipelineOptions::default())
112        .expect("pipeline with ms2");
113
114    // Group the flat MS2 hill set into DIA channels (each hill already carries
115    // its window in `hill.isolation_window`; this is just the convenience view).
116    let windows: Vec<(IsolationWindow, Vec<Hill>)> = group_ms2_hills_by_window(out.ms2_hills);
117    println!(
118        "[tracer+ms2] {} MS1 features, {} DIA isolation windows",
119        out.features.len(),
120        windows.len()
121    );
122
123    // Precursor -> window mapping: a precursor feature is isolated by every
124    // window whose [lower, upper] contains its (charge-1) precursor m/z.
125    for f in out.features.iter().filter(|f| f.feature.charge > 0).take(3) {
126        let mz = f.feature.monoisotopic_mz(); // precursor m/z of the feature
127        let isolating: Vec<&(IsolationWindow, Vec<Hill>)> = windows
128            .iter()
129            .filter(|(w, _)| w.lower <= mz && mz <= w.upper)
130            .collect();
131        let n_frag: usize = isolating.iter().map(|(_, hs)| hs.len()).sum();
132        println!(
133            "[tracer+ms2]   precursor m/z {:.4} z{} -> {} window(s), {} candidate fragment hills",
134            mz,
135            f.feature.charge,
136            isolating.len(),
137            n_frag
138        );
139    }
140}
Source

pub fn faims_cv(&self) -> Option<f32>

FAIMS compensation voltage of this feature, inherited from its monoisotopic hill. Feature assembly guarantees all member hills share this value.

Source

pub fn monoisotopic_neutral_mass(&self, polarity: Polarity) -> Option<f64>

Neutral monoisotopic mass, undoing polarity’s adduct (mz·z ∓ z·proton).

Source

pub fn rt_apex(&self) -> f64

Examples found in repository?
examples/lfq_member_geometry.rs (line 66)
8fn main() -> anyhow::Result<()> {
9    let args: Vec<_> = std::env::args().skip(1).collect();
10    anyhow::ensure!(
11        args.len() == 5,
12        "usage: lfq_member_geometry BATCH CONFIG MEMBERS_TSV OUT_TSV ID,ID"
13    );
14    let cfg = AlignConfig::from_toml(&PathBuf::from(&args[1]))?;
15    let paths = discover_runs(&PathBuf::from(&args[0]))?;
16    let runs: Vec<_> = paths
17        .iter()
18        .map(|r| {
19            Ok(RunInput {
20                name: r.name.clone(),
21                features: read_features(&r.features_path)?,
22                hills: Vec::new(),
23                scan_times: Vec::new(),
24                rt_bounds: None,
25            })
26        })
27        .collect::<anyhow::Result<_>>()?;
28    check_batch_mobility_scales(
29        paths
30            .iter()
31            .zip(&runs)
32            .map(|(p, r)| (p, r.features.as_slice())),
33    )?;
34    let alignment = align_runs(&runs, &cfg.alignment);
35    let ids: HashSet<usize> = args[4]
36        .split(',')
37        .map(str::parse)
38        .collect::<Result<_, _>>()?;
39    let mut input = csv::ReaderBuilder::new()
40        .delimiter(b'\t')
41        .from_path(&args[2])?;
42    let mut output = csv::WriterBuilder::new()
43        .delimiter(b'\t')
44        .from_path(&args[3])?;
45    output.write_record([
46        "candidate_id",
47        "run_id",
48        "feature_idx",
49        "mass",
50        "rt",
51        "im",
52        "quality",
53        "is_primary",
54        "neutron_offset",
55    ])?;
56    for row in input.records() {
57        let row = row?;
58        let id: usize = row[0].parse()?;
59        if !ids.contains(&id) {
60            continue;
61        }
62        let r: usize = row[1].parse()?;
63        let f: usize = row[2].parse()?;
64        let feat = &runs[r].features[f];
65        let mz = feat.monoisotopic_mz();
66        let rt = feat.feature.rt_apex();
67        let im = feat.feature.im_apex();
68        let (mz, rt, im) = if r == alignment.reference_idx {
69            (mz, rt, im)
70        } else {
71            let a = &alignment.alignments[&runs[r].name];
72            (a.correct_mz(mz, rt), a.warp_rt(rt), a.correct_im(im, rt))
73        };
74        let mass = (mz - 1.007276466621) * feat.feature.charge as f64;
75        output.write_record([
76            id.to_string(),
77            r.to_string(),
78            f.to_string(),
79            mass.to_string(),
80            rt.to_string(),
81            im.to_string(),
82            feat.combined_score.to_string(),
83            row[3].to_string(),
84            feat.neutron_offset.to_string(),
85        ])?;
86    }
87    output.flush()?;
88    Ok(())
89}
Source

pub fn rt_start(&self) -> f64

Source

pub fn rt_end(&self) -> f64

Source

pub fn im_apex(&self) -> f64

Examples found in repository?
examples/lfq_member_geometry.rs (line 67)
8fn main() -> anyhow::Result<()> {
9    let args: Vec<_> = std::env::args().skip(1).collect();
10    anyhow::ensure!(
11        args.len() == 5,
12        "usage: lfq_member_geometry BATCH CONFIG MEMBERS_TSV OUT_TSV ID,ID"
13    );
14    let cfg = AlignConfig::from_toml(&PathBuf::from(&args[1]))?;
15    let paths = discover_runs(&PathBuf::from(&args[0]))?;
16    let runs: Vec<_> = paths
17        .iter()
18        .map(|r| {
19            Ok(RunInput {
20                name: r.name.clone(),
21                features: read_features(&r.features_path)?,
22                hills: Vec::new(),
23                scan_times: Vec::new(),
24                rt_bounds: None,
25            })
26        })
27        .collect::<anyhow::Result<_>>()?;
28    check_batch_mobility_scales(
29        paths
30            .iter()
31            .zip(&runs)
32            .map(|(p, r)| (p, r.features.as_slice())),
33    )?;
34    let alignment = align_runs(&runs, &cfg.alignment);
35    let ids: HashSet<usize> = args[4]
36        .split(',')
37        .map(str::parse)
38        .collect::<Result<_, _>>()?;
39    let mut input = csv::ReaderBuilder::new()
40        .delimiter(b'\t')
41        .from_path(&args[2])?;
42    let mut output = csv::WriterBuilder::new()
43        .delimiter(b'\t')
44        .from_path(&args[3])?;
45    output.write_record([
46        "candidate_id",
47        "run_id",
48        "feature_idx",
49        "mass",
50        "rt",
51        "im",
52        "quality",
53        "is_primary",
54        "neutron_offset",
55    ])?;
56    for row in input.records() {
57        let row = row?;
58        let id: usize = row[0].parse()?;
59        if !ids.contains(&id) {
60            continue;
61        }
62        let r: usize = row[1].parse()?;
63        let f: usize = row[2].parse()?;
64        let feat = &runs[r].features[f];
65        let mz = feat.monoisotopic_mz();
66        let rt = feat.feature.rt_apex();
67        let im = feat.feature.im_apex();
68        let (mz, rt, im) = if r == alignment.reference_idx {
69            (mz, rt, im)
70        } else {
71            let a = &alignment.alignments[&runs[r].name];
72            (a.correct_mz(mz, rt), a.warp_rt(rt), a.correct_im(im, rt))
73        };
74        let mass = (mz - 1.007276466621) * feat.feature.charge as f64;
75        output.write_record([
76            id.to_string(),
77            r.to_string(),
78            f.to_string(),
79            mass.to_string(),
80            rt.to_string(),
81            im.to_string(),
82            feat.combined_score.to_string(),
83            row[3].to_string(),
84            feat.neutron_offset.to_string(),
85        ])?;
86    }
87    output.flush()?;
88    Ok(())
89}
Source

pub fn total_intensity(&self) -> f64

Examples found in repository?
examples/streaming_api.rs (line 48)
30fn uno_style(path: &std::path::Path, config: &KothConfig) {
31    // One call, everything owned in memory. No files touched.
32    let out = run_pipeline(path, config, &PipelineOptions::default()).expect("pipeline");
33
34    // uno searches MS1 features by neutral mass + charge + RT.
35    let searchable: Vec<&ScoredFeature> = out
36        .features
37        .iter()
38        .filter(|f| f.feature.charge > 0) // same set the features file would hold
39        .collect();
40
41    println!(
42        "[uno] {} hills, {} charged features available for MS1 search",
43        out.hills.len(),
44        searchable.len()
45    );
46    if let Some(top) = searchable.iter().max_by(|a, b| {
47        a.feature
48            .total_intensity()
49            .partial_cmp(&b.feature.total_intensity())
50            .unwrap()
51    }) {
52        println!(
53            "[uno]   most intense: mass {:?} z{} score {:.3}",
54            top.monoisotopic_neutral_mass(koth_ms::Polarity::Positive),
55            top.feature.charge,
56            top.combined_score
57        );
58    }
59}
60
61// ---------------------------------------------------------------------------
62// koth_tracer-style consumer: take ownership of the hill set to build a trace
63// index, then fold features incrementally without holding the whole vector.
64// ---------------------------------------------------------------------------
65#[derive(Default)]
66struct TracerSink {
67    hills: Vec<Hill>, // owned once, up front — used to trace precursor<->fragment
68    n_features: usize,
69    total_intensity: f64,
70}
71
72impl PipelineSink for TracerSink {
73    fn on_hills(&mut self, hills: Vec<Hill>) {
74        // koth_tracer indexes the finalized hill set here (m/z, RT, IM) so it
75        // can attribute fragment hills to precursor features as they arrive.
76        println!("[tracer] indexing {} finalized hills", hills.len());
77        self.hills = hills;
78    }
79
80    fn on_feature(&mut self, feature: ScoredFeature) {
81        // Consume-and-drop: fold each feature into whatever the tracer keeps.
82        // The full feature vector is never materialized on the consumer side.
83        let f: &Feature = &feature.feature;
84        self.total_intensity += f.total_intensity();
85        self.n_features += 1;
86        // `feature` is dropped here, freeing its memory before the next arrives.
87    }
Source

pub fn n_scans_total(&self) -> usize

Source

pub fn elution_profile(&self) -> (usize, usize, Vec<f64>)

Combined elution profile: sum of all isotope hill intensities per scan. Returns (min_scan, max_scan, profile_vec).

Source

pub fn total_intensity_at_apex(&self) -> f64

Total intensity at the apex scan (summed across all isotope hills).

Source

pub fn apex_scan(&self) -> usize

Apex scan index: scan where the sum of all isotope hill intensities is highest.

Source

pub fn isotope_profile_apex(&self) -> Vec<f64>

Isotope profile at the apex scan: one intensity per hill.

Source

pub fn mono_scan_list(&self) -> Vec<usize>

Scan list for monoisotopic hill.

Source

pub fn mono_intensity_list(&self) -> &[f32]

Intensity list for monoisotopic hill.

Trait Implementations§

Source§

impl Clone for Feature

Source§

fn clone(&self) -> Feature

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Feature

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more