1use std::fs::File;
12use std::io::BufWriter;
13
14use openmassspec_core::{
15 write_indexed_mzml, write_mzml, Activation, Analyzer, CvTerm, MobilityArrayKind, MsPower,
16 Polarity, PrecursorInfo, RunMetadata, ScanMode, SpectrumRecord, SpectrumSource,
17};
18
19struct SampleSource {
20 meta: RunMetadata,
21 spectra: Vec<SpectrumRecord>,
22 cursor: usize,
23}
24
25impl SampleSource {
26 fn new() -> Self {
27 let meta = RunMetadata {
28 source_file_name: "sample.raw".into(),
29 source_file_format: CvTerm::new("MS:1000563", "Thermo RAW format"),
30 native_id_format: CvTerm::new("MS:1000768", "Thermo nativeID format"),
31 instrument: CvTerm::new("MS:1001911", "Q Exactive"),
32 software_name: "openmassspec-core-sample".into(),
33 software_version: env!("CARGO_PKG_VERSION").into(),
34 start_timestamp: None,
35 mobility_array_kind: Some(MobilityArrayKind::InverseReducedVsPerCm2),
36 };
37 let ms1 = SpectrumRecord {
38 index: 0,
39 scan_number: 1,
40 native_id: "controllerType=0 controllerNumber=1 scan=1".into(),
41 ms_level: MsPower::Ms1.ms_level(),
42 polarity: Some(Polarity::Positive),
43 scan_mode: Some(ScanMode::Centroid),
44 analyzer: Some(Analyzer::FTMS),
45 filter: Some("FTMS + p ESI Full ms".into()),
46 retention_time_sec: 0.123 * 60.0,
47 total_ion_current: None,
48 base_peak_mz: None,
49 base_peak_intensity: None,
50 low_mz: None,
51 high_mz: None,
52 ion_injection_time_ms: Some(20.0),
53 inv_mobility: None,
54 precursor: None,
55 mz: vec![100.0, 200.0, 300.0],
56 intensity: vec![1.0, 5.0, 2.0],
57 inv_mobility_per_peak: None,
58 };
59 let ms2 = SpectrumRecord {
60 index: 1,
61 scan_number: 2,
62 native_id: "controllerType=0 controllerNumber=1 scan=2".into(),
63 ms_level: MsPower::Ms2.ms_level(),
64 polarity: Some(Polarity::Positive),
65 scan_mode: Some(ScanMode::Centroid),
66 analyzer: Some(Analyzer::FTMS),
67 filter: Some("FTMS + p ESI d Full ms2 200.00@hcd28.00".into()),
68 retention_time_sec: 0.5 * 60.0,
69 total_ion_current: Some(123.45),
70 base_peak_mz: Some(150.5),
71 base_peak_intensity: Some(99.0),
72 low_mz: Some(100.0),
73 high_mz: Some(180.0),
74 ion_injection_time_ms: Some(50.0),
75 inv_mobility: None,
76 precursor: Some(PrecursorInfo {
77 target_mz: Some(200.0),
78 selected_mz: Some(200.001),
79 isolation_width: Some(2.0),
80 charge: Some(2),
81 intensity: None,
82 collision_energy: Some(28.0),
83 ce_is_nce: true,
84 precursor_native_id: Some("controllerType=0 controllerNumber=1 scan=1".into()),
85 activation: Some(Activation::CID),
86 analyzer: Some(Analyzer::FTMS),
87 }),
88 mz: vec![150.5, 160.0],
89 intensity: vec![99.0, 50.0],
90 inv_mobility_per_peak: None,
91 };
92 let ms1_mobility = SpectrumRecord {
97 index: 2,
98 scan_number: 3,
99 native_id: "frame=1 scan=0".into(),
100 ms_level: MsPower::Ms1.ms_level(),
101 polarity: Some(Polarity::Positive),
102 scan_mode: Some(ScanMode::Centroid),
103 analyzer: Some(Analyzer::TOFMS),
104 filter: None,
105 retention_time_sec: 0.75 * 60.0,
106 total_ion_current: None,
107 base_peak_mz: None,
108 base_peak_intensity: None,
109 low_mz: None,
110 high_mz: None,
111 ion_injection_time_ms: None,
112 inv_mobility: Some(0.95),
113 precursor: None,
114 mz: vec![120.0, 240.0, 360.0],
115 intensity: vec![3.0, 7.0, 4.0],
116 inv_mobility_per_peak: Some(vec![0.92, 0.95, 0.98]),
117 };
118 Self {
119 meta,
120 spectra: vec![ms1, ms2, ms1_mobility],
121 cursor: 0,
122 }
123 }
124}
125
126impl SpectrumSource for SampleSource {
127 fn run_metadata(&self) -> RunMetadata {
128 self.meta.clone()
129 }
130
131 fn iter_spectra<'a>(&'a mut self) -> Box<dyn Iterator<Item = SpectrumRecord> + 'a> {
132 self.cursor = 0;
133 Box::new(std::iter::from_fn(move || {
134 let rec = self.spectra.get(self.cursor).cloned();
135 if rec.is_some() {
136 self.cursor += 1;
137 }
138 rec
139 }))
140 }
141
142 fn spectrum_count_hint(&self) -> Option<usize> {
143 Some(self.spectra.len())
144 }
145}
146
147fn main() -> std::io::Result<()> {
148 let mut args = std::env::args().skip(1);
149 let plain_path = args.next().unwrap_or_else(|| "sample_plain.mzML".into());
150 let indexed_path = args.next().unwrap_or_else(|| "sample_indexed.mzML".into());
151
152 let mut src = SampleSource::new();
153 let mut plain = BufWriter::new(File::create(&plain_path)?);
154 write_mzml(&mut src, &mut plain)
155 .map_err(|e| std::io::Error::other(format!("write_mzml: {e}")))?;
156
157 let mut indexed = BufWriter::new(File::create(&indexed_path)?);
158 write_indexed_mzml(&mut src, &mut indexed)
159 .map_err(|e| std::io::Error::other(format!("write_indexed_mzml: {e}")))?;
160
161 eprintln!("wrote {plain_path} and {indexed_path}");
162 Ok(())
163}