1use rayon::iter::IntoParallelIterator;
2use timsrust_utils::{
3 custom_error,
4 reader::{IndexedReader, Reader},
5};
6use crate::{Intensity, IntensityIndex, Mz, TofIndex, coordinates::Converter};
9
10use super::{AcquisitionType, QuadrupoleSettings};
11use rayon::prelude::*;
12use std::sync::Arc;
13
14#[derive(Clone, Debug, Default, PartialEq)]
16pub struct Frame {
17 ions: FrameIons,
18 info: FrameInfo,
19}
20
21impl Frame {
22 pub fn get_corrected_intensity(&self, index: usize) -> f64 {
23 let v = u32::from(self.ions.intensities[index]) as f64;
24 self.info.intensity_correction_factor * v
25 }
26
27 pub fn info(&self) -> &FrameInfo {
28 &self.info
29 }
30
31 pub fn ions(&self) -> &FrameIons {
32 &self.ions
33 }
34
35 pub fn set_data(
36 &mut self,
37 scan_offsets: Vec<usize>,
38 tof_indices: Vec<TofIndex>,
39 intensities: Vec<IntensityIndex>,
40 ) {
41 self.ions = FrameIons::new(scan_offsets, tof_indices, intensities);
42 }
43
44 pub fn set_ions(&mut self, ions: FrameIons) {
45 self.ions = ions;
46 }
47
48 pub fn set_info(&mut self, info: FrameInfo) {
49 self.info = info;
50 }
51
52 pub fn len(&self) -> usize {
53 self.ions.intensities.len()
54 }
55
56 pub fn is_empty(&self) -> bool {
57 self.ions.is_empty()
58 }
59
60 pub fn index(&self) -> usize {
61 self.info().index
62 }
63}
64
65#[derive(Debug, PartialEq, Default, Clone, Copy)]
67pub enum MSLevel {
68 MS1,
69 MS2,
70 #[default]
72 Unknown,
73}
74
75impl MSLevel {
76 pub fn read_from_msms_type(msms_type: u8) -> MSLevel {
77 match msms_type {
78 0 => MSLevel::MS1,
79 8 => MSLevel::MS2,
80 9 => MSLevel::MS2,
81 _ => MSLevel::Unknown,
82 }
83 }
84}
85
86#[derive(Clone, Debug, PartialEq, Default)]
87pub struct FrameIons {
88 scan_offsets: Vec<usize>,
89 tof_indices: Vec<TofIndex>,
90 intensities: Vec<IntensityIndex>,
91}
92
93impl FrameIons {
94 pub fn new(
95 scan_offsets: Vec<usize>,
96 tof_indices: Vec<TofIndex>,
97 intensities: Vec<IntensityIndex>,
98 ) -> Self {
99 Self {
100 scan_offsets,
101 tof_indices,
102 intensities,
103 }
104 }
105
106 pub fn is_empty(&self) -> bool {
107 self.intensities.is_empty()
108 }
109
110 pub fn scan_offsets(&self) -> &Vec<usize> {
111 &self.scan_offsets
112 }
113
114 pub fn tof_indices(&self) -> &Vec<TofIndex> {
115 &self.tof_indices
116 }
117
118 pub fn mz_values<C: Converter<TofIndex, Mz>>(
119 &self,
120 converter: &C,
121 ) -> Vec<Mz> {
122 converter.batch_convert(&self.tof_indices)
123 }
124
125 pub fn intensities(&self) -> &Vec<IntensityIndex> {
126 &self.intensities
127 }
128
129 pub fn intensity_values<C: Converter<IntensityIndex, Intensity>>(
130 &self,
131 converter: &C,
132 ) -> Vec<Intensity> {
133 converter.batch_convert(&self.intensities)
134 }
135
136 pub fn read_scan(
137 &self,
138 scan_index: usize,
139 ) -> impl Iterator<Item = (TofIndex, IntensityIndex)> + '_ {
140 let (start, end) = if scan_index >= self.scan_count() {
141 (0, 0)
142 } else {
143 (
144 self.scan_offsets[scan_index],
145 self.scan_offsets[scan_index + 1],
146 )
147 };
148 (start..end).map(move |index| {
149 (self.tof_indices[index], self.intensities[index])
150 })
151 }
152
153 pub fn scan_count(&self) -> usize {
154 self.scan_offsets.len() - 1
155 }
156
157 pub fn add_info(self, info: FrameInfo) -> Frame {
158 Frame { ions: self, info }
159 }
160}
161
162#[derive(Clone, Debug, Default, PartialEq)]
163pub struct FrameInfo {
164 quadrupole_settings: Arc<QuadrupoleSettings>,
165 index: usize,
166 rt_in_seconds: f64,
167 intensity_correction_factor: f64,
168 acquisition_type: AcquisitionType,
169 ms_level: MSLevel,
170 window_group: u8,
171 cycle_index: Option<usize>,
172}
173
174impl FrameInfo {
175 #[allow(clippy::too_many_arguments)]
176 pub fn new(
177 quadrupole_settings: Arc<QuadrupoleSettings>,
178 index: usize,
179 rt_in_seconds: f64,
180 intensity_correction_factor: f64,
181 acquisition_type: AcquisitionType,
182 ms_level: MSLevel,
183 window_group: u8,
184 cycle_index: Option<usize>,
185 ) -> Self {
186 Self {
187 quadrupole_settings,
188 index,
189 rt_in_seconds,
190 intensity_correction_factor,
191 acquisition_type,
192 ms_level,
193 window_group,
194 cycle_index,
195 }
196 }
197
198 pub fn quadrupole_settings(&self) -> &Arc<QuadrupoleSettings> {
199 &self.quadrupole_settings
200 }
201
202 pub fn index(&self) -> usize {
203 self.index
204 }
205
206 pub fn cycle_index(&self) -> Option<usize> {
207 self.cycle_index
208 }
209
210 pub fn rt_in_seconds(&self) -> f64 {
211 self.rt_in_seconds
212 }
213
214 pub fn intensity_correction_factor(&self) -> f64 {
215 self.intensity_correction_factor
216 }
217
218 pub fn acquisition_type(&self) -> AcquisitionType {
219 self.acquisition_type
220 }
221
222 pub fn ms_level(&self) -> MSLevel {
223 self.ms_level
224 }
225
226 pub fn window_group(&self) -> u8 {
227 self.window_group
228 }
229
230 pub fn add_ions(self, ions: FrameIons) -> Frame {
231 Frame { ions, info: self }
232 }
233}
234#[derive(Debug)]
235pub struct FrameReader<IonReader, InfoReader> {
236 ion_reader: IonReader,
237 info_reader: InfoReader,
238}
239
240impl<IonReader, InfoReader> FrameReader<IonReader, InfoReader>
241where
242 IonReader: Reader<FrameIons>,
243 InfoReader: Reader<FrameInfo> + IndexedReader<FrameInfo>,
244{
245 pub fn new(ion_reader: IonReader, info_reader: InfoReader) -> Self {
246 Self {
247 ion_reader,
248 info_reader,
249 }
250 }
251
252 pub fn ion_reader(&self) -> &IonReader {
253 &self.ion_reader
254 }
255
256 pub fn info_reader(&self) -> &InfoReader {
257 &self.info_reader
258 }
259
260 pub fn ion_reader_index(
261 &self,
262 index: usize,
263 ) -> Result<usize, FrameReaderError> {
264 Ok(index)
265 }
266
267 pub fn info_reader_index(
268 &self,
269 index: usize,
270 ) -> Result<usize, FrameReaderError> {
271 Ok(index)
272 }
273
274 pub fn get_ions(
275 &self,
276 index: usize,
277 ) -> Result<FrameIons, FrameReaderError> {
278 let index = self.ion_reader_index(index)?;
279 let result = self
280 .ion_reader()
281 .get(index)
282 .map_err(|e| FrameReaderError::new(e.to_string()))?;
283 Ok(result)
284 }
285
286 pub fn get_info(
287 &self,
288 index: usize,
289 ) -> Result<FrameInfo, FrameReaderError> {
290 let index = self.info_reader_index(index)?;
291 let result = self
292 .info_reader()
293 .get(index)
294 .map_err(|e| FrameReaderError::new(e.to_string()))?;
295 Ok(result)
296 }
297
298 pub fn get_frame(&self, index: usize) -> Result<Frame, FrameReaderError> {
299 let info = self.get_info(index)?;
300 let ions = self.get_ions(index)?;
301 let mut frame = Frame::default();
302 frame.set_ions(ions);
303 frame.set_info(info);
304 Ok(frame)
305 }
306
307 pub fn get_partial_frame_without_ions(
309 &self,
310 index: usize,
311 ) -> Result<Frame, FrameReaderError> {
312 let info = self.get_info(index)?;
313 let mut frame = Frame::default();
314 frame.set_info(info);
315 Ok(frame)
316 }
317
318 pub fn len(&self) -> usize {
319 self.iter_indices().count()
320 }
321
322 pub fn is_empty(&self) -> bool {
323 self.len() == 0
324 }
325
326 pub fn iter_indices(&self) -> impl Iterator<Item = usize> {
331 self.info_reader().iter()
332 }
333
334 pub fn filter<'a, F: Fn(&Frame) -> bool + Sync + Send + 'a>(
335 &'a self,
336 predicate: F,
337 ) -> impl Iterator<Item = Result<Frame, FrameReaderError>> {
338 self.iter_indices().filter_map(move |x| {
339 match self.info_reader().get(x) {
340 Ok(frame_info) => {
341 let mut partial_frame = Frame::default();
342 partial_frame.set_info(frame_info);
343 if predicate(&partial_frame) {
344 let ions = self.get_ions(x).ok()?;
345 partial_frame.set_ions(ions);
346 Some(Ok(partial_frame))
347 } else {
348 None
349 }
350 },
351 Err(e) => Some(Err(FrameReaderError::new(e.to_string()))),
352 }
353 })
354 }
355
356 pub fn parallel_filter<'a, F: Fn(&Frame) -> bool + Sync + Send + 'a>(
357 &'a self,
358 predicate: F,
359 ) -> impl ParallelIterator<Item = Result<Frame, FrameReaderError>> + 'a
360 where
361 Self: Sync + Send + 'a,
362 {
363 self.iter_indices()
364 .collect::<Vec<_>>()
365 .into_par_iter()
366 .filter_map(move |x| match self.info_reader().get(x) {
367 Ok(frame_info) => {
368 let mut partial_frame = Frame::default();
369 partial_frame.set_info(frame_info);
370 if predicate(&partial_frame) {
371 let ions = self.get_ions(x).ok()?;
372 partial_frame.set_ions(ions);
373 Some(Ok(partial_frame))
374 } else {
375 None
376 }
377 },
378 Err(e) => Some(Err(FrameReaderError::new(e.to_string()))),
379 })
380 }
381}
382
383custom_error!(pub FrameReaderError);