GCC Code Coverage Report


./
File: src/XpertMass/IsotopicClusterShaper.cpp
Date: 2024-08-24 11:26:06
Lines:
0/115
0.0%
Functions:
0/19
0.0%
Branches:
0/130
0.0%

Line Branch Exec Source
1 /* BEGIN software license
2 *
3 * MsXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright (C) 2009--2020 Filippo Rusconi
6 *
7 * http://www.msxpertsuite.org
8 *
9 * This file is part of the MsXpertSuite project.
10 *
11 * The MsXpertSuite project is the successor of the massXpert project. This
12 * project now includes various independent modules:
13 *
14 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
15 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
16 *
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *
30 * END software license
31 */
32
33
34 /////////////////////// StdLib includes
35 #include <cmath>
36 #include <algorithm>
37 #include <limits> // for std::numeric_limits
38
39
40 /////////////////////// Qt includes
41
42
43 /////////////////////// pappsomspp includes
44 #include <pappsomspp/massspectrum/massspectrum.h>
45 #include <pappsomspp/processing/combiners/massspectrumpluscombiner.h>
46 #include <pappsomspp/processing/combiners/tracepluscombiner.h>
47 #include <pappsomspp/trace/trace.h>
48 #include <pappsomspp/processing/filters/filternormalizeintensities.h>
49 #include <pappsomspp/utils.h>
50
51
52 /////////////////////// Local includes
53 #include "globals.hpp"
54 #include "MassDataCborMassSpectrumHandler.hpp"
55 #include "IsotopicClusterShaper.hpp"
56 #include "MassPeakShaper.hpp"
57
58
59 namespace MsXpS
60 {
61
62 namespace libXpertMass
63 {
64
65
66 /*!
67 \class MsXpS::libXpertMass::IsotopicClusterShaper
68 \inmodule libXpertMass
69 \ingroup XpertMassMassCalculations
70 \inheaderfile IsotopicClusterShaper.hpp
71
72 \brief The IsotopicClusterShaper class provides the features needed to shape
73 sets of (peak centroid m/z, intensity) pairs associated to a given charge
74 into a mass spectral pappso;:Trace.
75
76 Each set of (peak centroid m/z, intensity) pairs corresponds to an isotopic
77 cluster that is associated to a charge.
78
79 The configuration of the peak shaping process is held in a specific \l
80 MassPeakShaperConfig class.
81
82 The output of the computation is a pappso::Trace obtained by combining all the
83 different shapes obtained for the different peak centroids of all the sets of
84 (peak centroid m/z, intensity) pairs. If binning was requested, the obtained
85 Trace is the result of a combination accounting for the required bin size,
86 otherwise the obtained Trace is the result of the mere addition of all the
87 points in the different traces.
88
89 \sa MassPeakShaperConfig
90 */
91
92 /*!
93 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_isotopicClusterChargePairs
94
95 \brief Vector of pappso::Trace instances in pair with charges.
96 */
97
98 /*!
99 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_config
100
101 \brief The configuration driving the mass peak shaping process.
102 */
103
104 /*!
105 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_mapTrace
106
107 \brief The map relating a m/z value to its intensity.
108
109 This map is a variant of pappso::Trace that is designed to allow for easy mass
110 spectrum combination. It is generally used only for computations and is
111 converted to a pappso::Trace once all the computations have been carried out.
112 */
113
114 /*!
115 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_finalTrace
116
117 \brief The pappso::Trace holding the final results of the computations.
118 */
119
120 /*!
121 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_mzIntegrationParams
122
123 \brief The configuration of the mass spectral combinations (for
124 example, determines the bins, if binning is required).
125 */
126
127 /*!
128 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_mostIntensePeakMz
129
130 \brief The most intense peak encountered during the calculations.
131 */
132
133 /*!
134 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_smallestMz
135
136 \brief The smallest m/z value encountered during the calculations.
137
138 This value is required for the crafting of the bins.
139 */
140
141 /*!
142 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_greatestMz
143
144 \brief The greatest m/z value encountered during the calculations.
145
146 This value is required for the crafting of the bins.
147 */
148
149 /*!
150 \variable MsXpS::libXpertMass::IsotopicClusterShaper::m_normalizeIntensity
151
152 \brief The value by which all the peak shapes need to be normalized.
153 */
154
155 /*!
156 \brief Constructs a IsotopicClusterShaper instance.
157
158 \list
159 \li \a isotopic_cluster: The peak centroids belonging to an isotopic cluster
160 in the form of a pappso::Trace.
161 \li \a charge: The charge of the analyte below the isotopic cluster peaks.
162 \li \a config: The mass peak shaping process configuration.
163 \endlist
164
165 Each pappso::DataPoint in the \a isotopic_cluster pappso::Trace corresponds to
166 a (m/z, intensity) peak centroid belonging to the isotopic cluster.
167 */
168 IsotopicClusterShaper::IsotopicClusterShaper(
169 const pappso::Trace &isotopic_cluster,
170 int charge,
171 const MassPeakShaperConfig &config)
172 : m_config(config)
173 {
174 // No need to reset, we are constructing.
175 setIsotopicCluster(isotopic_cluster, charge, false);
176 }
177
178
179 /*!
180 \brief Constructs a IsotopicClusterShaper instance.
181
182 \list
183 \li \a isotopic_cluster_charge_pairs: The pairs associating a pappso::Trace
184 instance to its corresponding charge.
185 \li \a config: The mass peak shaping process configuration.
186 \endlist
187
188 In this constructor, a set of sets of (m/z, charge) peak centroids is passed as
189 argument. The pappso::Trace instances in \a isotopic_cluster_charge_pairs might
190 correspond to all the isotopic clusters representing a given analyte at
191 different charges.
192 */
193 IsotopicClusterShaper::IsotopicClusterShaper(
194 const std::vector<IsotopicClusterChargePair> &isotopic_cluster_charge_pairs,
195 const MassPeakShaperConfig &config)
196 : m_config(config)
197 {
198 // No need to reset, we are constructing.
199 setIsotopicClusterChargePairs(isotopic_cluster_charge_pairs, false);
200 }
201
202 /*!
203 \brief Destructs this IsotopicClusterShaper instance.
204 */
205 IsotopicClusterShaper::~IsotopicClusterShaper()
206 {
207 }
208
209 /*!
210 \brief Sets the peak shaping process \a{config}uration.
211 */
212 void
213 IsotopicClusterShaper::setConfig(MassPeakShaperConfig config)
214 {
215 m_config = config;
216 }
217
218
219 /*!
220 \brief Gets the peak shaping process configuration.
221 */
222 MassPeakShaperConfig
223 IsotopicClusterShaper::getConfig() const
224 {
225 return m_config;
226 }
227
228
229 /*!
230 \brief Sets the intensity normalization value to \a max_intensity.
231 */
232 void
233 IsotopicClusterShaper::setNormalizeIntensity(int max_intensity)
234 {
235 m_normalizeIntensity = max_intensity;
236 }
237
238
239 /*!
240 \brief Gets the intensity normalization value.
241 */
242 int
243 IsotopicClusterShaper::getNormalizeIntensity() const
244 {
245 return m_normalizeIntensity;
246 }
247
248 /*!
249 \brief Runs the mass peak shaping process for all the \l
250 IsotopicClusterChargePair objects in \l m_isotopicClusterChargePairs.
251
252 If \a reset is true, the member \l m_mapTrace and \l m_finalTrace are cleared
253 before starting the computations. The \l m_config member is first
254 \l{MassPeakShaperConfig::resolve()}d to check that all the parameters have been
255 properly set and are valid.
256
257 Returns the obtained pappso::Trace corresponding to the combination of all the
258 individual traces obtained for the various isotopic clusters and their
259 corresponding charge.
260 */
261 pappso::Trace &
262 IsotopicClusterShaper::run(bool reset)
263 {
264 if(reset)
265 {
266 // Clear the map trace that will receive the results of the combinations.
267 m_mapTrace.clear();
268 m_finalTrace.clear();
269 }
270
271 if(!m_config.resolve())
272 {
273 qDebug() << "The peak shaper configuration failed to resolve.";
274 return m_finalTrace;
275 }
276
277 // This class works on a vector of pairs containing the following:
278 // 1. a pappso::TraceCstSPtr
279 // 2. a charge
280
281 // We will process each pair in turn. If the integration requires bin, then
282 // each shaped isotopic cluster will be combined into a mass spectrum.
283 // Otherwise a trace combiner will be used.
284
285 // When setting the data (either by construction or using the set<> functions,
286 // we had monitored the smallest and the greatest m/z value over the whole set
287 // of the DataPoint objects in the isotopic clusters (centroid data). This is
288 // because we need, in case binning is required, these values to craft the
289 // bins.
290
291 // We will need to perform combinations, positive combinations.
292 // This mass spectrum combiner is in case we need binning.
293 pappso::MassSpectrumPlusCombiner mass_spectrum_plus_combiner;
294
295 // This trace combiner is in case do *not* need binning.
296 pappso::TracePlusCombiner trace_plus_combiner(-1);
297
298 // Configure the mass spectrum combiner in case we need binning.
299
300 if(m_config.withBins())
301 {
302 // Bins were requested.
303
304 // qDebug() << "Bins are required.";
305
306 // Get the bin size out of the configuration.
307
308 double bin_size = m_config.getBinSize();
309
310 // qDebug() << "The bin size in the config is:" << bin_size;
311
312 // Because we had monitored the m/z values of all the shapes generated
313 // above, we know the smallest and greatest m/z value that were
314 // encountered in all that peak shaping activity. We thus can create the
315 // bins faithfully.
316
317 MassPeakWidthLogic logic = m_config.getMassPeakWidthLogic();
318
319 // The m_smallestMz and m_greatestMz values have been determined by
320 // looking into the unshaped isotopic clusters passed to this object
321 // either by construction or with functions. These two mz values are thus
322 // peak centroids, not data points belonging to a shaped peak since we
323 // have not yet started shaping the peaks. This means that we cannot
324 // create bins start / ending at these values because we would loose the
325 // first half of the first shaped peak centroid and the second half of the
326 // last shaped peak centroid (a shaped peak goes left *and* right of the
327 // peak centroid otherwise there would be no shape).
328 //
329 // This is why we provide a confortable margin fo the bin creation below
330 // by removing 1 Th on the left of the smallest mz and by adding 1 Th on
331 // right of the greatest mz.
332
333 if(logic == MassPeakWidthLogic::FWHM)
334 {
335 m_mzIntegrationParams = pappso::MzIntegrationParams(
336 m_smallestMz - 1,
337 m_greatestMz + 1,
338 pappso::BinningType::ARBITRARY,
339 -1,
340 pappso::PrecisionFactory::getDaltonInstance(bin_size),
341 1,
342 true);
343 }
344 else if(logic == MassPeakWidthLogic::RESOLUTION)
345 {
346 double resolution = m_config.getResolution();
347
348 m_mzIntegrationParams = pappso::MzIntegrationParams(
349 m_smallestMz - 1,
350 m_greatestMz + 1,
351 pappso::BinningType::ARBITRARY,
352 -1,
353 pappso::PrecisionFactory::getResInstance(resolution),
354 m_config.getBinSizeDivisor(),
355 true);
356 }
357 else
358 qFatal(
359 "Programming error. By this time, the mass peak width logic should "
360 "have been defined.");
361
362 // qDebug() << "The mz integration params:"
363 //<< m_mzIntegrationParams.toString();
364
365 // Now compute the bins.
366
367 std::vector<double> bins = m_mzIntegrationParams.createBins();
368 // qDebug() << "The bins:" << bins;
369
370 mass_spectrum_plus_combiner.setBins(bins);
371 // qDebug() << "Set bins to the mass spectrum combiner:"
372 //<< mass_spectrum_plus_combiner.getBins().size();
373 }
374
375 std::size_t peak_centroid_count = 0;
376 std::size_t isotopic_cluster_count = 0;
377
378 // Iterate in the isotopic cluster/charge pairs.
379 for(auto isotopic_cluster_charge_pair : m_isotopicClusterChargePairs)
380 {
381 int charge = isotopic_cluster_charge_pair.second;
382
383 // Iterate in the data points of the current centroid data isotopic
384 // cluster.
385 for(auto data_point : *isotopic_cluster_charge_pair.first)
386 {
387 // Note the division by m_charge below!
388
389 pappso::Trace trace = MassPeakShaper::computePeakShape(
390 data_point.x / charge, data_point.y, m_config);
391
392 // qDebug() << "The shaped isotopic cluster has size:" <<
393 // trace.size();
394
395 if(trace.size())
396 {
397 if(m_config.withBins())
398 mass_spectrum_plus_combiner.combine(m_mapTrace, trace);
399 else
400 trace_plus_combiner.combine(m_mapTrace, trace);
401
402 // qDebug() << qSetRealNumberPrecision(15)
403 //<< "The map trace for combination has size:"
404 //<< m_mapTrace.size()
405 //<< "and starting m/z:" << m_mapTrace.begin()->first
406 //<< "and ending m/z:"
407 //<< std::prev(m_mapTrace.end())->first;
408
409 ++peak_centroid_count;
410 }
411 }
412 ++isotopic_cluster_count;
413 }
414
415 // qDebug() << QString(
416 //"Successfully processed %1 isotopic clusters for a total of %2 "
417 //"shaped peak centroids")
418 //.arg(isotopic_cluster_count)
419 //.arg(peak_centroid_count);
420
421 // The user might have asked that the most intense m/z peak centroid be used
422 // for normalization. In that case that peak centroid's intensity is brought
423 // to m_normalizeIntensity and the ratio between its current intensity and
424 // m_normalizeIntensity is used to normalize all the other data points in the
425 // trace.
426
427 if(m_normalizeIntensity != 1)
428 {
429
430 // qDebug() << "Now normalizing to intensity = " << m_normalizeIntensity;
431
432 pappso::Trace trace = m_mapTrace.toTrace();
433 m_finalTrace =
434 trace.filter(pappso::FilterNormalizeIntensities(m_normalizeIntensity));
435
436 // double max_int = normalized_trace.maxYDataPoint().y;
437 // qDebug() << "After normalization max int:" << max_int;
438 }
439 else
440 m_finalTrace = m_mapTrace.toTrace();
441
442 // qDebug() << "Returning a trace of size:" << m_finalTrace.size();
443
444 // pappso::Utils::writeToFile(m_finalTrace.toString(), "/tmp/mass/trace.txt");
445
446 return m_finalTrace;
447 }
448
449 /*!
450 \brief Handles the \a isotopic_cluster_sp input isotopic cluster as a
451 pappso::Trace.
452
453 \a isotopic_cluster_sp is associated to a \a charge. If \a reset is true, the
454 member vector of \l IsotopicClusterChargePair instances is cleared before the
455 computations.
456
457 This function is the workhorse for all the functions used to set the initial
458 data for the computations. Its main task is to scrutinize the data in \a
459 isotopic_cluster_sp and update the \l m_smallestMz, \l m_greatestMz and \l
460 m_mostIntensePeakMz values based on the data passed as argument.
461 */
462 void
463 IsotopicClusterShaper::setIsotopicCluster(
464 pappso::TraceCstSPtr isotopic_cluster_sp, int charge, bool reset)
465 {
466 if(reset)
467 m_isotopicClusterChargePairs.clear();
468
469 double min_x = isotopic_cluster_sp->minX();
470 m_smallestMz = std::min(m_smallestMz, min_x);
471
472 double max_x = isotopic_cluster_sp->maxX();
473 m_greatestMz = std::max(m_greatestMz, max_x);
474
475 m_mostIntensePeakMz = isotopic_cluster_sp->maxYDataPoint().x;
476
477 // qDebug() << qSetRealNumberPrecision(15) << "m_smallestMz:" << m_smallestMz
478 //<< "m_greatestMz:" << m_greatestMz
479 //<< "m_mostIntensePeakMz:" << m_mostIntensePeakMz;
480
481 m_isotopicClusterChargePairs.push_back(
482 IsotopicClusterChargePair(isotopic_cluster_sp, charge));
483
484 m_config.setReferencePeakMz(m_mostIntensePeakMz);
485 }
486
487
488 /*!
489 \brief Handles the \a isotopic_cluster_sp input isotopic cluster as a
490 pappso::Trace.
491
492 \a isotopic_cluster_sp is associated to a \a charge.
493
494 The member vector of \l IsotopicClusterChargePair instances is cleared before
495 the computations.
496 */
497 void
498 IsotopicClusterShaper::setIsotopicCluster(
499 pappso::TraceCstSPtr isotopic_cluster_sp, int charge)
500 {
501 setIsotopicCluster(isotopic_cluster_sp, charge, true);
502 }
503
504
505 /*!
506 \brief Handles the \a isotopic_cluster input isotopic cluster as a
507 pappso::Trace.
508
509 \a isotopic_cluster is associated to a \a charge. If \a reset is true, the
510 member vector of \l IsotopicClusterChargePair instances is cleared before the
511 computations.
512 */
513 void
514 IsotopicClusterShaper::setIsotopicCluster(const pappso::Trace &isotopic_cluster,
515 int charge,
516 bool reset)
517 {
518 setIsotopicCluster(
519 std::make_shared<const pappso::Trace>(isotopic_cluster), charge, reset);
520 }
521
522
523 /*!
524 \brief Handles the \a isotopic_cluster input isotopic cluster as a
525 pappso::Trace.
526
527 \a isotopic_cluster is associated to a \a charge.
528
529 The member vector of \l IsotopicClusterChargePair instances is cleared before
530 the computations.
531 */
532 void
533 IsotopicClusterShaper::setIsotopicCluster(const pappso::Trace &isotopic_cluster,
534 int charge)
535 {
536 setIsotopicCluster(
537 std::make_shared<const pappso::Trace>(isotopic_cluster), charge, true);
538 }
539
540
541 /*!
542 \brief Handles the \a isotopic_cluster_charge_pair input isotopic cluster as a
543 IsotopicClusterChargePair.
544
545 The member vector of \l IsotopicClusterChargePair instances is cleared before
546 the computations.
547 */
548 void
549 IsotopicClusterShaper::setIsotopicCluster(
550 IsotopicClusterChargePair isotopic_cluster_charge_pair)
551 {
552 setIsotopicCluster(isotopic_cluster_charge_pair.first,
553 isotopic_cluster_charge_pair.second,
554 true);
555 }
556
557
558 /*!
559 \brief Handles the \a isotopic_cluster_charge_pair input isotopic cluster as a
560 IsotopicClusterChargePair.
561
562 If \a reset is true, the member vector of \l IsotopicClusterChargePair instances
563 is cleared before the computations.
564 */
565 void
566 IsotopicClusterShaper::setIsotopicCluster(
567 IsotopicClusterChargePair isotopic_cluster_charge_pair, bool reset)
568 {
569 setIsotopicCluster(isotopic_cluster_charge_pair.first,
570 isotopic_cluster_charge_pair.second,
571 reset);
572 }
573
574
575 /*!
576 \brief Handles the \a isotopic_cluster_charge_pairs input isotopic cluster as a
577 vector of IsotopicClusterChargePair instances.
578
579 If \a reset is true, the member vector of \l IsotopicClusterChargePair
580 instances is cleared before the computations.
581 */
582 void
583 IsotopicClusterShaper::setIsotopicClusterChargePairs(
584 const std::vector<IsotopicClusterChargePair> &isotopic_cluster_charge_pairs,
585 bool reset)
586 {
587 for(auto cluster_charge_pair : isotopic_cluster_charge_pairs)
588 setIsotopicCluster(
589 cluster_charge_pair.first, cluster_charge_pair.second, reset);
590
591 // qDebug() << qSetRealNumberPrecision(15) << "m_smallestMz:" << m_smallestMz
592 //<< "m_greatestMz:" << m_greatestMz
593 //<< "m_mostIntensePeakMz:" << m_mostIntensePeakMz;
594 }
595
596
597 /*!
598 \brief Handles the \a isotopic_cluster_charge_pairs input isotopic cluster as a
599 vector of IsotopicClusterChargePair instances.
600
601 The member vector of \l IsotopicClusterChargePair instances is cleared before
602 the computations.
603 */
604 void
605 IsotopicClusterShaper::setIsotopicClusterChargePairs(
606 const std::vector<IsotopicClusterChargePair> &isotopic_cluster_charge_pairs)
607 {
608 setIsotopicClusterChargePairs(isotopic_cluster_charge_pairs, true);
609
610 // qDebug() << qSetRealNumberPrecision(15) << "m_smallestMz:" << m_smallestMz
611 //<< "m_greatestMz:" << m_greatestMz
612 //<< "m_mostIntensePeakMz:" << m_mostIntensePeakMz;
613 }
614
615 /*!
616 \brief Adds an isotopic cluster in the form of the \a isotopic_cluster
617 pappso::Trace associated to the corresponding \a charge.
618
619 The member vector of \l IsotopicClusterChargePair instances is \e{not} cleared
620 before the computations.
621 */
622 void
623 IsotopicClusterShaper::appendIsotopicCluster(
624 const pappso::Trace &isotopic_cluster, int charge)
625 {
626 // Do not clear the isotopic clusters!
627
628 setIsotopicCluster(isotopic_cluster, charge, false);
629 }
630
631
632 /*!
633 \brief Adds isotopic clusters in the form of the \a
634 isotopic_cluster_charge_pairs vector of IsotopicClusterChargePair instances.
635
636 The member vector of \l IsotopicClusterChargePair instances is \e{not} cleared
637 before the computations.
638 */
639 void
640 IsotopicClusterShaper::appendIsotopicClusterChargePairs(
641 const std::vector<IsotopicClusterChargePair> &isotopic_cluster_charge_pairs)
642 {
643 setIsotopicClusterChargePairs(isotopic_cluster_charge_pairs, false);
644
645 // qDebug() << "m_smallestMz:" << m_smallestMz << "m_greatestMz:" <<
646 // m_greatestMz
647 //<< "m_mostIntensePeakMz:" << m_mostIntensePeakMz;
648 }
649
650 /*!
651 \brief Returns the final result of all the computations as a string.
652 */
653 QString
654 IsotopicClusterShaper::shapeToString()
655 {
656 return m_finalTrace.toString();
657 }
658
659 } // namespace libXpertMass
660
661 } // namespace MsXpS
662