1use byteorder::{ByteOrder, LittleEndian};
2use mscore::timstof::frame::TimsFrame;
3use rayon::iter::IntoParallelRefIterator;
4use rayon::prelude::*;
5use rayon::ThreadPoolBuilder;
6use std::io;
7use std::io::{Read, Write};
8
9pub fn zstd_decompress(compressed_data: &[u8]) -> io::Result<Vec<u8>> {
20 let mut decoder = zstd::Decoder::new(compressed_data)?;
21 let mut decompressed_data = Vec::new();
22 decoder.read_to_end(&mut decompressed_data)?;
23 Ok(decompressed_data)
24}
25
26pub fn zstd_compress(decompressed_data: &[u8], compression_level: i32) -> io::Result<Vec<u8>> {
37 let mut encoder = zstd::Encoder::new(Vec::new(), compression_level)?;
38 encoder.write_all(decompressed_data)?;
39 let compressed_data = encoder.finish()?;
40 Ok(compressed_data)
41}
42
43fn sort_dedup_scan_tof(
55 scans: &[u32],
56 tofs: &[u32],
57 intensities: &[u32],
58) -> (Vec<u32>, Vec<u32>, Vec<u32>) {
59 use std::collections::HashMap;
60 let mut acc: HashMap<(u32, u32), u64> = HashMap::with_capacity(scans.len());
61 for i in 0..scans.len() {
62 *acc.entry((scans[i], tofs[i])).or_insert(0) += intensities[i] as u64;
63 }
64 let mut pairs: Vec<((u32, u32), u64)> = acc.into_iter().collect();
65 pairs.sort_unstable_by_key(|&((s, t), _)| (s, t));
67
68 let n = pairs.len();
69 let mut out_scan = Vec::with_capacity(n);
70 let mut out_tof = Vec::with_capacity(n);
71 let mut out_int = Vec::with_capacity(n);
72 for ((s, t), inten) in pairs {
73 out_scan.push(s);
74 out_tof.push(t);
75 out_int.push(inten.min(u32::MAX as u64) as u32);
76 }
77 (out_scan, out_tof, out_int)
78}
79
80pub fn reconstruct_compressed_data(
81 scans: Vec<u32>,
82 tofs: Vec<u32>,
83 intensities: Vec<u32>,
84 total_scans: u32,
85 compression_level: i32,
86) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
87 assert_eq!(scans.len(), tofs.len());
89 assert_eq!(scans.len(), intensities.len());
90
91 let (scans, mut tofs, intensities) = sort_dedup_scan_tof(&scans, &tofs, &intensities);
93
94 modify_tofs(&mut tofs, &scans);
96
97 let peak_cnts = get_peak_cnts(total_scans, &scans);
99
100 let mut interleaved = Vec::new();
102 for (&tof, &intensity) in tofs.iter().zip(intensities.iter()) {
103 interleaved.push(tof);
104 interleaved.push(intensity);
105 }
106
107 let real_data = get_realdata(&peak_cnts, &interleaved);
109
110 let compressed_data = zstd_compress(&real_data, compression_level)?;
112
113 let mut final_data = Vec::new();
115
116 final_data.extend_from_slice(&(compressed_data.len() as u32 + 8).to_le_bytes());
118
119 final_data.extend_from_slice(&total_scans.to_le_bytes());
121
122 final_data.extend_from_slice(&compressed_data);
124
125 Ok(final_data)
126}
127
128pub fn compress_collection(
129 frames: Vec<TimsFrame>,
130 max_scan_count: u32,
131 compression_level: i32,
132 num_threads: usize,
133) -> Vec<Vec<u8>> {
134 let pool = ThreadPoolBuilder::new()
135 .num_threads(num_threads)
136 .build()
137 .unwrap();
138
139 let result = pool.install(|| {
140 frames
141 .par_iter()
142 .map(|frame| {
143 let compressed_data = reconstruct_compressed_data(
144 frame.scan.iter().map(|&x| x as u32).collect(),
145 frame.tof.iter().map(|&x| x as u32).collect(),
146 frame
147 .ims_frame
148 .intensity
149 .iter()
150 .map(|&x| x as u32)
151 .collect(),
152 max_scan_count,
153 compression_level,
154 )
155 .unwrap();
156 compressed_data
157 })
158 .collect()
159 });
160 result
161}
162
163pub fn parse_decompressed_bruker_binary_data(
176 decompressed_bytes: &[u8],
177) -> Result<(Vec<u32>, Vec<u32>, Vec<u32>), Box<dyn std::error::Error>> {
178 let mut buffer_u32 = Vec::new();
179
180 for i in 0..(decompressed_bytes.len() / 4) {
181 let value = LittleEndian::read_u32(&[
182 decompressed_bytes[i],
183 decompressed_bytes[i + (decompressed_bytes.len() / 4)],
184 decompressed_bytes[i + (2 * decompressed_bytes.len() / 4)],
185 decompressed_bytes[i + (3 * decompressed_bytes.len() / 4)],
186 ]);
187 buffer_u32.push(value);
188 }
189
190 let scan_count = buffer_u32[0] as usize;
192
193 let mut scan_indices: Vec<u32> = buffer_u32[..scan_count].to_vec();
195 for index in &mut scan_indices {
196 *index /= 2;
197 }
198
199 scan_indices[0] = 0;
201
202 let mut tof_indices: Vec<u32> = buffer_u32
204 .iter()
205 .skip(scan_count)
206 .step_by(2)
207 .cloned()
208 .collect();
209
210 let intensities: Vec<u32> = buffer_u32
212 .iter()
213 .skip(scan_count + 1)
214 .step_by(2)
215 .cloned()
216 .collect();
217
218 let last_scan = intensities.len() as u32 - scan_indices[1..].iter().sum::<u32>();
220
221 for i in 0..(scan_indices.len() - 1) {
223 scan_indices[i] = scan_indices[i + 1];
224 }
225
226 let len = scan_indices.len();
228 scan_indices[len - 1] = last_scan;
229
230 let mut index = 0;
232 for &size in &scan_indices {
233 let mut current_sum = 0;
234 for _ in 0..size {
235 current_sum += tof_indices[index];
236 tof_indices[index] = current_sum;
237 index += 1;
238 }
239 }
240
241 let adjusted_tof_indices: Vec<u32> = tof_indices.iter().map(|&val| val - 1).collect();
243 Ok((scan_indices, adjusted_tof_indices, intensities))
244}
245
246pub fn get_peak_cnts(total_scans: u32, scans: &[u32]) -> Vec<u32> {
247 let mut peak_cnts = vec![total_scans];
248 let mut ii = 0;
249 for scan_id in 1..total_scans {
250 let mut counter = 0;
251 while ii < scans.len() && scans[ii] < scan_id {
252 ii += 1;
253 counter += 1;
254 }
255 peak_cnts.push(counter * 2);
256 }
257 peak_cnts
258}
259
260pub fn modify_tofs(tofs: &mut [u32], scans: &[u32]) {
261 let mut last_tof = -1i32; let mut last_scan = 0;
263 for ii in 0..tofs.len() {
264 if last_scan != scans[ii] {
265 last_tof = -1;
266 last_scan = scans[ii];
267 }
268 let val = tofs[ii] as i32; tofs[ii] = (val - last_tof) as u32; last_tof = val;
271 }
272}
273
274pub fn get_realdata(peak_cnts: &[u32], interleaved: &[u32]) -> Vec<u8> {
275 let mut back_data = Vec::new();
276
277 for &cnt in peak_cnts {
279 back_data.extend_from_slice(&cnt.to_le_bytes());
280 }
281
282 for &value in interleaved {
284 back_data.extend_from_slice(&value.to_le_bytes());
285 }
286
287 get_realdata_loop(&back_data)
289}
290
291pub fn get_realdata_loop(back_data: &[u8]) -> Vec<u8> {
292 let mut real_data = vec![0u8; back_data.len()];
293 let mut reminder = 0;
294 let mut bd_idx = 0;
295 for rd_idx in 0..back_data.len() {
296 if bd_idx >= back_data.len() {
297 reminder += 1;
298 bd_idx = reminder;
299 }
300 real_data[rd_idx] = back_data[bd_idx];
301 bd_idx += 4;
302 }
303 real_data
304}
305
306pub fn get_data_for_compression(
307 tofs: &Vec<u32>,
308 scans: &Vec<u32>,
309 intensities: &Vec<u32>,
310 max_scans: u32,
311) -> Vec<u8> {
312 let (scans, tofs, intensities) = sort_dedup_scan_tof(scans, tofs, intensities);
314
315 let mut tof_copy = tofs.clone();
316 modify_tofs(&mut tof_copy, &scans);
317 let peak_cnts = get_peak_cnts(max_scans, &scans);
318 let interleaved: Vec<u32> = tof_copy
320 .iter()
321 .zip(intensities.iter())
322 .flat_map(|(tof, intensity)| vec![*tof, *intensity])
323 .collect();
324
325 get_realdata(&peak_cnts, &interleaved)
326}
327
328pub fn get_data_for_compression_par(
329 tofs: Vec<Vec<u32>>,
330 scans: Vec<Vec<u32>>,
331 intensities: Vec<Vec<u32>>,
332 max_scans: u32,
333 num_threads: usize,
334) -> Vec<Vec<u8>> {
335 let pool = ThreadPoolBuilder::new()
336 .num_threads(num_threads)
337 .build()
338 .unwrap();
339
340 let result = pool.install(|| {
341 tofs.par_iter()
342 .zip(scans.par_iter())
343 .zip(intensities.par_iter())
344 .map(|((tof, scan), intensity)| {
345 get_data_for_compression(tof, scan, intensity, max_scans)
346 })
347 .collect()
348 });
349
350 result
351}
352
353pub fn flatten_scan_values(scan: &Vec<u32>, zero_indexed: bool) -> Vec<u32> {
354 let add = if zero_indexed { 0 } else { 1 };
355 scan.iter()
356 .enumerate()
357 .flat_map(|(index, &count)| vec![(index + add) as u32; count as usize].into_iter())
358 .collect()
359}
360
361pub fn merge_ranges(mut ranges: Vec<(usize, usize)>) -> Vec<(usize, usize)> {
363 if ranges.is_empty() { return ranges; }
364 ranges.sort_unstable_by_key(|x| x.0);
365 let mut out: Vec<(usize, usize)> = Vec::with_capacity(ranges.len());
366 let mut cur = ranges[0];
367 for (l, r) in ranges.into_iter().skip(1) {
368 if l <= cur.1 + 1 {
369 cur.1 = cur.1.max(r);
370 } else {
371 out.push(cur);
372 cur = (l, r);
373 }
374 }
375 out.push(cur);
376 out
377}