GCC Code Coverage Report


./
File: src/XpertMass/MassPeakShaper.cpp
Date: 2024-08-24 11:26:06
Lines:
0/105
0.0%
Functions:
0/20
0.0%
Branches:
0/86
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 <iostream>
37 #include <iomanip>
38 #include <memory>
39
40
41 /////////////////////// Qt includes
42 #include <QDebug>
43 #include <QFile>
44
45
46 /////////////////////// pappsomspp includes
47 #include <pappsomspp/utils.h>
48
49
50 /////////////////////// Local includes
51 #include "MassPeakShaper.hpp"
52
53
54 namespace MsXpS
55 {
56 namespace libXpertMass
57 {
58
59
60 /*!
61 \class MsXpS::libXpertMass::MassPeakShaper
62 \inmodule libXpertMass
63 \ingroup XpertMassMassCalculations
64 \inheaderfile MassPeakShaper.hpp
65
66 \brief The MassPeakShaper class provides the features needed to shape a mass
67 peak.
68
69 \e{Shaping a peak} means creating a shape around a centroid m/z value such that
70 the m/z peak is represented like it appears in a mass spectrum displayed in
71 "profile" mode.
72
73 The configuration of the mass peak shaping is held in a specific \l
74 MassPeakShaperConfig class.
75
76 \sa MassPeakShaperConfig
77 */
78
79 /*!
80 \typedef MassPeakShaperSPtr
81 \relates MassPeakShaper
82
83 Synonym for std::shared_ptr<MassPeakShaper>.
84 */
85
86 /*!
87 \variable MsXpS::libXpertMass::MassPeakShaper::m_peakCentroid
88
89 \brief The peak centroid for which a shape is computed.
90
91 A peak centroid is the center of a mass peak profile and is thus the (m/z,
92 intensity) pair.
93 */
94
95 /*!
96 \variable MsXpS::libXpertMass::MassPeakShaper::m_config
97
98 \brief The configuration needed to drive the mass peak shaping process.
99 */
100
101 /*!
102 \variable MsXpS::libXpertMass::MassPeakShaper::m_trace
103
104 \brief The Trace object that will receive the different points that make the
105 peak shape.
106 */
107
108
109 /*!
110 \brief Constructs a MassPeakShaper instance.
111 */
112 MassPeakShaper::MassPeakShaper() : m_peakCentroid(0, 0)
113 {
114 }
115
116 /*!
117 \brief Constructs a MassPeakShaper instance.
118
119 \list
120 \li \a mz: The peak centroid m/z value.
121 \li \a intensity: The peak centroid intensity value.
122 \li \a config: The configuration driving the mass peak shaping process.
123 \endlist
124 */
125 MassPeakShaper::MassPeakShaper(double mz,
126 double intensity,
127 const MassPeakShaperConfig &config)
128 : m_peakCentroid(mz, intensity), m_config(config)
129 {
130 }
131
132
133 /*!
134 \brief Constructs a MassPeakShaper instance.
135
136 \list
137 \li \a data_point: The data point representing the peak centroid.
138 \li \a config: The configuration driving the mass peak shaping process.
139 \endlist
140 */
141 MassPeakShaper::MassPeakShaper(const pappso::DataPoint &data_point,
142 const MassPeakShaperConfig &config)
143 : m_peakCentroid(data_point), m_config(config)
144 {
145 // qDebug()"m_config:" << m_config.asText(800);
146 }
147
148
149 /*!
150 \brief Constructs a MassPeakShaper instance as a copy of \a other.
151 */
152 MassPeakShaper::MassPeakShaper(const MassPeakShaper &other)
153 : m_peakCentroid(other.m_peakCentroid),
154 m_config(other.m_config),
155 m_trace(other.m_trace)
156 {
157 }
158
159 /*!
160 \brief Destructs this MassPeakShaper instance.
161 */
162 MassPeakShaper::~MassPeakShaper()
163 {
164 }
165
166 /*!
167 \brief Sets the \a peak_centroid_data.
168 */
169 void
170 MassPeakShaper::setPeakCentroid(const pappso::DataPoint &peak_centroid_data)
171 {
172 m_peakCentroid = peak_centroid_data;
173 }
174
175
176 /*!
177 \brief Returns the peak centroid data.
178 */
179 const pappso::DataPoint &
180 MassPeakShaper::getPeakCentroid() const
181 {
182 return m_peakCentroid;
183 }
184
185 /*!
186 \brief Returns the peak shape as a pappso::Trace.
187 */
188 const pappso::Trace &
189 MassPeakShaper::getTrace() const
190 {
191 return m_trace;
192 }
193
194 /*
195 \brief Clears the peak shape.
196 */
197 void
198 MassPeakShaper::clearTrace()
199 {
200 m_trace.clear();
201 }
202
203 /*!
204 \brief Sets the configuration driving the peak shaping process to \a config.
205 */
206 void
207 MassPeakShaper::setConfig(const MassPeakShaperConfig &config)
208 {
209 m_config = config;
210 }
211
212
213 /*!
214 \brief Returns the configuration driving the peak shaping process.
215 */
216 const MassPeakShaperConfig &
217 MassPeakShaper::getConfig() const
218 {
219 return m_config;
220 }
221
222 /*!
223 \brief Computes the peak shape of the peak centroid.
224
225 Returns the count of points in the peak shape.
226 */
227 int
228 MassPeakShaper::computePeakShape()
229 {
230 if(m_config.getMassPeakShapeType() == MassPeakShapeType::GAUSSIAN)
231 return computeGaussianPeakShape();
232 else
233 return computeLorentzianPeakShape();
234 }
235
236
237 /*!
238 \brief Computes the peak shape of the peak centroid.
239
240 \list
241 \li \a mz: the peak centroid's m/z value.
242 \li \a intensity: the peak centroid's intensity value.
243 \li \a config: the configuration driving the peak shaping process.
244 \endlist
245
246 Returns the pappso::Trace describing the peak shape.
247 */
248 pappso::Trace
249 MassPeakShaper::computePeakShape(double mz,
250 double intensity,
251 const MassPeakShaperConfig &config)
252 {
253 if(config.getMassPeakShapeType() == MassPeakShapeType::GAUSSIAN)
254 return computeGaussianPeakShape(mz, intensity, config);
255 else
256 return computeLorentzianPeakShape(mz, intensity, config);
257 }
258
259
260 /*!
261 \brief Computes the Gaussian peak shape of the peak centroid.
262 */
263 int
264 MassPeakShaper::computeGaussianPeakShape()
265 {
266 // qDebug();
267
268 m_trace.clear();
269
270 m_trace =
271 computeGaussianPeakShape(m_peakCentroid.x, m_peakCentroid.y, m_config);
272
273 return m_trace.size();
274 }
275
276
277 /*!
278 \brief Computes the Gaussian peak shape of the peak centroid.
279
280 \list
281 \li \a mz: the peak centroid's m/z value.
282 \li \a intensity: the peak centroid's intensity value.
283 \li \a config: the configuration driving the peak shaping process.
284 \endlist
285
286 Returns the pappso::Trace describing the peak shape.
287 */
288 pappso::Trace
289 MassPeakShaper::computeGaussianPeakShape(double mz,
290 double intensity,
291 const MassPeakShaperConfig &config)
292 {
293 pappso::Trace trace;
294
295 // We will use the data in the configuration object. First check that
296 // we can rely on it. This call sets all the proper values to the m_config's
297 // member data after having validate each.
298
299 MassPeakShaperConfig local_config = config;
300
301 if(!local_config.resolve())
302 {
303 qDebug() << "Failed to resolve the MassPeakShaperConfig.";
304 return trace;
305 }
306
307 // qDebug() << "The peak shaper configuration:" << m_config.toString();
308
309 // First off, we need to tell what the height of the gaussian peak should
310 // be.
311 double a;
312 // a = m_config.a(mz);
313
314 // We actually set a to 1, because it is the intensity above that will
315 // provide the height of the peak, see below where the height of the peak is
316 // set to a * intensity, that is, intensity if a = 1.
317 a = 1;
318
319 // qDebug() << "a:" << a;
320
321 bool ok = false;
322
323 double c = local_config.c(&ok);
324
325 if(!ok)
326 {
327 return trace;
328 }
329
330 double c_square = c * c;
331
332 // qDebug() << "c:" << c << "c²:" << c_square;
333
334
335 // Were are the left and right points of the shape ? We have to
336 // determine that using the point count and mz step values.
337
338 // Compute the mz step that will separate two consecutive points of the
339 // shape. This mzStep is function of the number of points we want for a
340 // given peak shape and the width of the peak shape left and right of the
341 // centroid.
342
343 double mz_step = local_config.getMzStep();
344
345 double left_point =
346 mz - ((double)FWHM_PEAK_SPAN_FACTOR / 2 * local_config.getFwhm());
347 double right_point =
348 mz + ((double)FWHM_PEAK_SPAN_FACTOR / 2 * local_config.getFwhm());
349
350 // qDebug() << "left m/z:" << left_point;
351 // qDebug() << "right m/z:" << right_point;
352
353 int iterations = (right_point - left_point) / mz_step;
354 double x = left_point;
355
356 for(int iter = 0; iter < iterations; ++iter)
357 {
358 double y = intensity * a * exp(-1 * (pow((x - mz), 2) / (2 * c_square)));
359
360 trace.push_back(pappso::DataPoint(x, y));
361
362 x += mz_step;
363 }
364
365 //qDebug() << qSetRealNumberPrecision(15) << "For centroid" << mz
366 //<< "first shape point:" << left_point
367 //<< "with trace:" << trace.toString();
368
369 return trace;
370 }
371
372 /*!
373 \brief Computes the Lorentzian peak shape of the peak centroid.
374 */
375 int
376 MassPeakShaper::computeLorentzianPeakShape()
377 {
378 // qDebug();
379
380 m_trace.clear();
381
382 m_trace =
383 computeLorentzianPeakShape(m_peakCentroid.x, m_peakCentroid.y, m_config);
384
385 return m_trace.size();
386 }
387
388 /*!
389 \brief Computes the Lorentzian peak shape of the peak centroid.
390
391 \list
392 \li \a mz: the peak centroid's m/z value.
393 \li \a intensity: the peak centroid's intensity value.
394 \li \a config: the configuration driving the peak shaping process.
395 \endlist
396
397 Returns the pappso::Trace describing the peak shape.
398 */
399 pappso::Trace
400 MassPeakShaper::computeLorentzianPeakShape(double mz,
401 double intensity,
402 const MassPeakShaperConfig &config)
403 {
404 pappso::Trace trace;
405
406 // We will use the data in the configuration object. First check that
407 // we can rely on it. This call sets all the proper values to the m_config's
408 // member data after having validate each.
409
410 MassPeakShaperConfig local_config = config;
411
412 if(!local_config.resolve())
413 {
414 qDebug() << "Failed to resolve the MassPeakShaperConfig.";
415 return trace;
416 }
417
418 // qDebug() << "The peak shaper configuration:" << m_config.toString();
419
420 // First off, we need to tell what the height of the gaussian peak should
421 // be.
422 double a;
423 // a = local_config.a(mz);
424
425 // We actually set a to 1, because it is the intensity above that will
426 // provide the height of the peak, see below where the heigh of the peak is
427 // set to a * intensity, that is, intensity if a = 1.
428 a = 1;
429
430 // qDebug() << "a value:" << a;
431
432 bool ok = false;
433
434 // The calls below will trigger the computation of fwhm, if it is
435 // equal to 0 because it was not set manually.
436 double gamma = local_config.gamma(&ok);
437
438 if(!ok)
439 {
440 return trace;
441 }
442
443 double gamma_square = gamma * gamma;
444
445 // qDebug() << "gamma:" << gamma << "gamma²:" << gamma_square;
446
447 // Were are the left and right points of the shape ? We have to
448 // determine that using the m_points and m_increment values.
449
450 // Compute the mz step that will separate two consecutive points of the
451 // shape. This mzStep is function of the number of points we want for a
452 // given peak shape and the width of the peak shape left and right of the
453 // centroid.
454
455 double mz_step = local_config.getMzStep();
456
457 double left_point =
458 mz - ((double)FWHM_PEAK_SPAN_FACTOR / 2 * local_config.getFwhm());
459 double right_point =
460 mz + ((double)FWHM_PEAK_SPAN_FACTOR / 2 * local_config.getFwhm());
461
462 // qDebug() << "left m/z:" << left_point;
463 // qDebug() << "right m/z:" << right_point;
464
465 int iterations = (right_point - left_point) / mz_step;
466 double x = left_point;
467
468 for(int iter = 0; iter < iterations; ++iter)
469 {
470 double y =
471 intensity * a * (gamma_square / (pow((x - mz), 2) + gamma_square));
472
473 trace.push_back(pappso::DataPoint(x, y));
474
475 x += mz_step;
476 }
477
478 // qDebug().noquote() << m_trace.toString();
479
480 return trace;
481 }
482
483 /*!
484 \brief Returns the intensity of a data point in the member peak shape
485 pappso::Trace (m_trace).
486
487 If the member pappso::Trace contains a data point having its x value equal to
488 \a mz (comparison performed using tolerance \a precision_p), then return the
489 intensity (y member) of that data point and set \a ok to true. Otherwise,
490 return 0 and set \a ok to false.
491 */
492 double
493 MassPeakShaper::intensityAt(double mz,
494 pappso::PrecisionPtr precision_p,
495 bool &ok)
496 {
497 pappso::DataPoint data_point = m_trace.containsX(mz, precision_p);
498
499 if(data_point.isValid())
500 {
501 ok = true;
502 return data_point.y;
503 }
504
505 ok = false;
506 return 0;
507 }
508
509 /*!
510 \brief Returns a string with the data in the member pappso::Trace.
511 */
512 QString
513 MassPeakShaper::shapetoString()
514 {
515 return m_trace.toString();
516 }
517
518 /*!
519 \brief Writes to \a file_name a string containing the member pappso::Trace
520 data.
521
522 Returns true if successful, false otherwise.
523
524 \sa shapetoString()
525 */
526 bool
527 MassPeakShaper::shapeToFile(const QString &file_name)
528 {
529 return pappso::Utils::writeToFile(m_trace.toString(), file_name);
530 }
531
532
533 } // namespace libXpertMass
534
535 } // namespace MsXpS
536