GCC Code Coverage Report


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