1use crate::data::acquisition::AcquisitionMode;
2use crate::data::handle::{IndexConverter, TimsData, TimsDataLoader};
3use crate::data::meta::{
4 read_dda_precursor_meta, read_global_meta_sql, read_meta_data_sql, read_pasef_frame_ms_ms_info,
5 DDAPrecursor, PasefMsMsMeta,
6};
7use mscore::timstof::frame::{RawTimsFrame, TimsFrame};
8use mscore::timstof::slice::TimsSlice;
9use rayon::prelude::*;
10use rayon::ThreadPoolBuilder;
11use std::collections::BTreeMap;
12
13#[derive(Clone)]
14pub struct PASEFDDAFragment {
15 pub frame_id: u32,
16 pub precursor_id: u32,
17 pub collision_energy: f64,
18 pub selected_fragment: TimsFrame,
19}
20
21pub struct TimsDatasetDDA {
22 pub loader: TimsDataLoader,
23}
24
25impl TimsDatasetDDA {
26 pub fn new(
27 bruker_lib_path: &str,
28 data_path: &str,
29 in_memory: bool,
30 use_bruker_sdk: bool,
31 ) -> Self {
32 let global_meta_data = read_global_meta_sql(data_path).unwrap();
34 let meta_data = read_meta_data_sql(data_path).unwrap();
35
36 let scan_max_index = meta_data.iter().map(|x| x.num_scans).max().unwrap() as u32;
37 let im_lower = global_meta_data.one_over_k0_range_lower;
38 let im_upper = global_meta_data.one_over_k0_range_upper;
39
40 let tof_max_index = global_meta_data.tof_max_index;
41 let mz_lower = global_meta_data.mz_acquisition_range_lower;
42 let mz_upper = global_meta_data.mz_acquisition_range_upper;
43
44 let loader = match in_memory {
45 true => TimsDataLoader::new_in_memory(
46 bruker_lib_path,
47 data_path,
48 use_bruker_sdk,
49 scan_max_index,
50 im_lower,
51 im_upper,
52 tof_max_index,
53 mz_lower,
54 mz_upper,
55 ),
56 false => TimsDataLoader::new_lazy(
57 bruker_lib_path,
58 data_path,
59 use_bruker_sdk,
60 scan_max_index,
61 im_lower,
62 im_upper,
63 tof_max_index,
64 mz_lower,
65 mz_upper,
66 ),
67 };
68 TimsDatasetDDA { loader }
69 }
70
71 pub fn get_selected_precursors(&self) -> Vec<DDAPrecursor> {
89 let precursor_meta = read_dda_precursor_meta(&self.loader.get_data_path()).unwrap();
90 let pasef_meta = self.get_pasef_frame_ms_ms_info();
91
92 let precursor_id_to_pasef_meta: BTreeMap<i64, &PasefMsMsMeta> = pasef_meta
93 .iter()
94 .map(|x| (x.precursor_id as i64, x))
95 .collect();
96
97 let result: Vec<_> = precursor_meta
99 .iter()
100 .map(|precursor| {
101 let pasef_meta = precursor_id_to_pasef_meta
102 .get(&precursor.precursor_id)
103 .unwrap();
104 DDAPrecursor {
105 frame_id: precursor.precursor_frame_id,
106 precursor_id: precursor.precursor_id,
107 mono_mz: precursor.precursor_mz_monoisotopic,
108 highest_intensity_mz: precursor.precursor_mz_highest_intensity,
109 average_mz: precursor.precursor_mz_average,
110 charge: precursor.precursor_charge,
111 inverse_ion_mobility: self.scan_to_inverse_mobility(
112 precursor.precursor_frame_id as u32,
113 &vec![precursor.precursor_average_scan_number as u32],
114 )[0],
115 collision_energy: pasef_meta.collision_energy,
116 precuror_total_intensity: precursor.precursor_total_intensity,
117 isolation_mz: pasef_meta.isolation_mz,
118 isolation_width: pasef_meta.isolation_width,
119 }
120 })
121 .collect();
122
123 result
124 }
125
126 pub fn get_precursor_frames(
127 &self,
128 min_intensity: f64,
129 max_num_peaks: usize,
130 num_threads: usize,
131 ) -> Vec<TimsFrame> {
132 let meta_data = read_meta_data_sql(&self.loader.get_data_path()).unwrap();
134
135 let precursor_frames = meta_data.iter().filter(|x| x.ms_ms_type == 0);
137
138 let tims_silce =
139 self.get_slice(precursor_frames.map(|x| x.id as u32).collect(), num_threads);
140
141 let result: Vec<_> = tims_silce
142 .frames
143 .par_iter()
144 .map(|frame| {
145 frame
146 .filter_ranged(0.0, 2000.0, 0, 2000, 0.0, 5.0, min_intensity, 1e9)
147 .top_n(max_num_peaks)
148 })
149 .collect();
150
151 result
152 }
153
154 pub fn get_pasef_frame_ms_ms_info(&self) -> Vec<PasefMsMsMeta> {
155 read_pasef_frame_ms_ms_info(&self.loader.get_data_path()).unwrap()
156 }
157
158 pub fn get_pasef_fragments(&self, num_threads: usize) -> Vec<PASEFDDAFragment> {
160 let pasef_info = self.get_pasef_frame_ms_ms_info();
162
163 let pool = ThreadPoolBuilder::new()
164 .num_threads(num_threads)
165 .build()
166 .unwrap();
167
168 let filtered_frames = pool.install(|| {
169 let result: Vec<_> = pasef_info
170 .par_iter()
171 .map(|pasef_info| {
172 let frame = self.loader.get_frame(pasef_info.frame_id as u32);
174
175 let scan_margin = (pasef_info.scan_num_end - pasef_info.scan_num_begin) / 20;
177
178 let filtered_frame = frame.filter_ranged(
180 0.0,
181 2000.0,
182 (pasef_info.scan_num_begin - scan_margin) as i32,
183 (pasef_info.scan_num_end + scan_margin) as i32,
184 0.0,
185 5.0,
186 0.0,
187 1e9,
188 );
189
190 PASEFDDAFragment {
191 frame_id: pasef_info.frame_id as u32,
192 precursor_id: pasef_info.precursor_id as u32,
193 collision_energy: pasef_info.collision_energy,
194 selected_fragment: filtered_frame,
196 }
197 })
198 .collect();
199
200 result
201 });
202
203 filtered_frames
204 }
205}
206
207impl TimsData for TimsDatasetDDA {
208 fn get_frame(&self, frame_id: u32) -> TimsFrame {
209 self.loader.get_frame(frame_id)
210 }
211
212 fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame {
213 self.loader.get_raw_frame(frame_id)
214 }
215
216 fn get_slice(&self, frame_ids: Vec<u32>, num_threads: usize) -> TimsSlice {
217 self.loader.get_slice(frame_ids, num_threads)
218 }
219
220 fn get_acquisition_mode(&self) -> AcquisitionMode {
221 self.loader.get_acquisition_mode().clone()
222 }
223
224 fn get_frame_count(&self) -> i32 {
225 self.loader.get_frame_count()
226 }
227
228 fn get_data_path(&self) -> &str {
229 &self.loader.get_data_path()
230 }
231}
232
233impl IndexConverter for TimsDatasetDDA {
234 fn tof_to_mz(&self, frame_id: u32, tof_values: &Vec<u32>) -> Vec<f64> {
235 self.loader
236 .get_index_converter()
237 .tof_to_mz(frame_id, tof_values)
238 }
239
240 fn mz_to_tof(&self, frame_id: u32, mz_values: &Vec<f64>) -> Vec<u32> {
241 self.loader
242 .get_index_converter()
243 .mz_to_tof(frame_id, mz_values)
244 }
245
246 fn scan_to_inverse_mobility(&self, frame_id: u32, scan_values: &Vec<u32>) -> Vec<f64> {
247 self.loader
248 .get_index_converter()
249 .scan_to_inverse_mobility(frame_id, scan_values)
250 }
251
252 fn inverse_mobility_to_scan(
253 &self,
254 frame_id: u32,
255 inverse_mobility_values: &Vec<f64>,
256 ) -> Vec<u32> {
257 self.loader
258 .get_index_converter()
259 .inverse_mobility_to_scan(frame_id, inverse_mobility_values)
260 }
261}