use std::collections::BTreeMap;
use std::fmt;
use std::fmt::{Display, Formatter};
use crate::data::spectrum::{IndexedMzSpectrum, IndexedMzSpectrumVectorized, MsType, MzSpectrum};
#[derive(Clone)]
pub struct TimsSpectrumVectorized {
pub frame_id: i32,
pub scan: i32,
pub retention_time: f64,
pub mobility: f64,
pub ms_type: MsType,
pub vector: IndexedMzSpectrumVectorized,
}
#[derive(Clone, Debug)]
pub struct TimsSpectrum {
pub frame_id: i32,
pub scan: i32,
pub retention_time: f64,
pub mobility: f64,
pub ms_type: MsType,
pub spectrum: IndexedMzSpectrum,
}
impl TimsSpectrum {
pub fn new(frame_id: i32, scan_id: i32, retention_time: f64, mobility: f64, ms_type: MsType, spectrum: IndexedMzSpectrum) -> Self {
TimsSpectrum { frame_id, scan: scan_id, retention_time, mobility: mobility, ms_type, spectrum }
}
pub fn filter_ranged(&self, mz_min: f64, mz_max: f64, intensity_min: f64, intensity_max: f64) -> Self {
let filtered = self.spectrum.filter_ranged(mz_min, mz_max, intensity_min, intensity_max);
TimsSpectrum { frame_id: self.frame_id, scan: self.scan, retention_time: self.retention_time, mobility: self.mobility, ms_type: self.ms_type.clone(), spectrum: filtered }
}
pub fn to_resolution(&self, resolution: i32) -> TimsSpectrum {
let spectrum = self.spectrum.to_resolution(resolution);
TimsSpectrum { frame_id: self.frame_id, scan: self.scan, retention_time: self.retention_time, mobility: self.mobility, ms_type: self.ms_type.clone(), spectrum }
}
pub fn vectorized(&self, resolution: i32) -> TimsSpectrumVectorized {
let vector = self.spectrum.vectorized(resolution);
TimsSpectrumVectorized { frame_id: self.frame_id, scan: self.scan, retention_time: self.retention_time, mobility: self.mobility, ms_type: self.ms_type.clone(), vector }
}
pub fn to_windows(&self, window_length: f64, overlapping: bool, min_peaks: usize, min_intensity: f64) -> BTreeMap<i32, TimsSpectrum> {
let mut splits: BTreeMap<i32, TimsSpectrum> = BTreeMap::new();
for (i, &mz) in self.spectrum.mz_spectrum.mz.iter().enumerate() {
let intensity = self.spectrum.mz_spectrum.intensity[i];
let tof = self.spectrum.index[i];
let tmp_key = (mz / window_length).floor() as i32;
splits.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.mz.push(mz);
splits.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.intensity.push(intensity);
splits.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.index.push(tof);
}
if overlapping {
let mut splits_offset = BTreeMap::new();
for (i, &mmz) in self.spectrum.mz_spectrum.mz.iter().enumerate() {
let intensity = self.spectrum.mz_spectrum.intensity[i];
let tof = self.spectrum.index[i];
let tmp_key = -((mmz + window_length / 2.0) / window_length).floor() as i32;
splits_offset.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.mz.push(mmz);
splits_offset.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.intensity.push(intensity);
splits_offset.entry(tmp_key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.index.push(tof);
}
for (key, val) in splits_offset {
splits.entry(key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.mz.extend(val.spectrum.mz_spectrum.mz);
splits.entry(key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.mz_spectrum.intensity.extend(val.spectrum.mz_spectrum.intensity);
splits.entry(key).or_insert_with(|| TimsSpectrum::new(self.frame_id, self.scan, self.retention_time, self.mobility, self.ms_type.clone(), IndexedMzSpectrum::new(
Vec::new(), Vec::new(), Vec::new()))
).spectrum.index.extend(val.spectrum.index);
}
}
splits.retain(|_, spectrum| {
spectrum.spectrum.mz_spectrum.mz.len() >= min_peaks && spectrum.spectrum.mz_spectrum.intensity.iter().cloned().max_by(
|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)).unwrap_or(0.0) >= min_intensity
});
splits
}
}
impl std::ops::Add for TimsSpectrum {
type Output = Self;
fn add(self, other: Self) -> TimsSpectrum {
assert_eq!(self.frame_id, other.frame_id);
assert_eq!(self.scan, other.scan);
let average_mobility = (self.mobility + other.mobility) / 2.0;
let average_retention_time = (self.retention_time + other.retention_time) / 2.0;
let mut combined_map: BTreeMap<i64, (f64, i32, i32)> = BTreeMap::new();
let quantize = |mz: f64| -> i64 { (mz * 1_000_000.0).round() as i64 };
for ((mz, intensity), index) in self.spectrum.mz_spectrum.mz.iter().zip(self.spectrum.mz_spectrum.intensity.iter()).zip(self.spectrum.index.iter()) {
let key = quantize(*mz);
combined_map.insert(key, (*intensity, *index, 1)); }
for ((mz, intensity), index) in other.spectrum.mz_spectrum.mz.iter().zip(other.spectrum.mz_spectrum.intensity.iter()).zip(other.spectrum.index.iter()) {
let key = quantize(*mz);
combined_map.entry(key).and_modify(|e| {
e.0 += *intensity; e.1 += *index; e.2 += 1; }).or_insert((*intensity, *index, 1));
}
let mz_combined: Vec<f64> = combined_map.keys().map(|&key| key as f64 / 1_000_000.0).collect();
let intensity_combined: Vec<f64> = combined_map.values().map(|(intensity, _, _)| *intensity).collect();
let index_combined: Vec<i32> = combined_map.values().map(|(_, index, count)| index / count).collect(); let spectrum = IndexedMzSpectrum { index: index_combined, mz_spectrum: MzSpectrum { mz: mz_combined, intensity: intensity_combined } };
TimsSpectrum { frame_id: self.frame_id, scan: self.scan, retention_time: average_retention_time, mobility: average_mobility, ms_type: self.ms_type.clone(), spectrum }
}
}
impl Display for TimsSpectrum {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "TimsSpectrum(frame_id: {}, scan_id: {}, retention_time: {}, mobility: {}, spectrum: {})", self.frame_id, self.scan, self.retention_time, self.mobility, self.spectrum)
}
}