use std::path::PathBuf;
use koth_ms::{
config::KothConfig, group_ms2_hills_by_window, run_pipeline, run_pipeline_streaming,
run_pipeline_with_ms2, Feature, Hill, IsolationWindow, PipelineOptions, PipelineSink,
ScoredFeature,
};
fn uno_style(path: &std::path::Path, config: &KothConfig) {
let out = run_pipeline(path, config, &PipelineOptions::default()).expect("pipeline");
let searchable: Vec<&ScoredFeature> = out
.features
.iter()
.filter(|f| f.feature.charge > 0) .collect();
println!(
"[uno] {} hills, {} charged features available for MS1 search",
out.hills.len(),
searchable.len()
);
if let Some(top) = searchable.iter().max_by(|a, b| {
a.feature
.total_intensity()
.partial_cmp(&b.feature.total_intensity())
.unwrap()
}) {
println!(
"[uno] most intense: mass {:?} z{} score {:.3}",
top.monoisotopic_neutral_mass(koth_ms::Polarity::Positive),
top.feature.charge,
top.combined_score
);
}
}
#[derive(Default)]
struct TracerSink {
hills: Vec<Hill>, n_features: usize,
total_intensity: f64,
}
impl PipelineSink for TracerSink {
fn on_hills(&mut self, hills: Vec<Hill>) {
println!("[tracer] indexing {} finalized hills", hills.len());
self.hills = hills;
}
fn on_feature(&mut self, feature: ScoredFeature) {
let f: &Feature = &feature.feature;
self.total_intensity += f.total_intensity();
self.n_features += 1;
}
}
fn tracer_style(path: &std::path::Path, config: &KothConfig) {
let mut sink = TracerSink::default();
run_pipeline_streaming(path, config, &PipelineOptions::default(), &mut sink)
.expect("streaming pipeline");
println!(
"[tracer] streamed {} features (sum intensity {:.3e}) over {} indexed hills",
sink.n_features,
sink.total_intensity,
sink.hills.len()
);
}
fn tracer_with_ms2(path: &std::path::Path, config: &KothConfig) {
let out = run_pipeline_with_ms2(path, config, &PipelineOptions::default())
.expect("pipeline with ms2");
let windows: Vec<(IsolationWindow, Vec<Hill>)> = group_ms2_hills_by_window(out.ms2_hills);
println!(
"[tracer+ms2] {} MS1 features, {} DIA isolation windows",
out.features.len(),
windows.len()
);
for f in out.features.iter().filter(|f| f.feature.charge > 0).take(3) {
let mz = f.feature.monoisotopic_mz(); let isolating: Vec<&(IsolationWindow, Vec<Hill>)> = windows
.iter()
.filter(|(w, _)| w.lower <= mz && mz <= w.upper)
.collect();
let n_frag: usize = isolating.iter().map(|(_, hs)| hs.len()).sum();
println!(
"[tracer+ms2] precursor m/z {:.4} z{} -> {} window(s), {} candidate fragment hills",
mz,
f.feature.charge,
isolating.len(),
n_frag
);
}
}
fn main() {
let path: PathBuf = std::env::args()
.nth(1)
.map(PathBuf::from)
.expect("usage: streaming_api <input.mzML | input.d>");
let config = KothConfig::default();
tracer_style(&path, &config);
uno_style(&path, &config);
tracer_with_ms2(&path, &config);
}