use std::fs::File;
use std::io::BufWriter;
use openmassspec_core::{
write_indexed_mzml, write_mzml, Activation, Analyzer, CvTerm, MobilityArrayKind, MsPower,
Polarity, PrecursorInfo, RunMetadata, ScanMode, SpectrumRecord, SpectrumSource,
};
struct SampleSource {
meta: RunMetadata,
spectra: Vec<SpectrumRecord>,
cursor: usize,
}
impl SampleSource {
fn new() -> Self {
let meta = RunMetadata {
source_file_name: "sample.raw".into(),
source_file_format: CvTerm::new("MS:1000563", "Thermo RAW format"),
native_id_format: CvTerm::new("MS:1000768", "Thermo nativeID format"),
instrument: CvTerm::new("MS:1001911", "Q Exactive"),
software_name: "openmassspec-core-sample".into(),
software_version: env!("CARGO_PKG_VERSION").into(),
start_timestamp: None,
mobility_array_kind: Some(MobilityArrayKind::InverseReducedVsPerCm2),
};
let ms1 = SpectrumRecord {
index: 0,
scan_number: 1,
native_id: "controllerType=0 controllerNumber=1 scan=1".into(),
ms_level: MsPower::Ms1.ms_level(),
polarity: Some(Polarity::Positive),
scan_mode: Some(ScanMode::Centroid),
analyzer: Some(Analyzer::FTMS),
filter: Some("FTMS + p ESI Full ms".into()),
retention_time_sec: 0.123 * 60.0,
total_ion_current: None,
base_peak_mz: None,
base_peak_intensity: None,
low_mz: None,
high_mz: None,
ion_injection_time_ms: Some(20.0),
inv_mobility: None,
precursor: None,
mz: vec![100.0, 200.0, 300.0],
intensity: vec![1.0, 5.0, 2.0],
inv_mobility_per_peak: None,
};
let ms2 = SpectrumRecord {
index: 1,
scan_number: 2,
native_id: "controllerType=0 controllerNumber=1 scan=2".into(),
ms_level: MsPower::Ms2.ms_level(),
polarity: Some(Polarity::Positive),
scan_mode: Some(ScanMode::Centroid),
analyzer: Some(Analyzer::FTMS),
filter: Some("FTMS + p ESI d Full ms2 200.00@hcd28.00".into()),
retention_time_sec: 0.5 * 60.0,
total_ion_current: Some(123.45),
base_peak_mz: Some(150.5),
base_peak_intensity: Some(99.0),
low_mz: Some(100.0),
high_mz: Some(180.0),
ion_injection_time_ms: Some(50.0),
inv_mobility: None,
precursor: Some(PrecursorInfo {
target_mz: Some(200.0),
selected_mz: Some(200.001),
isolation_width: Some(2.0),
charge: Some(2),
intensity: None,
collision_energy: Some(28.0),
ce_is_nce: true,
precursor_native_id: Some("controllerType=0 controllerNumber=1 scan=1".into()),
activation: Some(Activation::CID),
analyzer: Some(Analyzer::FTMS),
}),
mz: vec![150.5, 160.0],
intensity: vec![99.0, 50.0],
inv_mobility_per_peak: None,
};
let ms1_mobility = SpectrumRecord {
index: 2,
scan_number: 3,
native_id: "frame=1 scan=0".into(),
ms_level: MsPower::Ms1.ms_level(),
polarity: Some(Polarity::Positive),
scan_mode: Some(ScanMode::Centroid),
analyzer: Some(Analyzer::TOFMS),
filter: None,
retention_time_sec: 0.75 * 60.0,
total_ion_current: None,
base_peak_mz: None,
base_peak_intensity: None,
low_mz: None,
high_mz: None,
ion_injection_time_ms: None,
inv_mobility: Some(0.95),
precursor: None,
mz: vec![120.0, 240.0, 360.0],
intensity: vec![3.0, 7.0, 4.0],
inv_mobility_per_peak: Some(vec![0.92, 0.95, 0.98]),
};
Self {
meta,
spectra: vec![ms1, ms2, ms1_mobility],
cursor: 0,
}
}
}
impl SpectrumSource for SampleSource {
fn run_metadata(&self) -> RunMetadata {
self.meta.clone()
}
fn iter_spectra<'a>(&'a mut self) -> Box<dyn Iterator<Item = SpectrumRecord> + 'a> {
self.cursor = 0;
Box::new(std::iter::from_fn(move || {
let rec = self.spectra.get(self.cursor).cloned();
if rec.is_some() {
self.cursor += 1;
}
rec
}))
}
fn spectrum_count_hint(&self) -> Option<usize> {
Some(self.spectra.len())
}
}
fn main() -> std::io::Result<()> {
let mut args = std::env::args().skip(1);
let plain_path = args.next().unwrap_or_else(|| "sample_plain.mzML".into());
let indexed_path = args.next().unwrap_or_else(|| "sample_indexed.mzML".into());
let mut src = SampleSource::new();
let mut plain = BufWriter::new(File::create(&plain_path)?);
write_mzml(&mut src, &mut plain)
.map_err(|e| std::io::Error::other(format!("write_mzml: {e}")))?;
let mut indexed = BufWriter::new(File::create(&indexed_path)?);
write_indexed_mzml(&mut src, &mut indexed)
.map_err(|e| std::io::Error::other(format!("write_indexed_mzml: {e}")))?;
eprintln!("wrote {plain_path} and {indexed_path}");
Ok(())
}