mzdeisotope_map/
api.rs

1use std::marker::PhantomData;
2use std::mem;
3
4use mzdeisotope::charge::ChargeRange;
5use mzdeisotope::isotopic_model::CachingIsotopicModel;
6use mzdeisotope::scorer::{IsotopicFitFilter, IsotopicPatternScorer};
7use mzpeaks::feature::Feature;
8use mzpeaks::{coordinate::MZ, feature_map::FeatureMap};
9use mzpeaks::{prelude::*, Mass};
10
11use crate::DeconvolutionError;
12use crate::{processor::FeatureProcessor, FeatureSearchParams, solution::DeconvolvedSolutionFeature};
13use mzdeisotope::IsotopicModelLike;
14
15#[derive(Debug, Clone)]
16pub struct FeatureDeconvolutionEngine<
17    'lifespan,
18    T: Clone + Default,
19    C: FeatureLike<MZ, T> + Clone + Default,
20    S: IsotopicPatternScorer,
21    F: IsotopicFitFilter,
22> {
23    /// The set of parameters to use for `isotopic_model` when generating an isotopic pattern for a given m/z
24    isotopic_params: FeatureSearchParams,
25    /// The model to generate isotpoic patterns from, or a collection there-of. If more than one model is
26    /// provided, a slightly different algorithm will be used.
27    isotopic_model: Option<IsotopicModelLike<'lifespan>>,
28    /// The strategy for scoring isotopic pattern fits
29    scorer: Option<S>,
30    /// The strategy for filtering out isotopic pattern fits that are too poor to consider
31    fit_filter: Option<F>,
32    peak_type: PhantomData<C>,
33    time_dim: PhantomData<T>,
34}
35
36impl<
37        'lifespan,
38        T: Clone + Default,
39        C: FeatureLike<MZ, T> + Clone + Default,
40        S: IsotopicPatternScorer,
41        F: IsotopicFitFilter,
42    > FeatureDeconvolutionEngine<'lifespan, T, C, S, F>
43{
44    pub fn new<I: Into<IsotopicModelLike<'lifespan>>>(
45        isotopic_params: FeatureSearchParams,
46        isotopic_model: I,
47        scorer: S,
48        fit_filter: F,
49    ) -> Self {
50        Self {
51            isotopic_params,
52            isotopic_model: Some(isotopic_model.into()),
53            scorer: Some(scorer),
54            fit_filter: Some(fit_filter),
55            peak_type: PhantomData,
56            time_dim: PhantomData,
57        }
58    }
59
60
61    /// Pre-calculcate and cache all isotopic patterns between `min_mz` and `max_mz` for
62    /// charge states between `min_charge` and `max_charge`.
63    ///
64    /// If this method is not used, experimental peaks will be used to seed the isotopic pattern
65    /// caches which may lead to slightly different solutions depending upon the order in which
66    /// peak lists are processed.
67    ///
68    /// # See also
69    /// [`IsotopicPatternGenerator::populate_cache`](crate::isotopic_model::IsotopicPatternGenerator::populate_cache)
70    pub fn populate_isotopic_model_cache(
71        &mut self,
72        min_mz: f64,
73        max_mz: f64,
74        min_charge: i32,
75        max_charge: i32,
76    ) {
77        if let Some(cache) = self.isotopic_model.as_mut() {
78            match cache {
79                IsotopicModelLike::SingleModel(cache) => {
80                    cache.populate_cache_params(
81                        min_mz,
82                        max_mz,
83                        min_charge,
84                        max_charge,
85                        self.isotopic_params.as_isotopic_params(),
86                    );
87                }
88                IsotopicModelLike::MultipleModels(caches) => {
89                    for cache in caches {
90                        cache.populate_cache_params(
91                            min_mz,
92                            max_mz,
93                            min_charge,
94                            max_charge,
95                            self.isotopic_params.as_isotopic_params(),
96                        );
97                    }
98                }
99            }
100        }
101    }
102
103    #[allow(clippy::too_many_arguments)]
104    pub fn deconvolute_features(
105        &mut self,
106        features: FeatureMap<MZ, T, C>,
107        error_tolerance: Tolerance,
108        charge_range: ChargeRange,
109        minimum_size: usize,
110        maximum_time_gap: f64,
111        minimum_intensity: f32,
112        max_missed_peaks: usize,
113    ) -> Result<FeatureMap<Mass, T, DeconvolvedSolutionFeature<T>>, DeconvolutionError> {
114        let output = match mem::take(&mut self.isotopic_model).unwrap() {
115            IsotopicModelLike::SingleModel(model) => {
116                let mut deconvoluter =
117                    FeatureProcessor::<T, CachingIsotopicModel<'lifespan>, S, F>::new(
118                        features.into_iter().map(|f| {
119                            let f: Feature<MZ, T> = f.iter().collect();
120                            f
121                        }).collect(),
122                        model,
123                        mem::take(&mut self.scorer).unwrap(),
124                        mem::take(&mut self.fit_filter).unwrap(),
125                        minimum_size,
126                        maximum_time_gap,
127                        minimum_intensity,
128                        true
129                    );
130
131                let mut params = self.isotopic_params;
132                params.max_missed_peaks = max_missed_peaks;
133
134                let output = deconvoluter.deconvolve(
135                    error_tolerance,
136                    charge_range,
137                    1,
138                    0,
139                    &self.isotopic_params,
140                    1e-3,
141                    10,
142                );
143
144                self.isotopic_model = Some(deconvoluter.isotopic_model.into());
145                self.scorer = Some(deconvoluter.scorer);
146                self.fit_filter = Some(deconvoluter.fit_filter);
147                output
148            }
149            _ => {
150                todo!("not yet implemented")
151            }
152        };
153        output
154    }
155}
156
157#[allow(clippy::too_many_arguments)]
158pub fn deconvolute_features<'a, T: Clone + Default, C: FeatureLike<MZ, T> + Clone + Default, I: Into<IsotopicModelLike<'a>>, S: IsotopicPatternScorer, F: IsotopicFitFilter>(
159        features: FeatureMap<MZ, T, C>,
160        isotopic_params: FeatureSearchParams,
161        isotopic_model: I,
162        scorer: S,
163        fit_filter: F,
164        error_tolerance: Tolerance,
165        charge_range: ChargeRange,
166        minimum_size: usize,
167        maximum_time_gap: f64,
168        minimum_intensity: f32,
169        max_missed_peaks: usize,
170) -> Result<FeatureMap<Mass, T, DeconvolvedSolutionFeature<T>>, DeconvolutionError> {
171    let mut engine = FeatureDeconvolutionEngine::new(isotopic_params, isotopic_model, scorer, fit_filter);
172
173    engine.deconvolute_features(features, error_tolerance, charge_range, minimum_size, maximum_time_gap, minimum_intensity, max_missed_peaks)
174}