libpappsomspp
Library for mass spectrometry
massspectrumpluscombiner.cpp
Go to the documentation of this file.
1 /////////////////////// StdLib includes
2 #include <numeric>
3 #include <limits>
4 #include <vector>
5 #include <map>
6 #include <cmath>
7 #include <iostream>
8 #include <iomanip>
9 
10 
11 /////////////////////// Qt includes
12 #include <QDebug>
13 #include <QFile>
14 #include <QThread>
15 #if 0
16 // For debugging purposes.
17 #include <QFile>
18 #endif
19 
20 
21 /////////////////////// Local includes
23 #include "../../types.h"
24 #include "../../utils.h"
25 #include "../../pappsoexception.h"
26 #include "../../exception/exceptionoutofrange.h"
27 #include "../../exception/exceptionnotpossible.h"
28 
29 
30 namespace pappso
31 {
32 
33 
34 //! Construct an uninitialized instance.
36 {
37 }
38 
39 
41  : MassSpectrumCombiner(decimal_places)
42 {
43 }
44 
45 
47  const MassSpectrumPlusCombiner &other)
48  : MassSpectrumCombiner(other)
49 
50 {
51 }
52 
53 
56  : MassSpectrumCombiner(other)
57 
58 {
59 }
60 
61 
62 //! Destruct the instance.
64 {
65 }
66 
67 
70 {
71  if(this == &other)
72  return *this;
73 
75 
76  m_bins.assign(other.m_bins.begin(), other.m_bins.end());
77 
78  return *this;
79 }
80 
81 
82 // We get a trace as parameter that this combiner needs to combine to the
83 // map_trace we also get as parameter. This combiner is for a mass spectrum, and
84 // thus it needs to have been configured to hold a vector of m/z values that are
85 // bins into which DataPoints from trace are combined into map_trace. It is the
86 // bins that drive the the traversal of trace. For each bin, check if there is
87 // (or are, if bins are big) data points in the trace that fit in it.
88 
89 MapTrace &
90 MassSpectrumPlusCombiner::combine(MapTrace &map_trace, const Trace &trace) const
91 {
92  // qDebug();
93 
94  // If there is no single point in the trace we need to combine into the
95  // map_trace, then there is nothing to do.
96  if(!trace.size())
97  {
98  //qDebug() << "Thread:" << QThread::currentThreadId()
99  //<< "Returning right away because trace is empty.";
100  return map_trace;
101  }
102 
103  // We will need to only use these iterator variables if we do not want to
104  // loose consistency.
105 
106  using TraceIter = std::vector<DataPoint>::const_iterator;
107  TraceIter trace_iter_begin = trace.begin();
108  TraceIter trace_iter = trace_iter_begin;
109  TraceIter trace_iter_end = trace.end();
110 
111  // The destination map trace will be filled-in with the result of the
112  // combination.
113 
114  // Sanity check:
115  if(!m_bins.size())
116  throw(ExceptionNotPossible("The bin vector cannot be empty."));
117 
118  using BinIter = std::vector<pappso_double>::const_iterator;
119 
120  BinIter bin_iter = m_bins.begin();
121  BinIter bin_end_iter = m_bins.end();
122 
123  // qDebug() << "initial bins iter at a distance of:"
124  //<< std::distance(m_bins.begin(), bin_iter)
125  //<< "bins distance:" << std::distance(m_bins.begin(), m_bins.end())
126  //<< "bins size:" << m_bins.size() << "first bin:" << m_bins.front()
127  //<< "last bin:" << m_bins.back();
128 
129  // Iterate in the vector of bins and for each bin check if there are matching
130  // data points in the trace.
131 
132  pappso_double current_bin_mz = 0;
133 
134  pappso_double trace_x = 0;
135  pappso_double trace_y = 0;
136 
137  // Lower bound returns an iterator pointing to the first element in the
138  // range [first, last) that is not less than (i.e. greater or equal to)
139  // value, or last if no such element is found.
140 
141  auto bin_iter_for_mz = lower_bound(bin_iter, bin_end_iter, trace_iter->x);
142 
143  if(bin_iter_for_mz != bin_end_iter)
144  {
145  if(bin_iter_for_mz != m_bins.begin())
146  bin_iter = --bin_iter_for_mz;
147  }
148  else
149  throw(ExceptionNotPossible("The bin vector must match the mz value."));
150 
151  while(bin_iter != bin_end_iter)
152  {
153  current_bin_mz = *bin_iter;
154 
155  //qDebug() << "Current bin:"
156  //<< QString("%1").arg(current_bin_mz, 0, 'f', 15)
157  //<< "at a distance of:"
158  //<< std::distance(m_bins.begin(), bin_iter);
159 
160  // For the current bin, we start by instantiating a new DataPoint. By
161  // essence, each bin will have at most one corresponding DataPoint.
162 
163  DataPoint new_data_point;
164 
165  // Do not set the y value to 0 so that we can actually test if the
166  // data point is valid later on (try not to push back y=0 data
167  // points).
168  new_data_point.x = current_bin_mz;
169 
170  // Now perform a loop over the data points in the mass spectrum.
171 
172  //qDebug() << "Start looping in the trace to check if its DataPoint.x "
173  //"value matches that of the current bin."
174  //<< "trace_iter:" << trace_iter->toString()
175  //<< "data point distance:"
176  //<< std::distance(trace_iter_begin, trace_iter);
177 
178  while(trace_iter != trace_iter_end)
179  {
180 
181  bool trace_matched = false;
182 
183  // If trace is not to the end and the y value is not 0
184  // apply the shift, perform the rounding and check if the obtained
185  // x value is in the current bin, that is if it is less or equal
186  // to the current bin.
187 
188  //qDebug() << "Thread:" << QThread::currentThreadId();
189  //qDebug() << "trace_iter:" << trace_iter->toString()
190  //<< "data point distance:"
191  //<< std::distance(trace_iter_begin, trace_iter);
192 
193  // if(!Utils::almostEqual(trace_iter->y, 0.0, 10))
194  if(trace_iter->y)
195  {
196  trace_x = trace_iter->x;
197  trace_y = trace_iter->y;
198 
199  // trace_x is the m/z value that we need to combine,
200  // so make sure we check if there is a mz shift to apply.
201 
202  // if(m_mzIntegrationParams.m_applyMzShift)
203  // trace_x += m_mzIntegrationParams.m_mzShift;
204 
205  // Now apply the rounding (if any).
206  if(m_decimalPlaces != -1)
207  trace_x = Utils::roundToDecimals(trace_x, m_decimalPlaces);
208 
209  if(trace_x <= current_bin_mz)
210  {
211 
212  //qDebug() << "Matched, increment trace_iter";
213 
214  new_data_point.y += trace_y;
215 
216  // Let's record that we matched.
217  trace_matched = true;
218 
219  // Because we matched, we can step-up with the
220  // iterator.
221  ++trace_iter;
222  }
223  // else
224  //{
225  // We did have a non-0 y value, but that did not
226  // match. So we do not step-up with the iterator.
227  //}
228  }
229  // End of
230  // if(trace_iter->y)
231  else
232  {
233  // We iterated into a y=0 data point, so just skip it. Let
234  // the below code think that we have matched the point and
235  // iterate one step up.
236 
237  // qDebug() << "The y value is almost equal to 0, increment the "
238  //"trace iter but do nothing else.";
239 
240  trace_matched = true;
241  ++trace_iter;
242  }
243  // At this point, check if none of them matched.
244 
245  if(!trace_matched)
246  {
247  // None of the first and trace mass spectra data
248  // points were found to match the current bin. All we
249  // have to do is go to the next bin. We break and the
250  // bin vector iterator will be incremented.
251 
252  // However, if we had a valid new data point, that
253  // data point needs to be pushed back in the new mass
254  // spectrum.
255 
256  if(new_data_point.isValid())
257  {
258 
259  // We need to check if that bin value is present already in
260  // the map_trace object passed as parameter.
261 
262  std::pair<std::map<pappso_double, pappso_double>::iterator,
263  bool>
264  result =
265  map_trace.insert(std::pair<pappso_double, pappso_double>(
266  new_data_point.x, new_data_point.y));
267 
268  if(!result.second)
269  {
270  // The key already existed! The item was not inserted. We
271  // need to update the value.
272 
273  result.first->second += new_data_point.y;
274 
275  //qDebug()
276  //<< "Incremented the data point in the map trace.";
277  }
278  //else
279  //{
280  //qDebug()
281  //<< "Inserted a new data point into the map trace.";
282  //}
283  }
284 
285  // We need to break this loop! That will increment the
286  // bin iterator.
287 
288  break;
289  }
290  }
291  // End of
292  // while(1)
293 
294  // Each time we get here, that means that we have consumed all
295  // the mass spectra data points that matched the current bin.
296  // So go to the next bin.
297 
298  if(trace_iter == trace_iter_end)
299  {
300 
301  // Make sure a last check is done in case one data point was
302  // cooking...
303 
304  if(new_data_point.isValid())
305  {
306 
307  std::pair<std::map<pappso_double, pappso_double>::iterator, bool>
308  result =
309  map_trace.insert(std::pair<pappso_double, pappso_double>(
310  new_data_point.x, new_data_point.y));
311 
312  if(!result.second)
313  {
314  result.first->second += new_data_point.y;
315  }
316  }
317 
318  // Now truly exit the loops...
319  break;
320  }
321 
322  ++bin_iter;
323  }
324  // End of
325  // while(bin_iter != bin_end_iter)
326 
327  // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << " ()"
328  //<< "The combination result mass spectrum being returned has TIC:"
329  //<< new_trace.sumY();
330 
331  return map_trace;
332 }
333 
334 
335 MapTrace &
337  const MapTrace &map_trace_in) const
338 {
339  // qDebug();
340 
341  if(!map_trace_in.size())
342  {
343  // qDebug() << "Thread:" << QThread::currentThreadId()
344  //<< "Returning right away because map_trace_in is empty.";
345  return map_trace_out;
346  }
347 
348  Trace trace(map_trace_in);
349 
350  return combine(map_trace_out, trace);
351 }
352 
353 
354 } // namespace pappso
355 
int m_decimalPlaces
Number of decimals to use for the keys (x values)
std::vector< pappso_double > m_bins
MassSpectrumPlusCombiner()
Construct an uninitialized instance.
virtual ~MassSpectrumPlusCombiner()
Destruct the instance.
virtual MapTrace & combine(MapTrace &map_trace, const Trace &trace) const override
MassSpectrumPlusCombiner & operator=(const MassSpectrumPlusCombiner &other)
A simple container of DataPoint instances.
Definition: trace.h:132
static pappso_double roundToDecimals(pappso_double value, int decimal_places)
Definition: utils.cpp:104
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39
double pappso_double
A type definition for doubles.
Definition: types.h:48
std::shared_ptr< const MassSpectrumPlusCombiner > MassSpectrumPlusCombinerCstSPtr
pappso_double x
Definition: datapoint.h:22
bool isValid() const
Definition: datapoint.cpp:132
pappso_double y
Definition: datapoint.h:23