use mzcore::prelude::{CompoundPeptidoformIon, MassMode};
use mzdata::mzpeaks::PeakCollection;
use crate::prelude::{AnnotatedSpectrum, Fragment, MatchingParameters};
pub trait AnnotatableSpectrum: Sized {
fn empty_annotated(self, peptide: CompoundPeptidoformIon) -> AnnotatedSpectrum;
fn annotate(
self,
peptide: CompoundPeptidoformIon,
theoretical_fragments: &[Fragment],
parameters: &MatchingParameters,
mode: MassMode,
) -> AnnotatedSpectrum {
let tolerance = match parameters.tolerance {
mzcore::quantities::Tolerance::Absolute(mz) => mzdata::prelude::Tolerance::Da(mz.value),
mzcore::quantities::Tolerance::Relative(ratio) => {
mzdata::prelude::Tolerance::PPM(ratio.get::<mzcore::system::ratio::ppm>())
}
};
let mut annotated = Self::empty_annotated(self, peptide);
for fragment in theoretical_fragments {
if let Some(mz) = fragment.mz(mode) {
if !parameters.mz_range.contains(&mz) {
continue;
}
if let Some(index) = annotated
.peaks
.search(mz.get::<mzcore::system::thomson>(), tolerance)
{
match annotated.peaks[index].annotations.binary_search(fragment) {
Ok(ai) | Err(ai) => annotated.peaks[index]
.annotations
.insert(ai, fragment.clone()),
}
}
}
}
annotated
}
}
impl<T: Into<AnnotatedSpectrum>> AnnotatableSpectrum for T {
fn empty_annotated(self, peptide: CompoundPeptidoformIon) -> AnnotatedSpectrum {
let mut spectrum: AnnotatedSpectrum = self.into();
for (index, peptidoform_ion) in peptide.into_peptidoform_ions().into_iter().enumerate() {
spectrum.analytes.push(crate::mzspeclib::Analyte::new(
index as u32,
crate::mzspeclib::AnalyteTarget::PeptidoformIon(peptidoform_ion),
));
}
spectrum
}
}