1use crate::data::meta::{read_global_meta_sql, read_meta_data_sql, FrameMeta, GlobalMetaData};
2use crate::data::raw::BrukerTimsDataLibrary;
3use crate::data::utility::{
4 flatten_scan_values, parse_decompressed_bruker_binary_data, zstd_decompress,
5};
6use byteorder::{LittleEndian, ReadBytesExt};
7use mscore::data::spectrum::MsType;
8use mscore::timstof::frame::{ImsFrame, RawTimsFrame, TimsFrame};
9use mscore::timstof::slice::TimsSlice;
10use std::fs::File;
11use std::io::{Cursor, Read, Seek, SeekFrom};
12use std::path::PathBuf;
13
14use crate::data::acquisition::AcquisitionMode;
15use rayon::prelude::*;
16use rayon::ThreadPoolBuilder;
17
18use std::error::Error;
19
20fn lzf_decompress(data: &[u8], max_output_size: usize) -> Result<Vec<u8>, Box<dyn Error>> {
21 let decompressed_data = lzf::decompress(data, max_output_size)
22 .map_err(|e| format!("LZF decompression failed: {}", e))?;
23 Ok(decompressed_data)
24}
25
26fn parse_decompressed_bruker_binary_type1(
27 decompressed_bytes: &[u8],
28 scan_indices: &mut [i64],
29 tof_indices: &mut [u32],
30 intensities: &mut [u16],
31 scan_start: usize,
32 scan_index: usize,
33) -> usize {
34 let int_count = decompressed_bytes.len() / 4;
36 let buffer =
37 unsafe { std::slice::from_raw_parts(decompressed_bytes.as_ptr() as *const i32, int_count) };
38
39 let mut tof_index = 0i32;
40 let mut previous_was_intensity = true;
41 let mut current_index = scan_start;
42
43 for &value in buffer {
44 if value >= 0 {
45 if previous_was_intensity {
47 tof_index += 1;
48 }
49 tof_indices[current_index] = tof_index as u32;
50 intensities[current_index] = value as u16;
51 previous_was_intensity = true;
52 current_index += 1;
53 } else {
54 tof_index -= value; previous_was_intensity = false;
57 }
58 }
59
60 let scan_size = current_index - scan_start;
61 scan_indices[scan_index] = scan_size as i64;
62 scan_size
63}
64
65pub struct TimsRawDataLayout {
66 pub raw_data_path: String,
67 pub global_meta_data: GlobalMetaData,
68 pub frame_meta_data: Vec<FrameMeta>,
69 pub max_scan_count: i64,
70 pub frame_id_ptr: Vec<i64>,
71 pub tims_offset_values: Vec<i64>,
72 pub acquisition_mode: AcquisitionMode,
73}
74
75impl TimsRawDataLayout {
76 pub fn new(data_path: &str) -> Self {
77 let global_meta_data = read_global_meta_sql(data_path).unwrap();
79 let frame_meta_data = read_meta_data_sql(data_path).unwrap();
80
81 let max_scan_count = frame_meta_data.iter().map(|x| x.num_scans).max().unwrap();
83
84 let mut frame_id_ptr: Vec<i64> = Vec::new();
85 frame_id_ptr.resize(frame_meta_data.len() + 1, 0);
86
87 for (i, row) in frame_meta_data.iter().enumerate() {
89 frame_id_ptr[i + 1] = row.num_peaks + frame_id_ptr[i];
90 }
91
92 let tims_offset_values = frame_meta_data
94 .iter()
95 .map(|x| x.tims_id)
96 .collect::<Vec<i64>>();
97
98 let acquisition_mode = match frame_meta_data[0].scan_mode {
100 8 => AcquisitionMode::DDA,
101 9 => AcquisitionMode::DIA,
102 _ => AcquisitionMode::Unknown,
103 };
104
105 TimsRawDataLayout {
106 raw_data_path: data_path.to_string(),
107 global_meta_data,
108 frame_meta_data,
109 max_scan_count,
110 frame_id_ptr,
111 tims_offset_values,
112 acquisition_mode,
113 }
114 }
115}
116
117pub trait TimsData {
118 fn get_frame(&self, frame_id: u32) -> TimsFrame;
119 fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame;
120 fn get_slice(&self, frame_ids: Vec<u32>, num_threads: usize) -> TimsSlice;
121 fn get_acquisition_mode(&self) -> AcquisitionMode;
122 fn get_frame_count(&self) -> i32;
123 fn get_data_path(&self) -> &str;
124}
125
126pub trait IndexConverter {
127 fn tof_to_mz(&self, frame_id: u32, tof_values: &Vec<u32>) -> Vec<f64>;
128 fn mz_to_tof(&self, frame_id: u32, mz_values: &Vec<f64>) -> Vec<u32>;
129 fn scan_to_inverse_mobility(&self, frame_id: u32, scan_values: &Vec<u32>) -> Vec<f64>;
130 fn inverse_mobility_to_scan(
131 &self,
132 frame_id: u32,
133 inverse_mobility_values: &Vec<f64>,
134 ) -> Vec<u32>;
135}
136
137pub struct BrukerLibTimsDataConverter {
138 pub bruker_lib: BrukerTimsDataLibrary,
139}
140
141impl BrukerLibTimsDataConverter {
142 pub fn new(bruker_lib_path: &str, data_path: &str) -> Self {
143 let bruker_lib = BrukerTimsDataLibrary::new(bruker_lib_path, data_path).unwrap();
144 BrukerLibTimsDataConverter { bruker_lib }
145 }
146}
147impl IndexConverter for BrukerLibTimsDataConverter {
148 fn tof_to_mz(&self, frame_id: u32, tof: &Vec<u32>) -> Vec<f64> {
160 let mut dbl_tofs: Vec<f64> = Vec::new();
161 dbl_tofs.resize(tof.len(), 0.0);
162
163 for (i, &val) in tof.iter().enumerate() {
164 dbl_tofs[i] = val as f64;
165 }
166
167 let mut mz_values: Vec<f64> = Vec::new();
168 mz_values.resize(tof.len(), 0.0);
169
170 self.bruker_lib
171 .tims_index_to_mz(frame_id, &dbl_tofs, &mut mz_values)
172 .expect("Bruker binary call failed at: tims_index_to_mz;");
173
174 mz_values
175 }
176
177 fn mz_to_tof(&self, frame_id: u32, mz: &Vec<f64>) -> Vec<u32> {
178 let mut dbl_mz: Vec<f64> = Vec::new();
179 dbl_mz.resize(mz.len(), 0.0);
180
181 for (i, &val) in mz.iter().enumerate() {
182 dbl_mz[i] = val;
183 }
184
185 let mut tof_values: Vec<f64> = Vec::new();
186 tof_values.resize(mz.len(), 0.0);
187
188 self.bruker_lib
189 .tims_mz_to_index(frame_id, &dbl_mz, &mut tof_values)
190 .expect("Bruker binary call failed at: tims_mz_to_index;");
191
192 tof_values.iter().map(|&x| x.round() as u32).collect()
193 }
194
195 fn scan_to_inverse_mobility(&self, frame_id: u32, scan: &Vec<u32>) -> Vec<f64> {
207 let mut dbl_scans: Vec<f64> = Vec::new();
208 dbl_scans.resize(scan.len(), 0.0);
209
210 for (i, &val) in scan.iter().enumerate() {
211 dbl_scans[i] = val as f64;
212 }
213
214 let mut inv_mob: Vec<f64> = Vec::new();
215 inv_mob.resize(scan.len(), 0.0);
216
217 self.bruker_lib
218 .tims_scan_to_inv_mob(frame_id, &dbl_scans, &mut inv_mob)
219 .expect("Bruker binary call failed at: tims_scannum_to_oneoverk0;");
220
221 inv_mob
222 }
223
224 fn inverse_mobility_to_scan(&self, frame_id: u32, inv_mob: &Vec<f64>) -> Vec<u32> {
236 let mut dbl_inv_mob: Vec<f64> = Vec::new();
237 dbl_inv_mob.resize(inv_mob.len(), 0.0);
238
239 for (i, &val) in inv_mob.iter().enumerate() {
240 dbl_inv_mob[i] = val;
241 }
242
243 let mut scan_values: Vec<f64> = Vec::new();
244 scan_values.resize(inv_mob.len(), 0.0);
245
246 self.bruker_lib
247 .inv_mob_to_tims_scan(frame_id, &dbl_inv_mob, &mut scan_values)
248 .expect("Bruker binary call failed at: tims_oneoverk0_to_scannum;");
249
250 scan_values.iter().map(|&x| x.round() as u32).collect()
251 }
252}
253
254pub enum TimsIndexConverter {
255 Simple(SimpleIndexConverter),
256 BrukerLib(BrukerLibTimsDataConverter),
257}
258
259impl IndexConverter for TimsIndexConverter {
260 fn tof_to_mz(&self, frame_id: u32, tof_values: &Vec<u32>) -> Vec<f64> {
261 match self {
262 TimsIndexConverter::Simple(converter) => converter.tof_to_mz(frame_id, tof_values),
263 TimsIndexConverter::BrukerLib(converter) => converter.tof_to_mz(frame_id, tof_values),
264 }
265 }
266
267 fn mz_to_tof(&self, frame_id: u32, mz_values: &Vec<f64>) -> Vec<u32> {
268 match self {
269 TimsIndexConverter::Simple(converter) => converter.mz_to_tof(frame_id, mz_values),
270 TimsIndexConverter::BrukerLib(converter) => converter.mz_to_tof(frame_id, mz_values),
271 }
272 }
273
274 fn scan_to_inverse_mobility(&self, frame_id: u32, scan_values: &Vec<u32>) -> Vec<f64> {
275 match self {
276 TimsIndexConverter::Simple(converter) => {
277 converter.scan_to_inverse_mobility(frame_id, scan_values)
278 }
279 TimsIndexConverter::BrukerLib(converter) => {
280 converter.scan_to_inverse_mobility(frame_id, scan_values)
281 }
282 }
283 }
284
285 fn inverse_mobility_to_scan(
286 &self,
287 frame_id: u32,
288 inverse_mobility_values: &Vec<f64>,
289 ) -> Vec<u32> {
290 match self {
291 TimsIndexConverter::Simple(converter) => {
292 converter.inverse_mobility_to_scan(frame_id, inverse_mobility_values)
293 }
294 TimsIndexConverter::BrukerLib(converter) => {
295 converter.inverse_mobility_to_scan(frame_id, inverse_mobility_values)
296 }
297 }
298 }
299}
300
301pub struct TimsLazyLoder {
302 pub raw_data_layout: TimsRawDataLayout,
303 pub index_converter: TimsIndexConverter,
304}
305
306impl TimsData for TimsLazyLoder {
307 fn get_frame(&self, frame_id: u32) -> TimsFrame {
308 let frame_index = (frame_id - 1) as usize;
309
310 let num_peaks = self.raw_data_layout.frame_meta_data[frame_index].num_peaks;
312
313 if num_peaks == 0 {
314
315 let ms_type_raw = self.raw_data_layout.frame_meta_data[frame_index].ms_ms_type;
316
317 let ms_type = match ms_type_raw {
318 0 => MsType::Precursor,
319 8 => MsType::FragmentDda,
320 9 => MsType::FragmentDia,
321 _ => MsType::Unknown,
322 };
323
324 return TimsFrame {
325 frame_id: frame_id as i32,
326 ms_type,
327 scan: Vec::new(),
328 tof: Vec::new(),
329 ims_frame: ImsFrame {
330 retention_time: self.raw_data_layout.frame_meta_data[(frame_id - 1) as usize]
331 .time,
332 mobility: Vec::new(),
333 mz: Vec::new(),
334 intensity: Vec::new(),
335 },
336 };
337 }
338
339 let offset = self.raw_data_layout.tims_offset_values[frame_index] as u64;
340
341 let mut file_path = PathBuf::from(&self.raw_data_layout.raw_data_path);
342 file_path.push("analysis.tdf_bin");
343 let mut infile = File::open(&file_path).unwrap();
344
345 infile.seek(SeekFrom::Start(offset)).unwrap();
346
347 let mut bin_buffer = [0u8; 4];
348 infile.read_exact(&mut bin_buffer).unwrap();
349 let bin_size = Cursor::new(bin_buffer).read_i32::<LittleEndian>().unwrap();
350
351 infile.read_exact(&mut bin_buffer).unwrap();
352
353 match self.raw_data_layout.global_meta_data.tims_compression_type {
354 1 => {
355 let scan_count =
356 self.raw_data_layout.frame_meta_data[frame_index].num_scans as usize;
357 let num_peaks = num_peaks as usize;
358 let compression_offset = 8 + (scan_count + 1) * 4;
359
360 let mut scan_offsets_buffer = vec![0u8; (scan_count + 1) * 4];
361 infile.read_exact(&mut scan_offsets_buffer).unwrap();
362
363 let mut scan_offsets = Vec::with_capacity(scan_count + 1);
364 {
365 let mut rdr = Cursor::new(&scan_offsets_buffer);
366 for _ in 0..(scan_count + 1) {
367 scan_offsets.push(rdr.read_i32::<LittleEndian>().unwrap());
368 }
369 }
370
371 for offs in &mut scan_offsets {
372 *offs -= compression_offset as i32;
373 }
374
375 let remaining_size = (bin_size as usize - compression_offset) as usize;
376 let mut compressed_data = vec![0u8; remaining_size];
377 infile.read_exact(&mut compressed_data).unwrap();
378
379 let mut scan_indices_ = vec![0i64; scan_count];
380 let mut tof_indices_ = vec![0u32; num_peaks];
381 let mut intensities_ = vec![0u16; num_peaks];
382
383 let mut scan_start = 0usize;
384
385 for scan_index in 0..scan_count {
386 let start = scan_offsets[scan_index] as usize;
387 let end = scan_offsets[scan_index + 1] as usize;
388
389 if start == end {
390 continue;
391 }
392
393 let max_output_size = num_peaks * 8;
394 let decompressed_bytes =
395 lzf_decompress(&compressed_data[start..end], max_output_size)
396 .expect("LZF decompression failed.");
397
398 scan_start += parse_decompressed_bruker_binary_type1(
399 &decompressed_bytes,
400 &mut scan_indices_,
401 &mut tof_indices_,
402 &mut intensities_,
403 scan_start,
404 scan_index,
405 );
406 }
407
408 let mut scan = Vec::with_capacity(num_peaks);
410 {
411 let mut current_scan_index = 0u32;
412 for &size in &scan_indices_ {
413 let sz = size as usize;
414 for _ in 0..sz {
415 scan.push(current_scan_index);
416 }
417 current_scan_index += 1;
418 }
419 }
420
421 let intensity_dbl = intensities_.iter().map(|&x| x as f64).collect::<Vec<f64>>();
422 let tof_i32 = tof_indices_.iter().map(|&x| x as i32).collect::<Vec<i32>>();
423
424 let mz = self.index_converter.tof_to_mz(frame_id, &tof_indices_);
425 let inv_mobility = self
426 .index_converter
427 .scan_to_inverse_mobility(frame_id, &scan);
428
429 let ms_type_raw = self.raw_data_layout.frame_meta_data[frame_index].ms_ms_type;
430 let ms_type = match ms_type_raw {
431 0 => MsType::Precursor,
432 8 => MsType::FragmentDda,
433 9 => MsType::FragmentDia,
434 _ => MsType::Unknown,
435 };
436
437 TimsFrame {
438 frame_id: frame_id as i32,
439 ms_type,
440 scan: scan.iter().map(|&x| x as i32).collect(),
441 tof: tof_i32,
442 ims_frame: ImsFrame {
443 retention_time: self.raw_data_layout.frame_meta_data[frame_index].time,
444 mobility: inv_mobility,
445 mz,
446 intensity: intensity_dbl,
447 },
448 }
449 }
450
451 2 => {
453 let mut compressed_data = vec![0u8; bin_size as usize - 8];
454 infile.read_exact(&mut compressed_data).unwrap();
455
456 let decompressed_bytes = zstd_decompress(&compressed_data).unwrap();
457
458 let (scan, tof, intensity) =
459 parse_decompressed_bruker_binary_data(&decompressed_bytes).unwrap();
460 let intensity_dbl = intensity.iter().map(|&x| x as f64).collect();
461 let tof_i32 = tof.iter().map(|&x| x as i32).collect();
462 let scan = flatten_scan_values(&scan, true);
463
464 let mz = self.index_converter.tof_to_mz(frame_id, &tof);
465 let inv_mobility = self
466 .index_converter
467 .scan_to_inverse_mobility(frame_id, &scan);
468
469 let ms_type_raw = self.raw_data_layout.frame_meta_data[frame_index].ms_ms_type;
470
471 let ms_type = match ms_type_raw {
472 0 => MsType::Precursor,
473 8 => MsType::FragmentDda,
474 9 => MsType::FragmentDia,
475 _ => MsType::Unknown,
476 };
477
478 TimsFrame {
479 frame_id: frame_id as i32,
480 ms_type,
481 scan: scan.iter().map(|&x| x as i32).collect(),
482 tof: tof_i32,
483 ims_frame: ImsFrame {
484 retention_time: self.raw_data_layout.frame_meta_data[frame_index].time,
485 mobility: inv_mobility,
486 mz,
487 intensity: intensity_dbl,
488 },
489 }
490 }
491
492 _ => {
493 panic!("TimsCompressionType is not 1 or 2.")
494 }
495 }
496 }
497
498 fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame {
499 let frame_index = (frame_id - 1) as usize;
500 let offset = self.raw_data_layout.tims_offset_values[frame_index] as u64;
501
502 let num_peaks = self.raw_data_layout.frame_meta_data[frame_index].num_peaks;
504
505 if num_peaks == 0 {
506 return RawTimsFrame {
507 frame_id: frame_id as i32,
508 retention_time: self.raw_data_layout.frame_meta_data[(frame_id - 1) as usize].time,
509 ms_type: MsType::Unknown,
510 scan: Vec::new(),
511 tof: Vec::new(),
512 intensity: Vec::new(),
513 };
514 }
515
516 let mut file_path = PathBuf::from(&self.raw_data_layout.raw_data_path);
517 file_path.push("analysis.tdf_bin");
518 let mut infile = File::open(&file_path).unwrap();
519
520 infile.seek(SeekFrom::Start(offset)).unwrap();
521
522 let mut bin_buffer = [0u8; 4];
523 infile.read_exact(&mut bin_buffer).unwrap();
524 let bin_size = Cursor::new(bin_buffer).read_i32::<LittleEndian>().unwrap();
525
526 infile.read_exact(&mut bin_buffer).unwrap();
527
528 match self.raw_data_layout.global_meta_data.tims_compression_type {
529 _ if self.raw_data_layout.global_meta_data.tims_compression_type == 1 => {
530 panic!("Decompression Type1 not implemented.");
531 }
532
533 _ if self.raw_data_layout.global_meta_data.tims_compression_type == 2 => {
535 let mut compressed_data = vec![0u8; bin_size as usize - 8];
536 infile.read_exact(&mut compressed_data).unwrap();
537
538 let decompressed_bytes = zstd_decompress(&compressed_data).unwrap();
539
540 let (scan, tof, intensity) =
541 parse_decompressed_bruker_binary_data(&decompressed_bytes).unwrap();
542
543 let ms_type_raw = self.raw_data_layout.frame_meta_data[frame_index].ms_ms_type;
544
545 let ms_type = match ms_type_raw {
546 0 => MsType::Precursor,
547 8 => MsType::FragmentDda,
548 9 => MsType::FragmentDia,
549 _ => MsType::Unknown,
550 };
551
552 let frame = RawTimsFrame {
553 frame_id: frame_id as i32,
554 retention_time: self.raw_data_layout.frame_meta_data[(frame_id - 1) as usize]
555 .time,
556 ms_type,
557 scan,
558 tof,
559 intensity: intensity.iter().map(|&x| x as f64).collect(),
560 };
561
562 return frame;
563 }
564
565 _ => {
567 panic!("TimsCompressionType is not 1 or 2.")
568 }
569 }
570 }
571
572 fn get_slice(&self, frame_ids: Vec<u32>, _num_threads: usize) -> TimsSlice {
573 let result: Vec<TimsFrame> = frame_ids.into_iter().map(|f| self.get_frame(f)).collect();
574
575 TimsSlice { frames: result }
576 }
577
578 fn get_acquisition_mode(&self) -> AcquisitionMode {
579 self.raw_data_layout.acquisition_mode.clone()
580 }
581
582 fn get_frame_count(&self) -> i32 {
583 self.raw_data_layout.frame_meta_data.len() as i32
584 }
585
586 fn get_data_path(&self) -> &str {
587 &self.raw_data_layout.raw_data_path
588 }
589}
590
591pub struct TimsInMemoryLoader {
592 pub raw_data_layout: TimsRawDataLayout,
593 pub index_converter: TimsIndexConverter,
594 compressed_data: Vec<u8>,
595}
596
597impl TimsData for TimsInMemoryLoader {
598 fn get_frame(&self, frame_id: u32) -> TimsFrame {
599 let raw_frame = self.get_raw_frame(frame_id);
600
601 let raw_frame = match raw_frame.ms_type {
602 MsType::FragmentDda => raw_frame.smooth(1).centroid(1),
603 _ => raw_frame,
604 };
605
606 if raw_frame.scan.is_empty() {
608 return TimsFrame::default();
609 }
610
611 let tof_i32 = raw_frame.tof.iter().map(|&x| x as i32).collect();
612 let scan = flatten_scan_values(&raw_frame.scan, true);
613
614 let mz = self.index_converter.tof_to_mz(frame_id, &raw_frame.tof);
615 let inverse_mobility = self
616 .index_converter
617 .scan_to_inverse_mobility(frame_id, &scan);
618
619 let ims_frame = ImsFrame {
620 retention_time: raw_frame.retention_time,
621 mz,
622 intensity: raw_frame.intensity,
623 mobility: inverse_mobility,
624 };
625
626 TimsFrame {
627 frame_id: frame_id as i32,
628 ms_type: raw_frame.ms_type,
629 scan: scan.iter().map(|&x| x as i32).collect(),
630 tof: tof_i32,
631 ims_frame,
632 }
633 }
634
635 fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame {
636 let frame_index = (frame_id - 1) as usize;
637 let offset = self.raw_data_layout.tims_offset_values[frame_index] as usize;
638
639 let bin_size_offset = offset + 4; let bin_size = Cursor::new(&self.compressed_data[offset..bin_size_offset])
641 .read_i32::<LittleEndian>()
642 .unwrap();
643
644 let data_offset = bin_size_offset + 4; let frame_data = &self.compressed_data[data_offset..data_offset + bin_size as usize - 8];
646
647 let decompressed_bytes = zstd_decompress(&frame_data).unwrap();
648
649 let (scan, tof, intensity) =
650 parse_decompressed_bruker_binary_data(&decompressed_bytes).unwrap();
651
652 let ms_type_raw = self.raw_data_layout.frame_meta_data[frame_index].ms_ms_type;
653
654 let ms_type = match ms_type_raw {
655 0 => MsType::Precursor,
656 8 => MsType::FragmentDda,
657 9 => MsType::FragmentDia,
658 _ => MsType::Unknown,
659 };
660
661 let raw_frame = RawTimsFrame {
662 frame_id: frame_id as i32,
663 retention_time: self.raw_data_layout.frame_meta_data[(frame_id - 1) as usize].time,
664 ms_type,
665 scan,
666 tof,
667 intensity: intensity.iter().map(|&x| x as f64).collect(),
668 };
669
670 raw_frame
671 }
672
673 fn get_slice(&self, frame_ids: Vec<u32>, num_threads: usize) -> TimsSlice {
674 let pool = ThreadPoolBuilder::new()
675 .num_threads(num_threads)
676 .build()
677 .unwrap();
678 let frames = pool.install(|| {
679 frame_ids
680 .par_iter()
681 .map(|&frame_id| self.get_frame(frame_id))
682 .collect()
683 });
684
685 TimsSlice { frames }
686 }
687
688 fn get_acquisition_mode(&self) -> AcquisitionMode {
689 self.raw_data_layout.acquisition_mode.clone()
690 }
691
692 fn get_frame_count(&self) -> i32 {
693 self.raw_data_layout.frame_meta_data.len() as i32
694 }
695
696 fn get_data_path(&self) -> &str {
697 &self.raw_data_layout.raw_data_path
698 }
699}
700
701pub enum TimsDataLoader {
702 InMemory(TimsInMemoryLoader),
703 Lazy(TimsLazyLoder),
704}
705
706impl TimsDataLoader {
707 pub fn new_lazy(
708 bruker_lib_path: &str,
709 data_path: &str,
710 use_bruker_sdk: bool,
711 scan_max_index: u32,
712 im_lower: f64,
713 im_upper: f64,
714 tof_max_index: u32,
715 mz_lower: f64,
716 mz_upper: f64,
717 ) -> Self {
718 let raw_data_layout = TimsRawDataLayout::new(data_path);
719
720 let index_converter = match use_bruker_sdk {
721 true => TimsIndexConverter::BrukerLib(BrukerLibTimsDataConverter::new(
722 bruker_lib_path,
723 data_path,
724 )),
725 false => TimsIndexConverter::Simple(SimpleIndexConverter::from_boundaries(
726 mz_lower,
727 mz_upper,
728 tof_max_index,
729 im_lower,
730 im_upper,
731 scan_max_index,
732 )),
733 };
734
735 TimsDataLoader::Lazy(TimsLazyLoder {
736 raw_data_layout,
737 index_converter,
738 })
739 }
740
741 pub fn new_in_memory(
742 bruker_lib_path: &str,
743 data_path: &str,
744 use_bruker_sdk: bool,
745 scan_max_index: u32,
746 im_lower: f64,
747 im_upper: f64,
748 tof_max_index: u32,
749 mz_lower: f64,
750 mz_upper: f64,
751 ) -> Self {
752 let raw_data_layout = TimsRawDataLayout::new(data_path);
753
754 let index_converter = match use_bruker_sdk {
755 true => TimsIndexConverter::BrukerLib(BrukerLibTimsDataConverter::new(
756 bruker_lib_path,
757 data_path,
758 )),
759 false => TimsIndexConverter::Simple(SimpleIndexConverter::from_boundaries(
760 mz_lower,
761 mz_upper,
762 tof_max_index,
763 im_lower,
764 im_upper,
765 scan_max_index,
766 )),
767 };
768
769 let mut file_path = PathBuf::from(data_path);
770 file_path.push("analysis.tdf_bin");
771 let mut infile = File::open(file_path).unwrap();
772 let mut data = Vec::new();
773 infile.read_to_end(&mut data).unwrap();
774
775 TimsDataLoader::InMemory(TimsInMemoryLoader {
776 raw_data_layout,
777 index_converter,
778 compressed_data: data,
779 })
780 }
781 pub fn get_index_converter(&self) -> &dyn IndexConverter {
782 match self {
783 TimsDataLoader::InMemory(loader) => &loader.index_converter,
784 TimsDataLoader::Lazy(loader) => &loader.index_converter,
785 }
786 }
787}
788
789impl TimsData for TimsDataLoader {
790 fn get_frame(&self, frame_id: u32) -> TimsFrame {
791 match self {
792 TimsDataLoader::InMemory(loader) => loader.get_frame(frame_id),
793 TimsDataLoader::Lazy(loader) => loader.get_frame(frame_id),
794 }
795 }
796 fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame {
797 match self {
798 TimsDataLoader::InMemory(loader) => loader.get_raw_frame(frame_id),
799 TimsDataLoader::Lazy(loader) => loader.get_raw_frame(frame_id),
800 }
801 }
802
803 fn get_slice(&self, frame_ids: Vec<u32>, num_threads: usize) -> TimsSlice {
804 match self {
805 TimsDataLoader::InMemory(loader) => loader.get_slice(frame_ids, num_threads),
806 TimsDataLoader::Lazy(loader) => loader.get_slice(frame_ids, num_threads),
807 }
808 }
809
810 fn get_acquisition_mode(&self) -> AcquisitionMode {
811 match self {
812 TimsDataLoader::InMemory(loader) => loader.get_acquisition_mode(),
813 TimsDataLoader::Lazy(loader) => loader.get_acquisition_mode(),
814 }
815 }
816
817 fn get_frame_count(&self) -> i32 {
818 match self {
819 TimsDataLoader::InMemory(loader) => loader.get_frame_count(),
820 TimsDataLoader::Lazy(loader) => loader.get_frame_count(),
821 }
822 }
823
824 fn get_data_path(&self) -> &str {
825 match self {
826 TimsDataLoader::InMemory(loader) => loader.get_data_path(),
827 TimsDataLoader::Lazy(loader) => loader.get_data_path(),
828 }
829 }
830}
831
832pub struct SimpleIndexConverter {
833 pub tof_intercept: f64,
834 pub tof_slope: f64,
835 pub scan_intercept: f64,
836 pub scan_slope: f64,
837}
838
839impl SimpleIndexConverter {
840 pub fn from_boundaries(
841 mz_min: f64,
842 mz_max: f64,
843 tof_max_index: u32,
844 im_min: f64,
845 im_max: f64,
846 scan_max_index: u32,
847 ) -> Self {
848 let tof_intercept: f64 = mz_min.sqrt();
849 let tof_slope: f64 = (mz_max.sqrt() - tof_intercept) / tof_max_index as f64;
850
851 let scan_intercept: f64 = im_max;
852 let scan_slope: f64 = (im_min - scan_intercept) / scan_max_index as f64;
853 Self {
854 tof_intercept,
855 tof_slope,
856 scan_intercept,
857 scan_slope,
858 }
859 }
860}
861
862impl IndexConverter for SimpleIndexConverter {
863 fn tof_to_mz(&self, _frame_id: u32, _tof_values: &Vec<u32>) -> Vec<f64> {
864 let mut mz_values: Vec<f64> = Vec::new();
865 mz_values.resize(_tof_values.len(), 0.0);
866
867 for (i, &val) in _tof_values.iter().enumerate() {
868 mz_values[i] = (self.tof_intercept + self.tof_slope * val as f64).powi(2);
869 }
870
871 mz_values
872 }
873
874 fn mz_to_tof(&self, _frame_id: u32, _mz_values: &Vec<f64>) -> Vec<u32> {
875 let mut tof_values: Vec<u32> = Vec::new();
876 tof_values.resize(_mz_values.len(), 0);
877
878 for (i, &val) in _mz_values.iter().enumerate() {
879 tof_values[i] = ((val.sqrt() - self.tof_intercept) / self.tof_slope) as u32;
880 }
881
882 tof_values
883 }
884
885 fn scan_to_inverse_mobility(&self, _frame_id: u32, _scan_values: &Vec<u32>) -> Vec<f64> {
886 let mut inv_mobility_values: Vec<f64> = Vec::new();
887 inv_mobility_values.resize(_scan_values.len(), 0.0);
888
889 for (i, &val) in _scan_values.iter().enumerate() {
890 inv_mobility_values[i] = self.scan_intercept + self.scan_slope * val as f64;
891 }
892
893 inv_mobility_values
894 }
895
896 fn inverse_mobility_to_scan(
897 &self,
898 _frame_id: u32,
899 _inverse_mobility_values: &Vec<f64>,
900 ) -> Vec<u32> {
901 let mut scan_values: Vec<u32> = Vec::new();
902 scan_values.resize(_inverse_mobility_values.len(), 0);
903
904 for (i, &val) in _inverse_mobility_values.iter().enumerate() {
905 scan_values[i] = ((val - self.scan_intercept) / self.scan_slope) as u32;
906 }
907
908 scan_values
909 }
910}