1use std::{collections::HashSet, convert::TryInto, mem};
2
3use mzpeaks::{
4 CentroidLike, CentroidPeak, CoordinateLike, DeconvolutedPeak, DeconvolutedPeakSet, IonMobility,
5 MZ, MZPeakSetType, Mass, PeakSet,
6 feature::{ChargedFeature, Feature},
7 peak::{IonMobilityAwareCentroidPeak, IonMobilityAwareDeconvolutedPeak},
8 prelude::*,
9};
10
11use mzdata_param::Unit;
12
13use crate::utils::{mass_charge_ratio, neutral_mass};
14
15use super::{
16 BinaryArrayMap3D, ByteArrayView,
17 array::DataArray,
18 encodings::{ArrayRetrievalError, ArrayType, BinaryDataArrayType},
19 map::BinaryArrayMap,
20};
21
22impl From<&PeakSet> for BinaryArrayMap {
23 fn from(peaks: &PeakSet) -> BinaryArrayMap {
24 let mut arrays = BinaryArrayMap::new();
25
26 let mut mz_array = DataArray::from_name_type_size(
27 &ArrayType::MZArray,
28 BinaryDataArrayType::Float64,
29 peaks.len() * BinaryDataArrayType::Float64.size_of(),
30 );
31
32 let mut intensity_array = DataArray::from_name_type_size(
33 &ArrayType::IntensityArray,
34 BinaryDataArrayType::Float32,
35 peaks.len() * BinaryDataArrayType::Float32.size_of(),
36 );
37
38 for p in peaks.iter() {
39 let mz: f64 = p.coordinate();
40 let inten: f32 = p.intensity();
41
42 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
43 mz_array.data.extend(raw_bytes);
44
45 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
46 intensity_array.data.extend(raw_bytes);
47 }
48
49 arrays.add(mz_array);
50 arrays.add(intensity_array);
51 arrays
52 }
53}
54
55impl<C: CentroidLike + From<CentroidPeak>> From<BinaryArrayMap> for MZPeakSetType<C> {
56 fn from(arrays: BinaryArrayMap) -> MZPeakSetType<C> {
57 (&arrays).into()
58 }
59}
60
61impl<C: CentroidLike + From<CentroidPeak>> From<&BinaryArrayMap> for MZPeakSetType<C> {
62 fn from(arrays: &BinaryArrayMap) -> MZPeakSetType<C> {
63 let mz_array = arrays.mzs().unwrap();
64 let intensity_array = arrays.intensities().unwrap();
65 let mut peaks = Vec::with_capacity(mz_array.len());
66
67 for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
68 peaks.push(
69 CentroidPeak {
70 mz: *mz,
71 intensity: *intensity,
72 index: i as u32,
73 }
74 .into(),
75 )
76 }
77 MZPeakSetType::<C>::new(peaks)
78 }
79}
80
81impl From<&BinaryArrayMap> for DeconvolutedPeakSet {
82 fn from(arrays: &BinaryArrayMap) -> DeconvolutedPeakSet {
83 let mz_array = arrays.mzs().unwrap();
84 let intensity_array = arrays.intensities().unwrap();
85 let charge_array = arrays
86 .charges()
87 .expect("Charge state array is required for deconvoluted peaks");
88 let mut peaks = Vec::with_capacity(mz_array.len());
89 for (i, ((mz, intensity), charge)) in mz_array
90 .iter()
91 .zip(intensity_array.iter())
92 .zip(charge_array.iter())
93 .enumerate()
94 {
95 peaks.push(DeconvolutedPeak {
96 neutral_mass: neutral_mass(*mz, *charge),
97 intensity: *intensity,
98 charge: *charge,
99 index: i as u32,
100 })
101 }
102
103 DeconvolutedPeakSet::new(peaks)
104 }
105}
106
107impl From<&DeconvolutedPeakSet> for BinaryArrayMap {
108 fn from(peaks: &DeconvolutedPeakSet) -> BinaryArrayMap {
109 let mut arrays = BinaryArrayMap::new();
110
111 let mut mz_array = DataArray::from_name_type_size(
112 &ArrayType::MZArray,
113 BinaryDataArrayType::Float64,
114 peaks.len() * BinaryDataArrayType::Float64.size_of(),
115 );
116
117 let mut intensity_array = DataArray::from_name_type_size(
118 &ArrayType::IntensityArray,
119 BinaryDataArrayType::Float32,
120 peaks.len() * BinaryDataArrayType::Float32.size_of(),
121 );
122
123 let mut charge_array = DataArray::from_name_type_size(
124 &ArrayType::ChargeArray,
125 BinaryDataArrayType::Int32,
126 peaks.len() * BinaryDataArrayType::Int32.size_of(),
127 );
128
129 for p in peaks.iter() {
130 let mz: f64 = p.mz();
131 let inten: f32 = p.intensity();
132 let charge = p.charge();
133
134 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
135 mz_array.data.extend_from_slice(&raw_bytes);
136
137 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
138 intensity_array.data.extend_from_slice(&raw_bytes);
139
140 let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
141 charge_array.data.extend_from_slice(&raw_bytes);
142 }
143
144 arrays.add(mz_array);
145 arrays.add(intensity_array);
146 arrays.add(charge_array);
147 arrays
148 }
149}
150
151#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum ArraysAvailable {
155 Unknown,
157 Ok,
159 MissingArrays(Vec<ArrayType>),
161}
162
163pub trait BuildFromArrayMap: Sized {
179 fn arrays_required() -> Option<Vec<ArrayType>> {
183 None
184 }
185
186 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError>;
190
191 fn from_arrays(arrays: &BinaryArrayMap) -> Vec<Self> {
193 Self::try_from_arrays(arrays).unwrap()
194 }
195
196 fn has_arrays_for(arrays: &BinaryArrayMap) -> ArraysAvailable {
198 if let Some(arrays_required) = Self::arrays_required() {
199 let missing: Vec<_> = arrays_required
200 .into_iter()
201 .filter(|array_type| !arrays.has_array(array_type))
202 .collect();
203 if !missing.is_empty() {
204 ArraysAvailable::MissingArrays(missing)
205 } else {
206 ArraysAvailable::Ok
207 }
208 } else {
209 ArraysAvailable::Unknown
210 }
211 }
212}
213
214pub trait BuildArrayMapFrom: Sized {
237 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
241 None
242 }
243
244 fn as_arrays(source: &[Self]) -> BinaryArrayMap;
249}
250
251pub trait BuildArrayMap3DFrom: BuildArrayMapFrom {
257 fn as_arrays_3d(source: &[Self]) -> BinaryArrayMap3D {
269 BuildArrayMapFrom::as_arrays(source).try_into().unwrap()
270 }
271}
272
273pub trait BuildFromArrayMap3D: BuildFromArrayMap {
279 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
285 BuildFromArrayMap::try_from_arrays(&arrays.unstack()?)
286 }
287
288 fn from_arrays_3d(arrays: &BinaryArrayMap3D) -> Vec<Self> {
290 Self::try_from_arrays_3d(arrays).unwrap()
291 }
292
293 fn has_arrays_3d_for(arrays: &BinaryArrayMap3D) -> ArraysAvailable {
296 if let Some(arrays_required) = Self::arrays_required() {
297 let arrays_required: Vec<_> = arrays_required
298 .into_iter()
299 .filter(|a| !a.is_ion_mobility())
300 .collect();
301 let mut arrays_not_seen: HashSet<_> = arrays_required.iter().cloned().collect();
302 let mut missing = Vec::new();
303 for (_, arr) in arrays.iter() {
304 if arr.is_empty() {
305 continue;
306 }
307 missing.clear();
308 for array_type in arrays_required.iter() {
309 if arr.has_array(array_type) {
310 arrays_not_seen.remove(array_type);
311 } else {
312 missing.push(array_type);
313 }
314 }
315 if missing.is_empty() {
316 return ArraysAvailable::Ok;
317 }
318 }
319 if arrays_not_seen.is_empty() {
320 ArraysAvailable::Unknown
321 } else {
322 ArraysAvailable::MissingArrays(arrays_not_seen.into_iter().collect())
323 }
324 } else {
325 ArraysAvailable::Unknown
326 }
327 }
328}
329
330impl BuildArrayMapFrom for CentroidPeak {
334 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
336 Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
337 }
338
339 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
340 let mut arrays = BinaryArrayMap::new();
341
342 let mut mz_array = DataArray::from_name_type_size(
343 &ArrayType::MZArray,
344 BinaryDataArrayType::Float64,
345 source.len() * BinaryDataArrayType::Float64.size_of(),
346 );
347 mz_array.unit = Unit::MZ;
348
349 let mut intensity_array = DataArray::from_name_type_size(
350 &ArrayType::IntensityArray,
351 BinaryDataArrayType::Float32,
352 source.len() * BinaryDataArrayType::Float32.size_of(),
353 );
354 intensity_array.unit = Unit::DetectorCounts;
355
356 for p in source.iter() {
357 let mz: f64 = p.coordinate();
358 let inten: f32 = p.intensity();
359
360 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
361 mz_array.data.extend_from_slice(&raw_bytes);
362
363 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
364 intensity_array.data.extend_from_slice(&raw_bytes);
365 }
366
367 arrays.add(mz_array);
368 arrays.add(intensity_array);
369 arrays
370 }
371}
372
373impl BuildFromArrayMap for CentroidPeak {
374 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
375 let mz_array = arrays.mzs()?;
376 let intensity_array = arrays.intensities()?;
377 let mut peaks = Vec::with_capacity(mz_array.len());
378
379 for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
380 peaks.push(CentroidPeak {
381 mz: *mz,
382 intensity: *intensity,
383 index: i as u32,
384 })
385 }
386 Ok(peaks)
387 }
388
389 fn arrays_required() -> Option<Vec<ArrayType>> {
391 Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
392 }
393}
394
395impl BuildArrayMapFrom for DeconvolutedPeak {
401 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
402 let mut arrays = BinaryArrayMap::new();
403
404 let mut mz_array = DataArray::from_name_type_size(
405 &ArrayType::MZArray,
406 BinaryDataArrayType::Float64,
407 source.len() * BinaryDataArrayType::Float64.size_of(),
408 );
409 mz_array.unit = Unit::MZ;
410
411 let mut intensity_array = DataArray::from_name_type_size(
412 &ArrayType::IntensityArray,
413 BinaryDataArrayType::Float32,
414 source.len() * BinaryDataArrayType::Float32.size_of(),
415 );
416 intensity_array.unit = Unit::DetectorCounts;
417
418 let mut charge_array = DataArray::from_name_type_size(
419 &ArrayType::ChargeArray,
420 BinaryDataArrayType::Int32,
421 source.len() * BinaryDataArrayType::Int32.size_of(),
422 );
423
424 for p in source.iter() {
425 let mz: f64 = p.mz();
426 let inten: f32 = p.intensity();
427 let charge = p.charge();
428
429 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
430 mz_array.data.extend_from_slice(&raw_bytes);
431
432 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
433 intensity_array.data.extend_from_slice(&raw_bytes);
434
435 let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
436 charge_array.data.extend_from_slice(&raw_bytes);
437 }
438
439 arrays.add(mz_array);
440 arrays.add(intensity_array);
441 arrays.add(charge_array);
442 arrays
443 }
444
445 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
448 Some(vec![
449 ArrayType::MZArray,
450 ArrayType::IntensityArray,
451 ArrayType::ChargeArray,
452 ])
453 }
454}
455
456impl BuildFromArrayMap for DeconvolutedPeak {
461 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
462 let mz_array = arrays.mzs()?;
463 let intensity_array = arrays.intensities()?;
464 let charge_array = arrays.charges()?;
465 let mut peaks = Vec::with_capacity(mz_array.len());
466 for (i, ((mz, intensity), charge)) in mz_array
467 .iter()
468 .zip(intensity_array.iter())
469 .zip(charge_array.iter())
470 .enumerate()
471 {
472 peaks.push(DeconvolutedPeak {
473 neutral_mass: neutral_mass(*mz, *charge),
474 intensity: *intensity,
475 charge: *charge,
476 index: i as u32,
477 })
478 }
479
480 Ok(peaks)
481 }
482}
483
484impl BuildArrayMapFrom for Feature<MZ, IonMobility> {
496 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
499 Some(vec![
500 ArrayType::MZArray,
501 ArrayType::IntensityArray,
502 ArrayType::RawIonMobilityArray,
503 ArrayType::nonstandard("feature identifier array"),
504 ])
505 }
506
507 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
514 let mut arrays = BinaryArrayMap::new();
515 let n: usize = source.iter().map(|f| f.len()).sum();
516
517 let mut mz_array = DataArray::from_name_type_size(
518 &ArrayType::MZArray,
519 BinaryDataArrayType::Float64,
520 n * BinaryDataArrayType::Float64.size_of(),
521 );
522 mz_array.unit = Unit::MZ;
523
524 let mut intensity_array = DataArray::from_name_type_size(
525 &ArrayType::IntensityArray,
526 BinaryDataArrayType::Float32,
527 n * BinaryDataArrayType::Float32.size_of(),
528 );
529 intensity_array.unit = Unit::DetectorCounts;
530
531 let mut ion_mobility_array = DataArray::from_name_type_size(
532 &ArrayType::RawIonMobilityArray,
533 BinaryDataArrayType::Float64,
534 n * BinaryDataArrayType::Float64.size_of(),
535 );
536
537 let mut marker_array = DataArray::from_name_type_size(
538 &ArrayType::nonstandard("feature identifier array"),
539 BinaryDataArrayType::Int32,
540 n * BinaryDataArrayType::Int32.size_of(),
541 );
542
543 let mut acc = Vec::with_capacity(n);
544 source.iter().enumerate().for_each(|(i, f)| {
545 f.iter()
546 .for_each(|(mz, im, inten)| acc.push((mz, im, inten, i)))
547 });
548 acc.sort_by(|(mz_a, im_a, _, key_a), (mz_b, im_b, _, key_b)| {
549 mz_a.total_cmp(mz_b)
550 .then(im_a.total_cmp(im_b))
551 .then(key_a.cmp(key_b))
552 });
553
554 for (mz, im, inten, key) in acc.iter() {
555 mz_array.data.extend_from_slice(&mz.to_le_bytes());
556 intensity_array.data.extend_from_slice(&inten.to_le_bytes());
557 ion_mobility_array.data.extend_from_slice(&im.to_le_bytes());
558 marker_array
559 .data
560 .extend_from_slice(&(*key as i32).to_le_bytes());
561 }
562
563 arrays.add(mz_array);
564 arrays.add(intensity_array);
565 arrays.add(ion_mobility_array);
566 arrays.add(marker_array);
567 arrays
568 }
569}
570
571impl BuildFromArrayMap for Feature<MZ, IonMobility> {
581 fn arrays_required() -> Option<Vec<ArrayType>> {
584 Self::default().arrays_included()
585 }
586
587 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
588 let mz_array = arrays.mzs()?;
589 let intensity_array = arrays.intensities()?;
590 let im_array = arrays
591 .get(&ArrayType::RawIonMobilityArray)
592 .or_else(|| arrays.get(&ArrayType::RawDriftTimeArray))
593 .or_else(|| arrays.get(&ArrayType::RawInverseReducedIonMobilityArray))
594 .ok_or(ArrayRetrievalError::NotFound(
595 ArrayType::RawIonMobilityArray,
596 ))?
597 .to_f64()?;
598
599 let array_key = ArrayType::nonstandard("feature identifier array");
600 let marker_array = arrays
601 .get(&array_key)
602 .ok_or(ArrayRetrievalError::NotFound(array_key))?
603 .to_i32()?;
604
605 let n = marker_array.iter().map(|i| *i as usize).max();
606
607 let mut features = if let Some(n) = n {
608 let mut features = Vec::with_capacity(n);
609 features.resize(n, Feature::default());
610 features
611 } else {
612 return Ok(Vec::new());
613 };
614
615 mz_array
616 .iter()
617 .zip(intensity_array.iter())
618 .zip(im_array.iter())
619 .zip(marker_array.iter())
620 .for_each(|(((mz, inten), im), key)| {
621 features[(*key) as usize].push_raw(*mz, *im, *inten);
622 });
623
624 Ok(features)
625 }
626}
627
628impl BuildArrayMapFrom for ChargedFeature<Mass, IonMobility> {
638 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
642 Some(vec![
643 ArrayType::MZArray,
644 ArrayType::IntensityArray,
645 ArrayType::RawIonMobilityArray,
646 ArrayType::ChargeArray,
647 ArrayType::nonstandard("feature identifier array"),
648 ])
649 }
650
651 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
661 let mut arrays = BinaryArrayMap::new();
662 let n: usize = source.iter().map(|f| f.len()).sum();
663
664 let mut mz_array = DataArray::from_name_type_size(
665 &ArrayType::MZArray,
666 BinaryDataArrayType::Float64,
667 n * BinaryDataArrayType::Float64.size_of(),
668 );
669 mz_array.unit = Unit::MZ;
670
671 let mut intensity_array = DataArray::from_name_type_size(
672 &ArrayType::IntensityArray,
673 BinaryDataArrayType::Float32,
674 n * BinaryDataArrayType::Float32.size_of(),
675 );
676 intensity_array.unit = Unit::DetectorCounts;
677
678 let mut charge_array = DataArray::from_name_type_size(
679 &ArrayType::ChargeArray,
680 BinaryDataArrayType::Int32,
681 n * BinaryDataArrayType::Int32.size_of(),
682 );
683
684 let mut ion_mobility_array = DataArray::from_name_type_size(
685 &ArrayType::RawIonMobilityArray,
686 BinaryDataArrayType::Float64,
687 n * BinaryDataArrayType::Float64.size_of(),
688 );
689
690 let mut marker_array = DataArray::from_name_type_size(
691 &ArrayType::nonstandard("feature identifier array"),
692 BinaryDataArrayType::Int32,
693 n * BinaryDataArrayType::Int32.size_of(),
694 );
695
696 let mut acc = Vec::with_capacity(n);
697 source.iter().enumerate().for_each(|(i, f)| {
698 f.iter().for_each(|(mass, im, inten)| {
699 acc.push((mass_charge_ratio(mass, f.charge), im, inten, f.charge, i))
700 })
701 });
702 acc.sort_by(|(mz_a, im_a, _, _, key_a), (mz_b, im_b, _, _, key_b)| {
703 mz_a.total_cmp(mz_b)
704 .then(im_a.total_cmp(im_b))
705 .then(key_a.cmp(key_b))
706 });
707
708 for (mz, im, inten, charge, key) in acc.iter() {
709 mz_array.data.extend(mz.to_le_bytes());
710 intensity_array.data.extend(inten.to_le_bytes());
711 ion_mobility_array.data.extend(im.to_le_bytes());
712 charge_array.data.extend(charge.to_le_bytes());
713 marker_array.data.extend((*key as i32).to_le_bytes());
714 }
715
716 arrays.add(mz_array);
717 arrays.add(intensity_array);
718 arrays.add(ion_mobility_array);
719 arrays.add(charge_array);
720 arrays.add(marker_array);
721 arrays
722 }
723}
724
725impl BuildFromArrayMap for ChargedFeature<Mass, IonMobility> {
738 fn arrays_required() -> Option<Vec<ArrayType>> {
741 Self::default().arrays_included()
742 }
743
744 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
745 let mz_array = arrays.mzs()?;
746 let intensity_array = arrays.intensities()?;
747 let im_array = arrays
748 .get(&ArrayType::RawIonMobilityArray)
749 .or_else(|| arrays.get(&ArrayType::RawDriftTimeArray))
750 .or_else(|| arrays.get(&ArrayType::RawInverseReducedIonMobilityArray))
751 .ok_or(ArrayRetrievalError::NotFound(
752 ArrayType::RawIonMobilityArray,
753 ))?
754 .to_f64()?;
755
756 let charge_array = arrays
757 .get(&ArrayType::ChargeArray)
758 .ok_or(ArrayRetrievalError::NotFound(ArrayType::ChargeArray))?
759 .to_i32()?;
760
761 let array_key = ArrayType::nonstandard("feature identifier array");
762 let marker_array = arrays
763 .get(&array_key)
764 .ok_or(ArrayRetrievalError::NotFound(array_key))?
765 .to_i32()?;
766
767 let n = marker_array.iter().map(|i| *i as usize).max();
768
769 let mut features = if let Some(n) = n {
770 let mut features = Vec::with_capacity(n);
771 features.resize(n, ChargedFeature::default());
772 features
773 } else {
774 return Ok(Vec::new());
775 };
776
777 mz_array
778 .iter()
779 .zip(intensity_array.iter())
780 .zip(im_array.iter().zip(charge_array.iter()))
781 .zip(marker_array.iter())
782 .for_each(|(((mz, inten), (im, charge)), key)| {
783 let f = &mut features[(*key) as usize];
784 if f.is_empty() {
785 f.charge = *charge;
786 }
787 f.push_raw(neutral_mass(*mz, *charge), *im, *inten);
788 });
789
790 Ok(features)
791 }
792}
793
794impl BuildArrayMap3DFrom for Feature<MZ, IonMobility> {}
796
797impl BuildFromArrayMap3D for Feature<MZ, IonMobility> {
798 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
799 let key = ArrayType::nonstandard("feature identifier array");
800 let mut n: usize = 0;
801 for (_, arr) in arrays.iter() {
802 if arr.is_empty() {
803 continue;
804 }
805 if let Some(arr) = arr.get(&key) {
806 if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
807 n = n.max(i);
808 }
809 }
810 }
811
812 if n == 0 {
813 return Ok(Vec::new());
814 }
815 n += 1;
816 let mut index = Vec::with_capacity(n);
817 index.resize(n, Feature::default());
818
819 for (im, arr) in arrays.iter() {
820 if arr.is_empty() {
821 continue;
822 }
823
824 let mz_array = arr.mzs()?;
825 let intensity_array = arr.intensities()?;
826 let marker_array = arr
827 .get(&key)
828 .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
829 .to_i32()?;
830
831 for ((mz, inten), key_i) in mz_array
832 .iter()
833 .zip(intensity_array.iter())
834 .zip(marker_array.iter())
835 {
836 index[(*key_i) as usize].push_raw(*mz, im, *inten);
837 }
838 }
839
840 Ok(index)
841 }
842}
843
844impl BuildArrayMap3DFrom for ChargedFeature<Mass, IonMobility> {}
846
847impl BuildFromArrayMap3D for ChargedFeature<Mass, IonMobility> {
848 fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
849 let key = ArrayType::nonstandard("feature identifier array");
850 let mut n: usize = 0;
851 for (_, arr) in arrays.iter() {
852 if arr.is_empty() {
853 continue;
854 }
855 if let Some(arr) = arr.get(&key) {
856 if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
857 n = n.max(i);
858 }
859 }
860 }
861
862 if n == 0 {
863 return Ok(Vec::new());
864 }
865 n += 1;
866 let mut index = Vec::with_capacity(n);
867 index.resize(n, ChargedFeature::default());
868
869 for (im, arr) in arrays.iter() {
870 if arr.is_empty() {
871 continue;
872 }
873
874 let mz_array = arr.mzs()?;
875 let intensity_array = arr.intensities()?;
876 let marker_array = arr
877 .get(&key)
878 .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
879 .to_i32()?;
880 let charge_array = arr.charges()?;
881
882 for ((mz, inten), (charge, key_i)) in mz_array
883 .iter()
884 .zip(intensity_array.iter())
885 .zip(charge_array.iter().zip(marker_array.iter()))
886 {
887 let f = &mut index[(*key_i) as usize];
888 f.push_raw(*mz, im, *inten);
889 f.charge = *charge;
890 }
891 }
892
893 Ok(index)
894 }
895}
896
897impl BuildArrayMapFrom for IonMobilityAwareCentroidPeak {
901 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
902 Some(vec![
903 ArrayType::MZArray,
904 ArrayType::IntensityArray,
905 ArrayType::MeanIonMobilityArray,
906 ])
907 }
908
909 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
910 let mut arrays = BinaryArrayMap::new();
911
912 let mut mz_array = DataArray::from_name_type_size(
913 &ArrayType::MZArray,
914 BinaryDataArrayType::Float64,
915 source.len() * BinaryDataArrayType::Float64.size_of(),
916 );
917 mz_array.unit = Unit::MZ;
918
919 let mut intensity_array = DataArray::from_name_type_size(
920 &ArrayType::IntensityArray,
921 BinaryDataArrayType::Float32,
922 source.len() * BinaryDataArrayType::Float32.size_of(),
923 );
924 intensity_array.unit = Unit::DetectorCounts;
925
926 let mut im_array = DataArray::from_name_type_size(
927 &ArrayType::MeanIonMobilityArray,
928 BinaryDataArrayType::Float64,
929 source.len() * BinaryDataArrayType::Float64.size_of(),
930 );
931
932 for p in source.iter() {
933 let mz: f64 = p.mz();
934 let inten: f32 = p.intensity();
935 let im = p.ion_mobility();
936
937 let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
938 mz_array.data.extend_from_slice(&raw_bytes);
939
940 let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
941 intensity_array.data.extend_from_slice(&raw_bytes);
942
943 let raw_bytes: [u8; mem::size_of::<f64>()] = im.to_le_bytes();
944 im_array.data.extend_from_slice(&raw_bytes);
945 }
946
947 arrays.add(mz_array);
948 arrays.add(intensity_array);
949 arrays.add(im_array);
950 arrays
951 }
952}
953
954impl BuildFromArrayMap for IonMobilityAwareCentroidPeak {
956 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
957 let mz_array = arrays.mzs()?;
958 let intensity_array = arrays.intensities()?;
959 let (im_array, _) = arrays.ion_mobility()?;
960 let mut peaks = Vec::with_capacity(mz_array.len());
961
962 for (i, (mz, (intensity, ion_mobility))) in mz_array
963 .iter()
964 .zip(intensity_array.iter().zip(im_array.iter()))
965 .enumerate()
966 {
967 peaks.push(IonMobilityAwareCentroidPeak {
968 mz: *mz,
969 intensity: *intensity,
970 index: i as u32,
971 ion_mobility: *ion_mobility,
972 })
973 }
974 Ok(peaks)
975 }
976
977 fn arrays_required() -> Option<Vec<ArrayType>> {
978 Some(vec![
979 ArrayType::MZArray,
980 ArrayType::IntensityArray,
981 ArrayType::IonMobilityArray,
982 ])
983 }
984}
985
986impl BuildArrayMapFrom for IonMobilityAwareDeconvolutedPeak {
988 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
989 Some(vec![
990 ArrayType::MZArray,
991 ArrayType::IntensityArray,
992 ArrayType::ChargeArray,
993 ArrayType::MeanIonMobilityArray,
994 ])
995 }
996
997 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
998 let mut arrays = BinaryArrayMap::new();
999
1000 let mut mz_array = DataArray::from_name_type_size(
1001 &ArrayType::MZArray,
1002 BinaryDataArrayType::Float64,
1003 source.len() * BinaryDataArrayType::Float64.size_of(),
1004 );
1005 mz_array.unit = Unit::MZ;
1006
1007 let mut intensity_array = DataArray::from_name_type_size(
1008 &ArrayType::IntensityArray,
1009 BinaryDataArrayType::Float32,
1010 source.len() * BinaryDataArrayType::Float32.size_of(),
1011 );
1012 intensity_array.unit = Unit::DetectorCounts;
1013
1014 let mut charge_array = DataArray::from_name_type_size(
1015 &ArrayType::ChargeArray,
1016 BinaryDataArrayType::Int32,
1017 source.len() * BinaryDataArrayType::Int32.size_of(),
1018 );
1019
1020 let mut im_array = DataArray::from_name_type_size(
1021 &ArrayType::MeanIonMobilityArray,
1022 BinaryDataArrayType::Float64,
1023 source.len() * BinaryDataArrayType::Float64.size_of(),
1024 );
1025
1026 for p in source.iter() {
1027 let mz: f64 = p.mz();
1028 let inten: f32 = p.intensity();
1029 let im = p.ion_mobility();
1030
1031 mz_array.data.extend_from_slice(&mz.to_le_bytes());
1032 intensity_array.data.extend_from_slice(&inten.to_le_bytes());
1033 im_array.data.extend_from_slice(&im.to_le_bytes());
1034 charge_array
1035 .data
1036 .extend_from_slice(&p.charge().to_le_bytes());
1037 }
1038
1039 arrays.add(mz_array);
1040 arrays.add(intensity_array);
1041 arrays.add(im_array);
1042 arrays.add(charge_array);
1043 arrays
1044 }
1045}
1046
1047impl BuildFromArrayMap for IonMobilityAwareDeconvolutedPeak {
1049 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
1050 let mz_array = arrays.mzs()?;
1051 let intensity_array = arrays.intensities()?;
1052 let charge_array = arrays.charges()?;
1053 let (im_array, _) = arrays.ion_mobility()?;
1054 let mut peaks = Vec::with_capacity(mz_array.len());
1055
1056 for (i, (mz, (intensity, (ion_mobility, charge)))) in mz_array
1057 .iter()
1058 .zip(
1059 intensity_array
1060 .iter()
1061 .zip(im_array.iter().zip(charge_array.iter())),
1062 )
1063 .enumerate()
1064 {
1065 let mass = neutral_mass(*mz, *charge);
1066 peaks.push(IonMobilityAwareDeconvolutedPeak {
1067 neutral_mass: mass,
1068 intensity: *intensity,
1069 index: i as u32,
1070 ion_mobility: *ion_mobility,
1071 charge: *charge,
1072 })
1073 }
1074 Ok(peaks)
1075 }
1076
1077 fn arrays_required() -> Option<Vec<ArrayType>> {
1078 Some(vec![
1079 ArrayType::MZArray,
1080 ArrayType::IntensityArray,
1081 ArrayType::ChargeArray,
1082 ArrayType::IonMobilityArray,
1083 ])
1084 }
1085}
1086
1087#[cfg(feature = "mzsignal")]
1088impl BuildArrayMapFrom for mzsignal::FittedPeak {
1092 fn arrays_included(&self) -> Option<Vec<ArrayType>> {
1093 Some(vec![
1094 ArrayType::MZArray,
1095 ArrayType::IntensityArray,
1096 ArrayType::SignalToNoiseArray,
1097 ])
1098 }
1099
1100 fn as_arrays(source: &[Self]) -> BinaryArrayMap {
1101 let mut arrays = BinaryArrayMap::new();
1102
1103 let mut mz_array = DataArray::from_name_type_size(
1104 &ArrayType::MZArray,
1105 BinaryDataArrayType::Float64,
1106 source.len() * BinaryDataArrayType::Float64.size_of(),
1107 );
1108 mz_array.unit = Unit::MZ;
1109
1110 let mut intensity_array = DataArray::from_name_type_size(
1111 &ArrayType::IntensityArray,
1112 BinaryDataArrayType::Float32,
1113 source.len() * BinaryDataArrayType::Float32.size_of(),
1114 );
1115 intensity_array.unit = Unit::DetectorCounts;
1116
1117 let mut snr_array = DataArray::from_name_type_size(
1118 &ArrayType::SignalToNoiseArray,
1119 BinaryDataArrayType::Float32,
1120 source.len() * BinaryDataArrayType::Float32.size_of(),
1121 );
1122
1123 for p in source.iter() {
1124 let mz: f64 = p.coordinate();
1125 let inten: f32 = p.intensity();
1126 mz_array.push(mz).unwrap();
1127 intensity_array.push(inten).unwrap();
1128 snr_array.push(p.signal_to_noise).unwrap();
1129 }
1130
1131 arrays.add(mz_array);
1132 arrays.add(intensity_array);
1133 arrays.add(snr_array);
1134 arrays
1135 }
1136}
1137
1138#[cfg(feature = "mzsignal")]
1139impl BuildFromArrayMap for mzsignal::FittedPeak {
1144 fn arrays_required() -> Option<Vec<ArrayType>> {
1145 CentroidPeak::arrays_required()
1146 }
1147
1148 fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
1149 let mzs = arrays.mzs()?;
1150 let intens = arrays.intensities()?;
1151 let snrs = arrays
1152 .get(&ArrayType::SignalToNoiseArray)
1153 .and_then(|a| a.to_f32().ok());
1154
1155 let n = mzs.len();
1156
1157 let mut out = Vec::with_capacity(n);
1158 for (i, (mz, inten)) in mzs.iter().copied().zip(intens.iter().copied()).enumerate() {
1159 out.push(mzsignal::FittedPeak::new(
1160 mz,
1161 inten,
1162 0,
1163 snrs.as_ref()
1164 .and_then(|v| v.get(i).copied())
1165 .unwrap_or_default(),
1166 0.0,
1167 ))
1168 }
1169 Ok(out)
1170 }
1171}