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 isotopic_params: FeatureSearchParams,
25 isotopic_model: Option<IsotopicModelLike<'lifespan>>,
28 scorer: Option<S>,
30 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 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 self.isotopic_params.max_missed_peaks = max_missed_peaks;
132
133 let output = deconvoluter.deconvolve(
134 error_tolerance,
135 charge_range,
136 1,
137 0,
138 &self.isotopic_params,
139 1e-3,
140 10,
141 );
142
143 self.isotopic_model = Some(deconvoluter.isotopic_model.into());
144 self.scorer = Some(deconvoluter.scorer);
145 self.fit_filter = Some(deconvoluter.fit_filter);
146 output
147 }
148 _ => {
149 todo!("not yet implemented")
150 }
151 };
152 output
153 }
154}
155
156#[allow(clippy::too_many_arguments)]
157pub fn deconvolute_features<'a, T: Clone + Default, C: FeatureLike<MZ, T> + Clone + Default, I: Into<IsotopicModelLike<'a>>, S: IsotopicPatternScorer, F: IsotopicFitFilter>(
158 features: FeatureMap<MZ, T, C>,
159 isotopic_params: FeatureSearchParams,
160 isotopic_model: I,
161 scorer: S,
162 fit_filter: F,
163 error_tolerance: Tolerance,
164 charge_range: ChargeRange,
165 minimum_size: usize,
166 maximum_time_gap: f64,
167 minimum_intensity: f32,
168 max_missed_peaks: usize,
169) -> Result<FeatureMap<Mass, T, DeconvolvedSolutionFeature<T>>, DeconvolutionError> {
170 let mut engine = FeatureDeconvolutionEngine::new(isotopic_params, isotopic_model, scorer, fit_filter);
171
172 engine.deconvolute_features(features, error_tolerance, charge_range, minimum_size, maximum_time_gap, minimum_intensity, max_missed_peaks)
173}