1use std::{collections::HashSet, convert::TryInto, mem};
2
3use mzpeaks::{
4 CentroidLike, CentroidPeak, CoordinateLike, DeconvolutedPeak, DeconvolutedPeakSet, IonMobility, MZ, MZPeakSetType, Mass, PeakSet, feature::{ChargedFeature, Feature}, peak::{IonMobilityAwareCentroidPeak, IonMobilityAwareDeconvolutedPeak}, prelude::*,
5};
6
7use mzdata_param::Unit;
8
9use crate::{utils::{mass_charge_ratio, neutral_mass}};
10
11use super::{
12 array::DataArray,
13 encodings::{ArrayRetrievalError, ArrayType, BinaryCompressionType, BinaryDataArrayType},
14 map::BinaryArrayMap,
15 BinaryArrayMap3D, ByteArrayView,
16};
17
18impl From<&PeakSet> for BinaryArrayMap {
19 fn from(peaks: &PeakSet) -> BinaryArrayMap {
20 let mut arrays = BinaryArrayMap::new();
21
22 let mut mz_array = DataArray::from_name_type_size(
23 &ArrayType::MZArray,
24 BinaryDataArrayType::Float64,
25 peaks.len() * BinaryDataArrayType::Float64.size_of(),
26 );
27
28 let mut intensity_array = DataArray::from_name_type_size(
29 &ArrayType::IntensityArray,
30 BinaryDataArrayType::Float32,
31 peaks.len() * BinaryDataArrayType::Float32.size_of(),
32 );
33
34 mz_array.compression = BinaryCompressionType::Decoded;
35 intensity_array.compression = BinaryCompressionType::Decoded;
36
37 for p in peaks.iter() {
38 let mz: f64 = p.coordinate();
39 let inten: f32 = p.intensity();
40
41 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
42 mz_array.data.extend(raw_bytes);
43
44 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
45 intensity_array.data.extend(raw_bytes);
46 }
47
48 arrays.add(mz_array);
49 arrays.add(intensity_array);
50 arrays
51 }
52}
53
54impl<C: CentroidLike + From<CentroidPeak>> From<BinaryArrayMap> for MZPeakSetType<C> {
55 fn from(arrays: BinaryArrayMap) -> MZPeakSetType<C> {
56 (&arrays).into()
57 }
58}
59
60impl<C: CentroidLike + From<CentroidPeak>> From<&BinaryArrayMap> for MZPeakSetType<C> {
61 fn from(arrays: &BinaryArrayMap) -> MZPeakSetType<C> {
62 let mz_array = arrays.mzs().unwrap();
63 let intensity_array = arrays.intensities().unwrap();
64 let mut peaks = Vec::with_capacity(mz_array.len());
65
66 for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
67 peaks.push(
68 CentroidPeak {
69 mz: *mz,
70 intensity: *intensity,
71 index: i as u32,
72 }
73 .into(),
74 )
75 }
76 MZPeakSetType::<C>::new(peaks)
77 }
78}
79
80impl From<&BinaryArrayMap> for DeconvolutedPeakSet {
81 fn from(arrays: &BinaryArrayMap) -> DeconvolutedPeakSet {
82 let mz_array = arrays.mzs().unwrap();
83 let intensity_array = arrays.intensities().unwrap();
84 let charge_array = arrays
85 .charges()
86 .expect("Charge state array is required for deconvoluted peaks");
87 let mut peaks = Vec::with_capacity(mz_array.len());
88 for (i, ((mz, intensity), charge)) in mz_array
89 .iter()
90 .zip(intensity_array.iter())
91 .zip(charge_array.iter())
92 .enumerate()
93 {
94 peaks.push(DeconvolutedPeak {
95 neutral_mass: neutral_mass(*mz, *charge),
96 intensity: *intensity,
97 charge: *charge,
98 index: i as u32,
99 })
100 }
101
102 DeconvolutedPeakSet::new(peaks)
103 }
104}
105
106impl From<&DeconvolutedPeakSet> for BinaryArrayMap {
107 fn from(peaks: &DeconvolutedPeakSet) -> BinaryArrayMap {
108 let mut arrays = BinaryArrayMap::new();
109
110 let mut mz_array = DataArray::from_name_type_size(
111 &ArrayType::MZArray,
112 BinaryDataArrayType::Float64,
113 peaks.len() * BinaryDataArrayType::Float64.size_of(),
114 );
115
116 let mut intensity_array = DataArray::from_name_type_size(
117 &ArrayType::IntensityArray,
118 BinaryDataArrayType::Float32,
119 peaks.len() * BinaryDataArrayType::Float32.size_of(),
120 );
121
122 let mut charge_array = DataArray::from_name_type_size(
123 &ArrayType::ChargeArray,
124 BinaryDataArrayType::Int32,
125 peaks.len() * BinaryDataArrayType::Int32.size_of(),
126 );
127
128 mz_array.compression = BinaryCompressionType::Decoded;
129 intensity_array.compression = BinaryCompressionType::Decoded;
130 charge_array.compression = BinaryCompressionType::Decoded;
131
132 for p in peaks.iter() {
133 let mz: f64 = p.mz();
134 let inten: f32 = p.intensity();
135 let charge = p.charge();
136
137 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
138 mz_array.data.extend_from_slice(&raw_bytes);
139
140 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
141 intensity_array.data.extend_from_slice(&raw_bytes);
142
143 let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
144 charge_array.data.extend_from_slice(&raw_bytes);
145 }
146
147 arrays.add(mz_array);
148 arrays.add(intensity_array);
149 arrays.add(charge_array);
150 arrays
151 }
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
157pub enum ArraysAvailable {
158 Unknown,
160 Ok,
162 MissingArrays(Vec<ArrayType>),
164}
165
166pub trait BuildFromArrayMap: Sized {
182 fn arrays_required() -> Option<Vec<ArrayType>> {
186 None
187 }
188
189 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError>;
193
194 fn from_arrays(arrays: &BinaryArrayMap) -> Vec<Self> {
196 Self::try_from_arrays(arrays).unwrap()
197 }
198
199 fn has_arrays_for(arrays: &BinaryArrayMap) -> ArraysAvailable {
201 if let Some(arrays_required) = Self::arrays_required() {
202 let missing: Vec<_> = arrays_required
203 .into_iter()
204 .filter(|array_type| !arrays.has_array(array_type))
205 .collect();
206 if !missing.is_empty() {
207 ArraysAvailable::MissingArrays(missing)
208 } else {
209 ArraysAvailable::Ok
210 }
211 } else {
212 ArraysAvailable::Unknown
213 }
214 }
215}
216
217pub trait BuildArrayMapFrom: Sized {
240 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
244 None
245 }
246
247 fn as_arrays(source: &[Self]) -> BinaryArrayMap;
252}
253
254pub trait BuildArrayMap3DFrom: BuildArrayMapFrom {
260 fn as_arrays_3d(source: &[Self]) -> BinaryArrayMap3D {
272 BuildArrayMapFrom::as_arrays(source).try_into().unwrap()
273 }
274}
275
276pub trait BuildFromArrayMap3D: BuildFromArrayMap {
282 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
288 BuildFromArrayMap::try_from_arrays(&arrays.unstack()?)
289 }
290
291 fn from_arrays_3d(arrays: &BinaryArrayMap3D) -> Vec<Self> {
293 Self::try_from_arrays_3d(arrays).unwrap()
294 }
295
296 fn has_arrays_3d_for(arrays: &BinaryArrayMap3D) -> ArraysAvailable {
299 if let Some(arrays_required) = Self::arrays_required() {
300 let arrays_required: Vec<_> = arrays_required
301 .into_iter()
302 .filter(|a| !a.is_ion_mobility())
303 .collect();
304 let mut arrays_not_seen: HashSet<_> = arrays_required.iter().cloned().collect();
305 let mut missing = Vec::new();
306 for (_, arr) in arrays.iter() {
307 if arr.is_empty() {
308 continue;
309 }
310 missing.clear();
311 for array_type in arrays_required.iter() {
312 if arr.has_array(array_type) {
313 arrays_not_seen.remove(array_type);
314 } else {
315 missing.push(array_type);
316 }
317 }
318 if missing.is_empty() {
319 return ArraysAvailable::Ok;
320 }
321 }
322 if arrays_not_seen.is_empty() {
323 ArraysAvailable::Unknown
324 } else {
325 ArraysAvailable::MissingArrays(arrays_not_seen.into_iter().collect())
326 }
327 } else {
328 ArraysAvailable::Unknown
329 }
330 }
331}
332
333impl BuildArrayMapFrom for CentroidPeak {
337
338 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
340 Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
341 }
342
343 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
344 let mut arrays = BinaryArrayMap::new();
345
346 let mut mz_array = DataArray::from_name_type_size(
347 &ArrayType::MZArray,
348 BinaryDataArrayType::Float64,
349 source.len() * BinaryDataArrayType::Float64.size_of(),
350 );
351 mz_array.unit = Unit::MZ;
352
353 let mut intensity_array = DataArray::from_name_type_size(
354 &ArrayType::IntensityArray,
355 BinaryDataArrayType::Float32,
356 source.len() * BinaryDataArrayType::Float32.size_of(),
357 );
358 intensity_array.unit = Unit::DetectorCounts;
359
360 mz_array.compression = BinaryCompressionType::Decoded;
361 intensity_array.compression = BinaryCompressionType::Decoded;
362
363 for p in source.iter() {
364 let mz: f64 = p.coordinate();
365 let inten: f32 = p.intensity();
366
367 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
368 mz_array.data.extend_from_slice(&raw_bytes);
369
370 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
371 intensity_array.data.extend_from_slice(&raw_bytes);
372 }
373
374 arrays.add(mz_array);
375 arrays.add(intensity_array);
376 arrays
377 }
378}
379
380impl BuildFromArrayMap for CentroidPeak {
381 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
382 let mz_array = arrays.mzs()?;
383 let intensity_array = arrays.intensities()?;
384 let mut peaks = Vec::with_capacity(mz_array.len());
385
386 for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
387 peaks.push(CentroidPeak {
388 mz: *mz,
389 intensity: *intensity,
390 index: i as u32,
391 })
392 }
393 Ok(peaks)
394 }
395
396 fn arrays_required() -> Option<Vec<ArrayType>> {
398 Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
399 }
400}
401
402impl BuildArrayMapFrom for DeconvolutedPeak {
408 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
409 let mut arrays = BinaryArrayMap::new();
410
411 let mut mz_array = DataArray::from_name_type_size(
412 &ArrayType::MZArray,
413 BinaryDataArrayType::Float64,
414 source.len() * BinaryDataArrayType::Float64.size_of(),
415 );
416 mz_array.unit = Unit::MZ;
417
418 let mut intensity_array = DataArray::from_name_type_size(
419 &ArrayType::IntensityArray,
420 BinaryDataArrayType::Float32,
421 source.len() * BinaryDataArrayType::Float32.size_of(),
422 );
423 intensity_array.unit = Unit::DetectorCounts;
424
425 let mut charge_array = DataArray::from_name_type_size(
426 &ArrayType::ChargeArray,
427 BinaryDataArrayType::Int32,
428 source.len() * BinaryDataArrayType::Int32.size_of(),
429 );
430
431 mz_array.compression = BinaryCompressionType::Decoded;
432 intensity_array.compression = BinaryCompressionType::Decoded;
433 charge_array.compression = BinaryCompressionType::Decoded;
434
435 for p in source.iter() {
436 let mz: f64 = p.mz();
437 let inten: f32 = p.intensity();
438 let charge = p.charge();
439
440 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
441 mz_array.data.extend_from_slice(&raw_bytes);
442
443 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
444 intensity_array.data.extend_from_slice(&raw_bytes);
445
446 let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
447 charge_array.data.extend_from_slice(&raw_bytes);
448 }
449
450 arrays.add(mz_array);
451 arrays.add(intensity_array);
452 arrays.add(charge_array);
453 arrays
454 }
455
456 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
459 Some(vec![
460 ArrayType::MZArray,
461 ArrayType::IntensityArray,
462 ArrayType::ChargeArray,
463 ])
464 }
465}
466
467
468impl BuildFromArrayMap for DeconvolutedPeak {
473 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
474 let mz_array = arrays.mzs()?;
475 let intensity_array = arrays.intensities()?;
476 let charge_array = arrays.charges()?;
477 let mut peaks = Vec::with_capacity(mz_array.len());
478 for (i, ((mz, intensity), charge)) in mz_array
479 .iter()
480 .zip(intensity_array.iter())
481 .zip(charge_array.iter())
482 .enumerate()
483 {
484 peaks.push(DeconvolutedPeak {
485 neutral_mass: neutral_mass(*mz, *charge),
486 intensity: *intensity,
487 charge: *charge,
488 index: i as u32,
489 })
490 }
491
492 Ok(peaks)
493 }
494}
495
496impl BuildArrayMapFrom for Feature<MZ, IonMobility> {
508 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
511 Some(vec![
512 ArrayType::MZArray,
513 ArrayType::IntensityArray,
514 ArrayType::RawIonMobilityArray,
515 ArrayType::nonstandard("feature identifier array"),
516 ])
517 }
518
519 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
526 let mut arrays = BinaryArrayMap::new();
527 let n: usize = source.iter().map(|f| f.len()).sum();
528
529 let mut mz_array = DataArray::from_name_type_size(
530 &ArrayType::MZArray,
531 BinaryDataArrayType::Float64,
532 n * BinaryDataArrayType::Float64.size_of(),
533 );
534 mz_array.unit = Unit::MZ;
535
536 let mut intensity_array = DataArray::from_name_type_size(
537 &ArrayType::IntensityArray,
538 BinaryDataArrayType::Float32,
539 n * BinaryDataArrayType::Float32.size_of(),
540 );
541 intensity_array.unit = Unit::DetectorCounts;
542
543 let mut ion_mobility_array = DataArray::from_name_type_size(
544 &ArrayType::RawIonMobilityArray,
545 BinaryDataArrayType::Float64,
546 n * BinaryDataArrayType::Float64.size_of(),
547 );
548
549 let mut marker_array = DataArray::from_name_type_size(
550 &ArrayType::nonstandard("feature identifier array"),
551 BinaryDataArrayType::Int32,
552 n * BinaryDataArrayType::Int32.size_of(),
553 );
554
555 mz_array.compression = BinaryCompressionType::Decoded;
556 intensity_array.compression = BinaryCompressionType::Decoded;
557 ion_mobility_array.compression = BinaryCompressionType::Decoded;
558 marker_array.compression = BinaryCompressionType::Decoded;
559
560 let mut acc = Vec::with_capacity(n);
561 source.iter().enumerate().for_each(|(i, f)| {
562 f.iter()
563 .for_each(|(mz, im, inten)| acc.push((mz, im, inten, i)))
564 });
565 acc.sort_by(|(mz_a, im_a, _, key_a), (mz_b, im_b, _, key_b)| {
566 mz_a.total_cmp(mz_b)
567 .then(im_a.total_cmp(im_b))
568 .then(key_a.cmp(key_b))
569 });
570
571 for (mz, im, inten, key) in acc.iter() {
572 mz_array.data.extend_from_slice(&mz.to_le_bytes());
573 intensity_array.data.extend_from_slice(&inten.to_le_bytes());
574 ion_mobility_array.data.extend_from_slice(&im.to_le_bytes());
575 marker_array
576 .data
577 .extend_from_slice(&(*key as i32).to_le_bytes());
578 }
579
580 arrays.add(mz_array);
581 arrays.add(intensity_array);
582 arrays.add(ion_mobility_array);
583 arrays.add(marker_array);
584 arrays
585 }
586}
587
588impl BuildFromArrayMap for Feature<MZ, IonMobility> {
598 fn arrays_required() -> Option<Vec<ArrayType>> {
601 Self::default().arrays_included()
602 }
603
604 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
605 let mz_array = arrays.mzs()?;
606 let intensity_array = arrays.intensities()?;
607 let im_array = arrays
608 .get(&ArrayType::RawIonMobilityArray)
609 .or_else(|| arrays.get(&ArrayType::RawDriftTimeArray))
610 .or_else(|| arrays.get(&ArrayType::RawInverseReducedIonMobilityArray))
611 .ok_or(ArrayRetrievalError::NotFound(
612 ArrayType::RawIonMobilityArray,
613 ))?
614 .to_f64()?;
615
616 let array_key = ArrayType::nonstandard("feature identifier array");
617 let marker_array = arrays
618 .get(&array_key)
619 .ok_or(ArrayRetrievalError::NotFound(array_key))?
620 .to_i32()?;
621
622 let n = marker_array.iter().map(|i| *i as usize).max();
623
624 let mut features = if let Some(n) = n {
625 let mut features = Vec::with_capacity(n);
626 features.resize(n, Feature::default());
627 features
628 } else {
629 return Ok(Vec::new());
630 };
631
632 mz_array
633 .iter()
634 .zip(intensity_array.iter())
635 .zip(im_array.iter())
636 .zip(marker_array.iter())
637 .for_each(|(((mz, inten), im), key)| {
638 features[(*key) as usize].push_raw(*mz, *im, *inten);
639 });
640
641 Ok(features)
642 }
643}
644
645impl BuildArrayMapFrom for ChargedFeature<Mass, IonMobility> {
655
656 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
660 Some(vec![
661 ArrayType::MZArray,
662 ArrayType::IntensityArray,
663 ArrayType::RawIonMobilityArray,
664 ArrayType::ChargeArray,
665 ArrayType::nonstandard("feature identifier array"),
666 ])
667 }
668
669 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
679 let mut arrays = BinaryArrayMap::new();
680 let n: usize = source.iter().map(|f| f.len()).sum();
681
682 let mut mz_array = DataArray::from_name_type_size(
683 &ArrayType::MZArray,
684 BinaryDataArrayType::Float64,
685 n * BinaryDataArrayType::Float64.size_of(),
686 );
687 mz_array.unit = Unit::MZ;
688
689 let mut intensity_array = DataArray::from_name_type_size(
690 &ArrayType::IntensityArray,
691 BinaryDataArrayType::Float32,
692 n * BinaryDataArrayType::Float32.size_of(),
693 );
694 intensity_array.unit = Unit::DetectorCounts;
695
696 let mut charge_array = DataArray::from_name_type_size(
697 &ArrayType::ChargeArray,
698 BinaryDataArrayType::Int32,
699 n * BinaryDataArrayType::Int32.size_of(),
700 );
701
702 let mut ion_mobility_array = DataArray::from_name_type_size(
703 &ArrayType::RawIonMobilityArray,
704 BinaryDataArrayType::Float64,
705 n * BinaryDataArrayType::Float64.size_of(),
706 );
707
708 let mut marker_array = DataArray::from_name_type_size(
709 &ArrayType::nonstandard("feature identifier array"),
710 BinaryDataArrayType::Int32,
711 n * BinaryDataArrayType::Int32.size_of(),
712 );
713
714 mz_array.compression = BinaryCompressionType::Decoded;
715 intensity_array.compression = BinaryCompressionType::Decoded;
716 ion_mobility_array.compression = BinaryCompressionType::Decoded;
717 marker_array.compression = BinaryCompressionType::Decoded;
718
719 let mut acc = Vec::with_capacity(n);
720 source.iter().enumerate().for_each(|(i, f)| {
721 f.iter().for_each(|(mass, im, inten)| {
722 acc.push((mass_charge_ratio(mass, f.charge), im, inten, f.charge, i))
723 })
724 });
725 acc.sort_by(|(mz_a, im_a, _, _, key_a), (mz_b, im_b, _, _, key_b)| {
726 mz_a.total_cmp(mz_b)
727 .then(im_a.total_cmp(im_b))
728 .then(key_a.cmp(key_b))
729 });
730
731 for (mz, im, inten, charge, key) in acc.iter() {
732 mz_array.data.extend(mz.to_le_bytes());
733 intensity_array.data.extend(inten.to_le_bytes());
734 ion_mobility_array.data.extend(im.to_le_bytes());
735 charge_array.data.extend(charge.to_le_bytes());
736 marker_array.data.extend((*key as i32).to_le_bytes());
737 }
738
739 arrays.add(mz_array);
740 arrays.add(intensity_array);
741 arrays.add(ion_mobility_array);
742 arrays.add(charge_array);
743 arrays.add(marker_array);
744 arrays
745 }
746}
747
748impl BuildFromArrayMap for ChargedFeature<Mass, IonMobility> {
761 fn arrays_required() -> Option<Vec<ArrayType>> {
764 Self::default().arrays_included()
765 }
766
767 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
768 let mz_array = arrays.mzs()?;
769 let intensity_array = arrays.intensities()?;
770 let im_array = arrays
771 .get(&ArrayType::RawIonMobilityArray)
772 .or_else(|| arrays.get(&ArrayType::RawDriftTimeArray))
773 .or_else(|| arrays.get(&ArrayType::RawInverseReducedIonMobilityArray))
774 .ok_or(ArrayRetrievalError::NotFound(
775 ArrayType::RawIonMobilityArray,
776 ))?
777 .to_f64()?;
778
779 let charge_array = arrays
780 .get(&ArrayType::ChargeArray)
781 .ok_or(ArrayRetrievalError::NotFound(ArrayType::ChargeArray))?
782 .to_i32()?;
783
784 let array_key = ArrayType::nonstandard("feature identifier array");
785 let marker_array = arrays
786 .get(&array_key)
787 .ok_or(ArrayRetrievalError::NotFound(array_key))?
788 .to_i32()?;
789
790 let n = marker_array.iter().map(|i| *i as usize).max();
791
792 let mut features = if let Some(n) = n {
793 let mut features = Vec::with_capacity(n);
794 features.resize(n, ChargedFeature::default());
795 features
796 } else {
797 return Ok(Vec::new());
798 };
799
800 mz_array
801 .iter()
802 .zip(intensity_array.iter())
803 .zip(im_array.iter().zip(charge_array.iter()))
804 .zip(marker_array.iter())
805 .for_each(|(((mz, inten), (im, charge)), key)| {
806 let f = &mut features[(*key) as usize];
807 if f.is_empty() {
808 f.charge = *charge;
809 }
810 f.push_raw(neutral_mass(*mz, *charge), *im, *inten);
811 });
812
813 Ok(features)
814 }
815}
816
817impl BuildArrayMap3DFrom for Feature<MZ, IonMobility> {}
819
820impl BuildFromArrayMap3D for Feature<MZ, IonMobility> {
821 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
822 let key = ArrayType::nonstandard("feature identifier array");
823 let mut n: usize = 0;
824 for (_, arr) in arrays.iter() {
825 if arr.is_empty() {
826 continue;
827 }
828 if let Some(arr) = arr.get(&key) {
829 if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
830 n = n.max(i);
831 }
832 }
833 }
834
835 if n == 0 {
836 return Ok(Vec::new());
837 }
838 n += 1;
839 let mut index = Vec::with_capacity(n);
840 index.resize(n, Feature::default());
841
842 for (im, arr) in arrays.iter() {
843 if arr.is_empty() {
844 continue;
845 }
846
847 let mz_array = arr.mzs()?;
848 let intensity_array = arr.intensities()?;
849 let marker_array = arr
850 .get(&key)
851 .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
852 .to_i32()?;
853
854 for ((mz, inten), key_i) in mz_array
855 .iter()
856 .zip(intensity_array.iter())
857 .zip(marker_array.iter())
858 {
859 index[(*key_i) as usize].push_raw(*mz, im, *inten);
860 }
861 }
862
863 Ok(index)
864 }
865}
866
867impl BuildArrayMap3DFrom for ChargedFeature<Mass, IonMobility> {}
869
870impl BuildFromArrayMap3D for ChargedFeature<Mass, IonMobility> {
871 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
872 let key = ArrayType::nonstandard("feature identifier array");
873 let mut n: usize = 0;
874 for (_, arr) in arrays.iter() {
875 if arr.is_empty() {
876 continue;
877 }
878 if let Some(arr) = arr.get(&key) {
879 if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
880 n = n.max(i);
881 }
882 }
883 }
884
885 if n == 0 {
886 return Ok(Vec::new());
887 }
888 n += 1;
889 let mut index = Vec::with_capacity(n);
890 index.resize(n, ChargedFeature::default());
891
892 for (im, arr) in arrays.iter() {
893 if arr.is_empty() {
894 continue;
895 }
896
897 let mz_array = arr.mzs()?;
898 let intensity_array = arr.intensities()?;
899 let marker_array = arr
900 .get(&key)
901 .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
902 .to_i32()?;
903 let charge_array = arr.charges()?;
904
905 for ((mz, inten), (charge, key_i)) in mz_array
906 .iter()
907 .zip(intensity_array.iter())
908 .zip(charge_array.iter().zip(marker_array.iter()))
909 {
910 let f = &mut index[(*key_i) as usize];
911 f.push_raw(*mz, im, *inten);
912 f.charge = *charge;
913 }
914 }
915
916 Ok(index)
917 }
918}
919
920impl BuildArrayMapFrom for IonMobilityAwareCentroidPeak {
924 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
925 Some(vec![
926 ArrayType::MZArray,
927 ArrayType::IntensityArray,
928 ArrayType::MeanIonMobilityArray,
929 ])
930 }
931
932 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
933 let mut arrays = BinaryArrayMap::new();
934
935 let mut mz_array = DataArray::from_name_type_size(
936 &ArrayType::MZArray,
937 BinaryDataArrayType::Float64,
938 source.len() * BinaryDataArrayType::Float64.size_of(),
939 );
940 mz_array.unit = Unit::MZ;
941
942 let mut intensity_array = DataArray::from_name_type_size(
943 &ArrayType::IntensityArray,
944 BinaryDataArrayType::Float32,
945 source.len() * BinaryDataArrayType::Float32.size_of(),
946 );
947 intensity_array.unit = Unit::DetectorCounts;
948
949 let mut im_array = DataArray::from_name_type_size(
950 &ArrayType::MeanIonMobilityArray,
951 BinaryDataArrayType::Float64,
952 source.len() * BinaryDataArrayType::Float64.size_of(),
953 );
954
955 mz_array.compression = BinaryCompressionType::Decoded;
956 intensity_array.compression = BinaryCompressionType::Decoded;
957 im_array.compression = BinaryCompressionType::Decoded;
958
959 for p in source.iter() {
960 let mz: f64 = p.mz();
961 let inten: f32 = p.intensity();
962 let im = p.ion_mobility();
963
964 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
965 mz_array.data.extend_from_slice(&raw_bytes);
966
967 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
968 intensity_array.data.extend_from_slice(&raw_bytes);
969
970 let raw_bytes: [u8; mem::size_of::<f64>()] = im.to_le_bytes();
971 im_array.data.extend_from_slice(&raw_bytes);
972 }
973
974 arrays.add(mz_array);
975 arrays.add(intensity_array);
976 arrays.add(im_array);
977 arrays
978 }
979}
980
981impl BuildFromArrayMap for IonMobilityAwareCentroidPeak {
983 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
984 let mz_array = arrays.mzs()?;
985 let intensity_array = arrays.intensities()?;
986 let (im_array, _) = arrays.ion_mobility()?;
987 let mut peaks = Vec::with_capacity(mz_array.len());
988
989 for (i, (mz, (intensity, ion_mobility))) in mz_array
990 .iter()
991 .zip(intensity_array.iter().zip(im_array.iter()))
992 .enumerate()
993 {
994 peaks.push(IonMobilityAwareCentroidPeak {
995 mz: *mz,
996 intensity: *intensity,
997 index: i as u32,
998 ion_mobility: *ion_mobility,
999 })
1000 }
1001 Ok(peaks)
1002 }
1003
1004 fn arrays_required() -> Option<Vec<ArrayType>> {
1005 Some(vec![
1006 ArrayType::MZArray,
1007 ArrayType::IntensityArray,
1008 ArrayType::IonMobilityArray,
1009 ])
1010 }
1011}
1012
1013impl BuildArrayMapFrom for IonMobilityAwareDeconvolutedPeak {
1015 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
1016 Some(vec![
1017 ArrayType::MZArray,
1018 ArrayType::IntensityArray,
1019 ArrayType::ChargeArray,
1020 ArrayType::MeanIonMobilityArray,
1021 ])
1022 }
1023
1024 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
1025 let mut arrays = BinaryArrayMap::new();
1026
1027 let mut mz_array = DataArray::from_name_type_size(
1028 &ArrayType::MZArray,
1029 BinaryDataArrayType::Float64,
1030 source.len() * BinaryDataArrayType::Float64.size_of(),
1031 );
1032 mz_array.unit = Unit::MZ;
1033
1034 let mut intensity_array = DataArray::from_name_type_size(
1035 &ArrayType::IntensityArray,
1036 BinaryDataArrayType::Float32,
1037 source.len() * BinaryDataArrayType::Float32.size_of(),
1038 );
1039 intensity_array.unit = Unit::DetectorCounts;
1040
1041 let mut charge_array = DataArray::from_name_type_size(
1042 &ArrayType::ChargeArray,
1043 BinaryDataArrayType::Int32,
1044 source.len() * BinaryDataArrayType::Int32.size_of(),
1045 );
1046
1047 let mut im_array = DataArray::from_name_type_size(
1048 &ArrayType::MeanIonMobilityArray,
1049 BinaryDataArrayType::Float64,
1050 source.len() * BinaryDataArrayType::Float64.size_of(),
1051 );
1052
1053 mz_array.compression = BinaryCompressionType::Decoded;
1054 intensity_array.compression = BinaryCompressionType::Decoded;
1055 im_array.compression = BinaryCompressionType::Decoded;
1056 charge_array.compression = BinaryCompressionType::Decoded;
1057
1058 for p in source.iter() {
1059 let mz: f64 = p.mz();
1060 let inten: f32 = p.intensity();
1061 let im = p.ion_mobility();
1062
1063 mz_array.data.extend_from_slice(&mz.to_le_bytes());
1064 intensity_array.data.extend_from_slice(&inten.to_le_bytes());
1065 im_array.data.extend_from_slice(&im.to_le_bytes());
1066 charge_array
1067 .data
1068 .extend_from_slice(&p.charge().to_le_bytes());
1069 }
1070
1071 arrays.add(mz_array);
1072 arrays.add(intensity_array);
1073 arrays.add(im_array);
1074 arrays.add(charge_array);
1075 arrays
1076 }
1077}
1078
1079impl BuildFromArrayMap for IonMobilityAwareDeconvolutedPeak {
1081 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
1082 let mz_array = arrays.mzs()?;
1083 let intensity_array = arrays.intensities()?;
1084 let charge_array = arrays.charges()?;
1085 let (im_array, _) = arrays.ion_mobility()?;
1086 let mut peaks = Vec::with_capacity(mz_array.len());
1087
1088 for (i, (mz, (intensity, (ion_mobility, charge)))) in mz_array
1089 .iter()
1090 .zip(
1091 intensity_array
1092 .iter()
1093 .zip(im_array.iter().zip(charge_array.iter())),
1094 )
1095 .enumerate()
1096 {
1097 let mass = neutral_mass(*mz, *charge);
1098 peaks.push(IonMobilityAwareDeconvolutedPeak {
1099 neutral_mass: mass,
1100 intensity: *intensity,
1101 index: i as u32,
1102 ion_mobility: *ion_mobility,
1103 charge: *charge,
1104 })
1105 }
1106 Ok(peaks)
1107 }
1108
1109 fn arrays_required() -> Option<Vec<ArrayType>> {
1110 Some(vec![
1111 ArrayType::MZArray,
1112 ArrayType::IntensityArray,
1113 ArrayType::ChargeArray,
1114 ArrayType::IonMobilityArray,
1115 ])
1116 }
1117}