| 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 | |||
| 37 | |||
| 38 | /////////////////////// Qt includes | ||
| 39 | #include <QDebug> | ||
| 40 | |||
| 41 | |||
| 42 | /////////////////////// pappsomspp includes | ||
| 43 | |||
| 44 | |||
| 45 | /////////////////////// Local includes | ||
| 46 | #include "MassPeakShaperConfig.hpp" | ||
| 47 | |||
| 48 | |||
| 49 | namespace MsXpS | ||
| 50 | { | ||
| 51 | namespace libXpertMass | ||
| 52 | { | ||
| 53 | |||
| 54 | |||
| 55 | /*! | ||
| 56 | \variable MsXpS::libXpertMass::FWHM_PEAK_SPAN_FACTOR | ||
| 57 | |||
| 58 | \brief The compounding factor to account for when shaping the sides of the | ||
| 59 | peak. | ||
| 60 | |||
| 61 | The shape of the peak needs to reflect a real mass peak. In particular, | ||
| 62 | the shape of the peak has to return, \e{on each one of both sides}, to the | ||
| 63 | baseline, thus mimicking the baseline for a m/z distance equivalent to | ||
| 64 | FWHM_PEAK_SPAN_FACTOR times the FWHM m/z range from left to right. That means | ||
| 65 | that the simulated peak region at the left hand side of the centroid value will | ||
| 66 | span (FWHM_PEAK_SPAN_FACTOR/2) times the FWHM and the same one right. | ||
| 67 | Empirically, a good FWHM_PEAK_SPAN_FACTOR is \c 4, meaning that the left half | ||
| 68 | of the peak (that is centered on the centroid) will have a size corresponding | ||
| 69 | to two times the FHWM, and the same for the right half of the peak. | ||
| 70 | |||
| 71 | This is best exemplified as follows: | ||
| 72 | |||
| 73 | \code | ||
| 74 | Centroid value | ||
| 75 | ^ | ||
| 76 | | | ||
| 77 | [ m/z - (2 * FWHM) <-|-> m/z + (2 * FWHM) ] | ||
| 78 | <----- width of the whole peak shape -----> | ||
| 79 | \endcode | ||
| 80 | */ | ||
| 81 | |||
| 82 | int FWHM_PEAK_SPAN_FACTOR = 4; | ||
| 83 | |||
| 84 | |||
| 85 | /*! | ||
| 86 | \class MsXpS::libXpertMass::MassPeakShaperConfig | ||
| 87 | \inmodule libXpertMass | ||
| 88 | \ingroup XpertMassMassCalculations | ||
| 89 | \inheaderfile MassPeakShaperConfig.hpp | ||
| 90 | |||
| 91 | \brief The MassPeakShaperConfig class provides the features required to | ||
| 92 | configure the shaping of a mass peak centroid into a Gaussian or a Lorentzian | ||
| 93 | fully profiled shape. | ||
| 94 | |||
| 95 | \e{Shaping a peak} means creating a shape around a centroid m/z value such that | ||
| 96 | the m/z peak is represented like it appears in a mass spectrum displayed in | ||
| 97 | "profile" mode. | ||
| 98 | |||
| 99 | \details{The peak shaping process} | ||
| 100 | |||
| 101 | The model used to craft the "profiled" mass peak can be of two types: | ||
| 102 | |||
| 103 | \list | ||
| 104 | \li \l{https://en.wikipedia.org/wiki/Gaussian_function}{Gaussian} | ||
| 105 | \li \l{https://en.wikipedia.org/wiki/Cauchy_distribution}{Lorentzian} | ||
| 106 | \endlist | ||
| 107 | |||
| 108 | The starting parameters are the (m/z,intensity) values of the peak centroid and | ||
| 109 | the full width at half maximum (FWHM) value that will govern the width of the | ||
| 110 | shape at 50% height of the peak. The width of the peak will be an inverse | ||
| 111 | representation of the resolving power of the instrument: the instrument with | ||
| 112 | the greatest resolving power will yield mass peaks with the smallest width. | ||
| 113 | Conversely, a very old instrument will produce mass spectra where the peaks | ||
| 114 | will be broad. | ||
| 115 | |||
| 116 | There are thus two possiblities for configuring the peak shape: | ||
| 117 | |||
| 118 | \list | ||
| 119 | |||
| 120 | \li Provide the FWHM value itself. | ||
| 121 | \li Provide the resolving power of the instrument that the peak simulation | ||
| 122 | should emulate. | ||
| 123 | |||
| 124 | \endlist | ||
| 125 | |||
| 126 | \enddetails | ||
| 127 | */ | ||
| 128 | |||
| 129 | /*! | ||
| 130 | \enum MsXpS::libXpertMass::MassPeakShapeType | ||
| 131 | |||
| 132 | This enum specifies the type of mass peak shape to be computed around a m/z | ||
| 133 | peak centroid. | ||
| 134 | |||
| 135 | \value GAUSSIAN | ||
| 136 | The peak will be shaped using the Gaussian model. | ||
| 137 | \value LORENTZIAN | ||
| 138 | The peak will be shaped using the Lorentizan model. | ||
| 139 | \omitvalue NOT_SET. | ||
| 140 | */ | ||
| 141 | |||
| 142 | /*! | ||
| 143 | \enum MsXpS::libXpertMass::MassPeakWidthLogic | ||
| 144 | |||
| 145 | This enum specifies the logic used to computed the width of the mass peak | ||
| 146 | shape around a m/z peak centroid. | ||
| 147 | |||
| 148 | \value FWHM | ||
| 149 | The full width at half maximum is directly used to compute the peak | ||
| 150 | shape width. | ||
| 151 | \value RESOLUTION | ||
| 152 | The resolving power of the instrument is the starting point to compute | ||
| 153 | the FWHM. | ||
| 154 | \omitvalue NOT_SET. | ||
| 155 | */ | ||
| 156 | |||
| 157 | |||
| 158 | /*! | ||
| 159 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_resolution | ||
| 160 | |||
| 161 | \brief Resolving power of the instrument. | ||
| 162 | */ | ||
| 163 | |||
| 164 | /*! | ||
| 165 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_fwhm | ||
| 166 | |||
| 167 | \brief Full width at half maximum of the shaped peak. | ||
| 168 | */ | ||
| 169 | |||
| 170 | /*! | ||
| 171 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_massPeakWidthLogic | ||
| 172 | |||
| 173 | \brief Describes the logic used to compute the peak shape width. | ||
| 174 | */ | ||
| 175 | |||
| 176 | /*! | ||
| 177 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_referencePeakMz | ||
| 178 | |||
| 179 | \brief The m/z value to be used when computing the FWHM value starting from a | ||
| 180 | mass spectrometer resolving power. | ||
| 181 | */ | ||
| 182 | |||
| 183 | /*! | ||
| 184 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_pointCount | ||
| 185 | |||
| 186 | \brief The count of points used to shape the peak. Typically between 150 and | ||
| 187 | 300. | ||
| 188 | */ | ||
| 189 | |||
| 190 | /*! | ||
| 191 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_withBins | ||
| 192 | |||
| 193 | \brief Tells if bins are requested for the computation. | ||
| 194 | |||
| 195 | There is no need in the context of the calculations performed by the | ||
| 196 | MassPeakShaperConfig class to know if bins are required or not. This variable | ||
| 197 | is useful when multiple peak shapes are combined into a more complex trace or | ||
| 198 | mass spectrum, typically when simulating an isotopic cluster. In this case, | ||
| 199 | each cluster peak centroid is shaped in sequence and then they are all merged | ||
| 200 | into a single trace (no bins) or mass spectrum (binning). The width of the bins | ||
| 201 | is defined using this m_withBins variable. | ||
| 202 | */ | ||
| 203 | |||
| 204 | /*! | ||
| 205 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_binSizeDivisor | ||
| 206 | |||
| 207 | \brief Empirical division factor to apply to \l m_binSize to reduce the size of | ||
| 208 | the bins after the bin size calculation. | ||
| 209 | |||
| 210 | Empirically, a good value is \c 6. | ||
| 211 | */ | ||
| 212 | |||
| 213 | /*! | ||
| 214 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_binSize | ||
| 215 | |||
| 216 | \brief The size of the m/z bins. | ||
| 217 | */ | ||
| 218 | |||
| 219 | /*! | ||
| 220 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_isBinSizeFixed | ||
| 221 | |||
| 222 | \brief Tells if the size of the m/z bins is fixed. | ||
| 223 | */ | ||
| 224 | |||
| 225 | /*! | ||
| 226 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_mzStep | ||
| 227 | |||
| 228 | \brief The m/z distance (a Delta) between to consecutive data points in the | ||
| 229 | shaped mass peak. | ||
| 230 | */ | ||
| 231 | |||
| 232 | /*! | ||
| 233 | \variable MsXpS::libXpertMass::MassPeakShaperConfig::m_massPeakShapeType | ||
| 234 | |||
| 235 | \brief The requested shape of the mass peak. | ||
| 236 | */ | ||
| 237 | |||
| 238 | |||
| 239 | /*! | ||
| 240 | \brief Constructs a MassPeakShaperConfig instance. | ||
| 241 | */ | ||
| 242 | ✗ | MassPeakShaperConfig::MassPeakShaperConfig() | |
| 243 | { | ||
| 244 | ✗ | reset(); | |
| 245 | ✗ | } | |
| 246 | |||
| 247 | |||
| 248 | /*! | ||
| 249 | \brief Constructs a MassPeakShaperConfig instance as a copy of \a other. | ||
| 250 | */ | ||
| 251 | ✗ | MassPeakShaperConfig::MassPeakShaperConfig(const MassPeakShaperConfig &other) | |
| 252 | ✗ | : m_resolution(other.m_resolution), | |
| 253 | ✗ | m_fwhm(other.m_fwhm), | |
| 254 | ✗ | m_massPeakWidthLogic(other.m_massPeakWidthLogic), | |
| 255 | ✗ | m_referencePeakMz(other.m_referencePeakMz), | |
| 256 | ✗ | m_pointCount(other.m_pointCount), | |
| 257 | ✗ | m_withBins(other.m_withBins), | |
| 258 | ✗ | m_binSizeDivisor(other.m_binSizeDivisor), | |
| 259 | ✗ | m_binSize(other.m_binSize), | |
| 260 | ✗ | m_isBinSizeFixed(other.m_isBinSizeFixed), | |
| 261 | ✗ | m_mzStep(other.m_mzStep), | |
| 262 | ✗ | m_massPeakShapeType(other.m_massPeakShapeType) | |
| 263 | { | ||
| 264 | ✗ | } | |
| 265 | |||
| 266 | /*! | ||
| 267 | \brief Destructs this MassPeakShaperConfig instance. | ||
| 268 | */ | ||
| 269 | ✗ | MassPeakShaperConfig::~MassPeakShaperConfig() | |
| 270 | { | ||
| 271 | ✗ | } | |
| 272 | |||
| 273 | /*! | ||
| 274 | \brief Assigns \a other to this MassPeakShaperConfig instance. | ||
| 275 | */ | ||
| 276 | void | ||
| 277 | ✗ | MassPeakShaperConfig::operator=(const MassPeakShaperConfig &other) | |
| 278 | { | ||
| 279 | ✗ | m_resolution = other.m_resolution; | |
| 280 | ✗ | m_fwhm = other.m_fwhm; | |
| 281 | ✗ | m_massPeakWidthLogic = other.m_massPeakWidthLogic; | |
| 282 | ✗ | m_referencePeakMz = other.m_referencePeakMz; | |
| 283 | ✗ | m_pointCount = other.m_pointCount; | |
| 284 | ✗ | m_withBins = other.m_withBins; | |
| 285 | ✗ | m_binSizeDivisor = other.m_binSizeDivisor; | |
| 286 | ✗ | m_binSize = other.m_binSize; | |
| 287 | ✗ | m_isBinSizeFixed = other.m_isBinSizeFixed; | |
| 288 | ✗ | m_mzStep = other.m_mzStep; | |
| 289 | ✗ | m_massPeakShapeType = other.m_massPeakShapeType; | |
| 290 | ✗ | } | |
| 291 | |||
| 292 | /*! | ||
| 293 | \brief Sets the \a resolution (the resolving power of the instrument). | ||
| 294 | */ | ||
| 295 | void | ||
| 296 | ✗ | MassPeakShaperConfig::setResolution(int resolution) | |
| 297 | { | ||
| 298 | ✗ | m_resolution = resolution; | |
| 299 | ✗ | } | |
| 300 | |||
| 301 | /*! | ||
| 302 | \brief Returns the resolution (the resolving power of the instrument). | ||
| 303 | */ | ||
| 304 | double | ||
| 305 | ✗ | MassPeakShaperConfig::getResolution() const | |
| 306 | { | ||
| 307 | ✗ | return m_resolution; | |
| 308 | } | ||
| 309 | |||
| 310 | /*! | ||
| 311 | \brief Calculates the resolution (resolving power of the instrument). | ||
| 312 | |||
| 313 | The calculation involves using the FWHM (m_fwhm) member datum and the m/z value | ||
| 314 | that is considered to be the reference for the calculation (m_referencePeakMz). | ||
| 315 | |||
| 316 | If any of these two values is not set, then this function returns 0 and sets \a | ||
| 317 | ok to false. | ||
| 318 | |||
| 319 | The calculation is that simple: | ||
| 320 | |||
| 321 | \code | ||
| 322 | m_resolution = m_referencePeakMz / m_fwhm; | ||
| 323 | \endcode | ||
| 324 | |||
| 325 | Because we used the FWHM to compute the resolution and set the calculated value | ||
| 326 | to the \l m_resolution member datum, we keep a record of this by: | ||
| 327 | |||
| 328 | \code | ||
| 329 | m_massPeakWidthLogic = MassPeakWidthLogic::FWHM; | ||
| 330 | \endcode | ||
| 331 | |||
| 332 | Returns the resolving power as set in \l m_resolution and sets \a ok to true. | ||
| 333 | */ | ||
| 334 | int | ||
| 335 | ✗ | MassPeakShaperConfig::resolution(bool *ok) | |
| 336 | { | ||
| 337 | ✗ | if(ok == nullptr) | |
| 338 | ✗ | qFatal("The pointer cannot be nullptr."); | |
| 339 | |||
| 340 | // If we want to compute the resolution that means that we have to have | ||
| 341 | // m_fwhm. | ||
| 342 | ✗ | if(!m_fwhm) | |
| 343 | { | ||
| 344 | ✗ | *ok = false; | |
| 345 | ✗ | return 0; | |
| 346 | } | ||
| 347 | |||
| 348 | ✗ | if(!m_referencePeakMz) | |
| 349 | { | ||
| 350 | ✗ | *ok = false; | |
| 351 | ✗ | return 0; | |
| 352 | } | ||
| 353 | |||
| 354 | ✗ | m_resolution = m_referencePeakMz / m_fwhm; | |
| 355 | |||
| 356 | ✗ | *ok = true; | |
| 357 | |||
| 358 | // We used the FWHM to compute the resolving power. | ||
| 359 | ✗ | m_massPeakWidthLogic = MassPeakWidthLogic::FWHM; | |
| 360 | |||
| 361 | ✗ | return m_resolution; | |
| 362 | } | ||
| 363 | |||
| 364 | |||
| 365 | /*! | ||
| 366 | \brief Sets the \a fwhm (full width at half maximum). | ||
| 367 | */ | ||
| 368 | void | ||
| 369 | ✗ | MassPeakShaperConfig::setFwhm(double fwhm) | |
| 370 | { | ||
| 371 | ✗ | m_fwhm = fwhm; | |
| 372 | ✗ | } | |
| 373 | |||
| 374 | |||
| 375 | /*! | ||
| 376 | \brief Gets the fwhm (full width at half maximum). | ||
| 377 | */ | ||
| 378 | double | ||
| 379 | ✗ | MassPeakShaperConfig::getFwhm() const | |
| 380 | { | ||
| 381 | ✗ | return m_fwhm; | |
| 382 | } | ||
| 383 | |||
| 384 | |||
| 385 | /*! | ||
| 386 | \brief Calculates the fwhm (full width at half maximum). | ||
| 387 | |||
| 388 | The calculation involves using the instrument's resolving power (m_resolution) | ||
| 389 | member datum and the m/z value that is considered to be the reference for the | ||
| 390 | calculation (m_referencePeakMz). | ||
| 391 | |||
| 392 | If any of these two values is not set, then this function returns 0 and sets \a | ||
| 393 | ok to false. | ||
| 394 | |||
| 395 | The calculation is that simple: | ||
| 396 | |||
| 397 | \code | ||
| 398 | m_fwhm = m_referencePeakMz / m_resolution; | ||
| 399 | \endcode | ||
| 400 | |||
| 401 | Because we used the resolution to compute the FWHM and set the calculated | ||
| 402 | value | ||
| 403 | to the \l m_fwhm member datum, we keep a record of this by: | ||
| 404 | |||
| 405 | \code | ||
| 406 | m_massPeakWidthLogic = MassPeakWidthLogic::RESOLUTION; | ||
| 407 | \endcode | ||
| 408 | |||
| 409 | Returns the FWHM value as set in \l m_fwhm and sets \a ok to true. | ||
| 410 | */ | ||
| 411 | double | ||
| 412 | ✗ | MassPeakShaperConfig::fwhm(bool *ok) | |
| 413 | { | ||
| 414 | ✗ | if(ok == nullptr) | |
| 415 | ✗ | qFatal("The pointer cannot be nullptr."); | |
| 416 | |||
| 417 | // Or we need to compute it using the mz passed as parameter and the | ||
| 418 | // resolution. | ||
| 419 | ✗ | if(!m_resolution) | |
| 420 | { | ||
| 421 | ✗ | *ok = false; | |
| 422 | ✗ | return 0; | |
| 423 | } | ||
| 424 | |||
| 425 | ✗ | if(!m_referencePeakMz) | |
| 426 | { | ||
| 427 | // qDebug() << "There is no reference peak centroid!"; | ||
| 428 | |||
| 429 | ✗ | *ok = false; | |
| 430 | ✗ | return 0; | |
| 431 | } | ||
| 432 | |||
| 433 | ✗ | m_fwhm = m_referencePeakMz / m_resolution; | |
| 434 | ✗ | *ok = true; | |
| 435 | |||
| 436 | // We used the resolving power to compute the FWHM. | ||
| 437 | ✗ | m_massPeakWidthLogic = MassPeakWidthLogic::RESOLUTION; | |
| 438 | |||
| 439 | ✗ | return m_fwhm; | |
| 440 | } | ||
| 441 | |||
| 442 | /*! | ||
| 443 | \brief Returns the half of the FWMH (m_fwhm) for use in the Lorentzian shape | ||
| 444 | calculation. | ||
| 445 | |||
| 446 | Uses the \l fwhm() function to compute the FWHM value. If the | ||
| 447 | FWHM calculation fails, returns 0 and \a ok is set to false, otherwise returns | ||
| 448 | half of FWHM and \a ok is set to true. | ||
| 449 | |||
| 450 | \sa fwhm() | ||
| 451 | */ | ||
| 452 | double | ||
| 453 | ✗ | MassPeakShaperConfig::halfFwhm(bool *ok) | |
| 454 | { | ||
| 455 | ✗ | double fwhm_value = fwhm(ok); | |
| 456 | |||
| 457 | ✗ | if(!*ok) | |
| 458 | ✗ | return 0; | |
| 459 | |||
| 460 | ✗ | return (fwhm_value / 2); | |
| 461 | } | ||
| 462 | |||
| 463 | /*! | ||
| 464 | \brief Sets the reference m/z value required for calculations to \a mz. | ||
| 465 | */ | ||
| 466 | void | ||
| 467 | ✗ | MassPeakShaperConfig::setReferencePeakMz(double mz) | |
| 468 | { | ||
| 469 | ✗ | m_referencePeakMz = mz; | |
| 470 | ✗ | } | |
| 471 | |||
| 472 | /*! | ||
| 473 | \brief Gets the reference m/z value required for calculations. | ||
| 474 | */ | ||
| 475 | double | ||
| 476 | ✗ | MassPeakShaperConfig::getReferencePeakMz() const | |
| 477 | { | ||
| 478 | ✗ | return m_referencePeakMz; | |
| 479 | } | ||
| 480 | |||
| 481 | |||
| 482 | /*! | ||
| 483 | \brief Sets the requirement to prepare m/z bins at a later computing stage to | ||
| 484 | \a with_bins. | ||
| 485 | |||
| 486 | \sa IsotopicClusterShaper::run() | ||
| 487 | */ | ||
| 488 | void | ||
| 489 | ✗ | MassPeakShaperConfig::setWithBins(bool with_bins) | |
| 490 | { | ||
| 491 | ✗ | m_withBins = with_bins; | |
| 492 | ✗ | } | |
| 493 | |||
| 494 | |||
| 495 | /*! | ||
| 496 | \brief Returns the requirement to prepare m/z bins at a later computing stage. | ||
| 497 | |||
| 498 | \sa IsotopicClusterShaper::run() | ||
| 499 | */ | ||
| 500 | bool | ||
| 501 | ✗ | MassPeakShaperConfig::withBins() const | |
| 502 | { | ||
| 503 | ✗ | return m_withBins; | |
| 504 | } | ||
| 505 | |||
| 506 | /*! | ||
| 507 | \brief Sets the \a bin_size. | ||
| 508 | */ | ||
| 509 | void | ||
| 510 | ✗ | MassPeakShaperConfig::setBinSize(double bin_size) | |
| 511 | { | ||
| 512 | ✗ | m_binSize = bin_size; | |
| 513 | ✗ | } | |
| 514 | |||
| 515 | |||
| 516 | /*! | ||
| 517 | \brief Computes the bin size. | ||
| 518 | |||
| 519 | If there is no requirement for bins (m_withBins is false), returns 0 and set \a | ||
| 520 | ok to true. | ||
| 521 | |||
| 522 | In order to compute the bin size we need that at least the FWHM (m_fwhm) or the | ||
| 523 | resolving power (m_resolution) be set. If none of these values are set, this | ||
| 524 | function returns 0 and sets \a ok to false. | ||
| 525 | |||
| 526 | If the bin size was fixed (m_isBinSizeFixed is true), then the bin size | ||
| 527 | (m_binSize) must be set. If that is not the case, the function returns 0 and | ||
| 528 | sets \a ok to false. | ||
| 529 | |||
| 530 | If the FWHM value (m_fwhm) is set, then it is used right away. Otherwise, the | ||
| 531 | FWHM is computed starting from the resolving power (m_resolution). If that | ||
| 532 | computation fails, the function returns 0 and sets \a ok to false. | ||
| 533 | |||
| 534 | Starting from the FWHM value (m_fwhm), the bin size calculation requires that | ||
| 535 | the m_binSizeDivisor be > 1. The bin size is thus computed as the ratio FWHM / | ||
| 536 | m_binSizeDivisor, and the obtained value is set to m_binSize. | ||
| 537 | |||
| 538 | Empirically, a value of 6 for m_binSizeDivisor, yields bin sizes that allow | ||
| 539 | combining correctly multiple peak shapes into a mass spectrum. Essentially, | ||
| 540 | that means that 6 individual m/z bins are required to combine nicely all the | ||
| 541 | peaks shapes obtained for all the peak centroids in a given isotopic cluster, | ||
| 542 | for example. | ||
| 543 | |||
| 544 | At this point, the function returns the bin size and sets \a ok to true. | ||
| 545 | |||
| 546 | \sa setBinSizeDivisor() | ||
| 547 | */ | ||
| 548 | double | ||
| 549 | ✗ | MassPeakShaperConfig::binSize(bool *ok) | |
| 550 | { | ||
| 551 | ✗ | if(ok == nullptr) | |
| 552 | ✗ | qFatal("The pointer cannot be nullptr."); | |
| 553 | |||
| 554 | // If the bin size was set before, then, just return it. | ||
| 555 | // if(m_binSize) | ||
| 556 | //{ | ||
| 557 | //*ok = true; | ||
| 558 | // return m_binSize; | ||
| 559 | //} | ||
| 560 | |||
| 561 | ✗ | if(!m_withBins) | |
| 562 | { | ||
| 563 | // qDebug() << "Bins are not requested, just return 0 and set true."; | ||
| 564 | ✗ | *ok = true; | |
| 565 | ✗ | return 0; | |
| 566 | } | ||
| 567 | |||
| 568 | // In order to compute the bin Size, we need the FWHM and the number of | ||
| 569 | // points. | ||
| 570 | |||
| 571 | ✗ | if(!m_resolution && !m_fwhm) | |
| 572 | { | ||
| 573 | // qDebug() << "That's an error when neither resolution nor FWHM is set."; | ||
| 574 | ✗ | *ok = false; | |
| 575 | ✗ | return 0; | |
| 576 | } | ||
| 577 | |||
| 578 | ✗ | if(m_fwhm) | |
| 579 | { | ||
| 580 | // FWHM is fine, we can use that immediately. | ||
| 581 | |||
| 582 | // qDebug() << "FWHM:" << m_fwhm; | ||
| 583 | |||
| 584 | ✗ | if(!m_pointCount) | |
| 585 | { | ||
| 586 | // qDebug() << "That's an error that the point count is 0."; | ||
| 587 | ✗ | *ok = false; | |
| 588 | ✗ | return 0; | |
| 589 | } | ||
| 590 | } | ||
| 591 | else | ||
| 592 | { | ||
| 593 | // We have to work with the resolution. | ||
| 594 | |||
| 595 | // qDebug() << "Resolution:" << m_resolution; | ||
| 596 | |||
| 597 | ✗ | fwhm(ok); | |
| 598 | |||
| 599 | ✗ | if(!*ok) | |
| 600 | { | ||
| 601 | // qDebug() | ||
| 602 | //<< "Could not compute FWHM on the basis of the resolution."; | ||
| 603 | |||
| 604 | ✗ | if(!m_pointCount) | |
| 605 | { | ||
| 606 | // qDebug() << "That's an error that the point count is 0."; | ||
| 607 | ✗ | *ok = false; | |
| 608 | ✗ | return 0; | |
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | ✗ | if(m_isBinSizeFixed) | |
| 614 | { | ||
| 615 | // The bin size has to be set and must not be changed, as the user has | ||
| 616 | // set it manually. | ||
| 617 | |||
| 618 | ✗ | if(!m_binSize) | |
| 619 | { | ||
| 620 | // qDebug() << "The bin size should be set manually but is not set."; | ||
| 621 | ✗ | *ok = false; | |
| 622 | ✗ | return 0; | |
| 623 | } | ||
| 624 | } | ||
| 625 | else | ||
| 626 | { | ||
| 627 | ✗ | m_binSize = m_fwhm / m_binSizeDivisor; | |
| 628 | |||
| 629 | // qDebug() << "The bin size was computed:" << m_binSize; | ||
| 630 | } | ||
| 631 | |||
| 632 | ✗ | *ok = true; | |
| 633 | ✗ | return m_binSize; | |
| 634 | } | ||
| 635 | |||
| 636 | /*! | ||
| 637 | \brief Returns (no computation) the bin size. | ||
| 638 | */ | ||
| 639 | double | ||
| 640 | ✗ | MassPeakShaperConfig::getBinSize() const | |
| 641 | { | ||
| 642 | ✗ | return m_binSize; | |
| 643 | } | ||
| 644 | |||
| 645 | /*! | ||
| 646 | \brief Sets the requirement that the bin size be set and fixed (not modifiable | ||
| 647 | by computations) to \a is_fixed. | ||
| 648 | |||
| 649 | When \a is_fixed is true, the \l binSize() function returns the bin size | ||
| 650 | without trying to compute it. | ||
| 651 | |||
| 652 | \sa binSize() | ||
| 653 | */ | ||
| 654 | void | ||
| 655 | ✗ | MassPeakShaperConfig::setBinSizeFixed(bool is_fixed) | |
| 656 | { | ||
| 657 | ✗ | m_isBinSizeFixed = is_fixed; | |
| 658 | ✗ | } | |
| 659 | |||
| 660 | /* | ||
| 661 | \brief Gets the requirement that the bin size be set and fixed (not modifiable | ||
| 662 | by computations). | ||
| 663 | */ | ||
| 664 | bool | ||
| 665 | ✗ | MassPeakShaperConfig::getBinSizeFixed() | |
| 666 | { | ||
| 667 | ✗ | return m_isBinSizeFixed; | |
| 668 | } | ||
| 669 | |||
| 670 | /*! | ||
| 671 | \brief Sets the bin size computation dividing \a factor. | ||
| 672 | |||
| 673 | When the bin size is computed (m_isBinSizeFixed is false), that value is | ||
| 674 | determined by dividing the FWHM value by this \a factor (m_binSizeDivisor). | ||
| 675 | |||
| 676 | Empirically, a value of 6 for m_binSizeDivisor, yields bin sizes that allow | ||
| 677 | combining correctly multiple peak shapes into a mass spectrum. Essentially, | ||
| 678 | that means that 6 individual m/z bins are required to combine nicely all the | ||
| 679 | peaks shapes obtained for all the peak centroids in a given isotopic cluster, | ||
| 680 | for example. | ||
| 681 | */ | ||
| 682 | void | ||
| 683 | ✗ | MassPeakShaperConfig::setBinSizeDivisor(int factor) | |
| 684 | { | ||
| 685 | ✗ | if(std::abs(factor) < 1) | |
| 686 | ✗ | qFatal("Programming error."); | |
| 687 | |||
| 688 | ✗ | m_binSizeDivisor = std::abs(factor); | |
| 689 | ✗ | } | |
| 690 | |||
| 691 | /*! | ||
| 692 | \brief Returns the bin size computation dividing factor. | ||
| 693 | |||
| 694 | \sa setBinSizeDivisor() | ||
| 695 | */ | ||
| 696 | int | ||
| 697 | ✗ | MassPeakShaperConfig::getBinSizeDivisor() const | |
| 698 | { | ||
| 699 | ✗ | return m_binSizeDivisor; | |
| 700 | } | ||
| 701 | |||
| 702 | /*! | ||
| 703 | \brief Sets the \a point_count to be used to shape the mass peak | ||
| 704 | around the m/z centroid value. | ||
| 705 | |||
| 706 | Typically, a value between 150 and 200 points is fine to nicely shape a m/z | ||
| 707 | peak centroid. | ||
| 708 | */ | ||
| 709 | void | ||
| 710 | ✗ | MassPeakShaperConfig::setPointCount(int point_count) | |
| 711 | { | ||
| 712 | ✗ | m_pointCount = point_count; | |
| 713 | ✗ | } | |
| 714 | |||
| 715 | /*! | ||
| 716 | \brief Gets the count of points to be used to shape the mass peak around the | ||
| 717 | m/z centroid value. | ||
| 718 | */ | ||
| 719 | int | ||
| 720 | ✗ | MassPeakShaperConfig::getPointCount() const | |
| 721 | { | ||
| 722 | ✗ | return m_pointCount; | |
| 723 | } | ||
| 724 | |||
| 725 | /*! | ||
| 726 | \brief Sets the type of mass peak shape to \a mass_peak_shape_type. | ||
| 727 | |||
| 728 | \sa MsXpS::libXpertMass::MassPeakShapeType | ||
| 729 | */ | ||
| 730 | void | ||
| 731 | ✗ | MassPeakShaperConfig::setMassPeakShapeType( | |
| 732 | MassPeakShapeType mass_peak_shape_type) | ||
| 733 | { | ||
| 734 | ✗ | m_massPeakShapeType = mass_peak_shape_type; | |
| 735 | ✗ | } | |
| 736 | |||
| 737 | |||
| 738 | /*! | ||
| 739 | \brief Gets the type of mass peak shape. | ||
| 740 | |||
| 741 | \sa MsXpS::libXpertMass::MassPeakShapeType | ||
| 742 | */ | ||
| 743 | MassPeakShapeType | ||
| 744 | ✗ | MassPeakShaperConfig::getMassPeakShapeType() const | |
| 745 | { | ||
| 746 | ✗ | return m_massPeakShapeType; | |
| 747 | } | ||
| 748 | |||
| 749 | /*! | ||
| 750 | \brief Sets the mass peak width calculation \a logic. | ||
| 751 | |||
| 752 | The full mass peak width at half peak maximum (FWHM) can either be set manually | ||
| 753 | or be computed from a reference m/z value and the instrument's resolving power. | ||
| 754 | |||
| 755 | \sa MsXpS::libXpertMass::MassPeakWidthLogic | ||
| 756 | */ | ||
| 757 | void | ||
| 758 | ✗ | MassPeakShaperConfig::setMassPeakWidthLogic(MassPeakWidthLogic logic) | |
| 759 | { | ||
| 760 | ✗ | m_massPeakWidthLogic = logic; | |
| 761 | ✗ | } | |
| 762 | |||
| 763 | /*! | ||
| 764 | \brief Gets the mass peak width calculation logic. | ||
| 765 | |||
| 766 | \sa MsXpS::libXpertMass::MassPeakWidthLogic | ||
| 767 | */ | ||
| 768 | MassPeakWidthLogic | ||
| 769 | ✗ | MassPeakShaperConfig::getMassPeakWidthLogic() const | |
| 770 | { | ||
| 771 | ✗ | return m_massPeakWidthLogic; | |
| 772 | } | ||
| 773 | |||
| 774 | |||
| 775 | double | ||
| 776 | ✗ | MassPeakShaperConfig::c(bool *ok) | |
| 777 | { | ||
| 778 | // c in the Gaussian curve is related to the fwhm value: | ||
| 779 | |||
| 780 | ✗ | fwhm(ok); | |
| 781 | |||
| 782 | ✗ | if(!*ok) | |
| 783 | { | ||
| 784 | ✗ | return 0; | |
| 785 | } | ||
| 786 | |||
| 787 | ✗ | double c = m_fwhm / (2 * sqrt(2 * log(2))); | |
| 788 | |||
| 789 | // qDebug() << "c:" << c; | ||
| 790 | |||
| 791 | ✗ | *ok = true; | |
| 792 | |||
| 793 | ✗ | return c; | |
| 794 | } | ||
| 795 | |||
| 796 | |||
| 797 | double | ||
| 798 | ✗ | MassPeakShaperConfig::a(bool *ok) | |
| 799 | { | ||
| 800 | // double pi = 3.1415926535897932384626433832795029; | ||
| 801 | |||
| 802 | ✗ | double c_value = c(ok); | |
| 803 | |||
| 804 | ✗ | if(!*ok) | |
| 805 | { | ||
| 806 | ✗ | return 0; | |
| 807 | } | ||
| 808 | |||
| 809 | ✗ | double a = (1 / (c_value * sqrt(2 * M_PI))); | |
| 810 | |||
| 811 | // qDebug() << "a:" << a; | ||
| 812 | |||
| 813 | ✗ | *ok = true; | |
| 814 | |||
| 815 | ✗ | return a; | |
| 816 | } | ||
| 817 | |||
| 818 | |||
| 819 | double | ||
| 820 | ✗ | MassPeakShaperConfig::gamma(bool *ok) | |
| 821 | { | ||
| 822 | ✗ | fwhm(ok); | |
| 823 | |||
| 824 | ✗ | if(!*ok) | |
| 825 | { | ||
| 826 | ✗ | return 0; | |
| 827 | } | ||
| 828 | |||
| 829 | ✗ | double gamma = m_fwhm / 2; | |
| 830 | |||
| 831 | // qDebug() << "gamma:" << gamma; | ||
| 832 | |||
| 833 | ✗ | *ok = true; | |
| 834 | |||
| 835 | ✗ | return gamma; | |
| 836 | } | ||
| 837 | |||
| 838 | /*! | ||
| 839 | \brief Sets the \a mz_step. | ||
| 840 | |||
| 841 | The m/z step value is the distance between two consecutive points in the peak | ||
| 842 | shape. | ||
| 843 | */ | ||
| 844 | void | ||
| 845 | ✗ | MassPeakShaperConfig::setMzStep(double mz_step) | |
| 846 | { | ||
| 847 | ✗ | m_mzStep = mz_step; | |
| 848 | ✗ | } | |
| 849 | |||
| 850 | |||
| 851 | /*! | ||
| 852 | \brief Gets the m/z step. | ||
| 853 | |||
| 854 | The m/z step value is the distance between two consecutive points in the peak | ||
| 855 | shape. | ||
| 856 | */ | ||
| 857 | double | ||
| 858 | ✗ | MassPeakShaperConfig::getMzStep() const | |
| 859 | { | ||
| 860 | ✗ | return m_mzStep; | |
| 861 | } | ||
| 862 | |||
| 863 | /*! | ||
| 864 | \brief Calculates the m/z step. | ||
| 865 | |||
| 866 | |||
| 867 | The m/z step value is the distance between two consecutive points in the peak | ||
| 868 | shape. To compute that value, the full m/z width of the calculated shape (not | ||
| 869 | only the width at half maximum, FWHM) is divided by the total number of data | ||
| 870 | points that make the final shape of the m/z peak. | ||
| 871 | |||
| 872 | The first variable is FWHM_PEAK_SPAN_FACTOR * m_fwhm, and the second | ||
| 873 | variable is m_pointCount. The calculation is thus: | ||
| 874 | |||
| 875 | \code | ||
| 876 | m_mzStep = (FWHM_PEAK_SPAN_FACTOR * m_fwhm) / m_pointCount; | ||
| 877 | \endcode | ||
| 878 | |||
| 879 | The first step is to compute the FWHM and then to check the value of | ||
| 880 | m_pointCount (that cannot be 0). If any of these fails, the function returns 0 | ||
| 881 | and set \a ok to false, otherwise the computed value is set to m_mzStep and | ||
| 882 | returned, while \a ok is set to true. | ||
| 883 | |||
| 884 | \sa FWHM_PEAK_SPAN_FACTOR | ||
| 885 | */ | ||
| 886 | double | ||
| 887 | ✗ | MassPeakShaperConfig::mzStep(bool *ok) | |
| 888 | { | ||
| 889 | // But what is the mz step ? | ||
| 890 | // | ||
| 891 | // We want the shape to be able to go down to baseline. Thus we want that | ||
| 892 | // the shape to have a "basis" (or, better, a "ground") corresponding to | ||
| 893 | // twice the FWHM on the left of the centroid and to twice the FWHM on the | ||
| 894 | // right (that makes in total FWHM_PEAK_SPAN_FACTOR * FWHM, that is, | ||
| 895 | // FWHM_PEAK_SPAN_FACTOR = 4). | ||
| 896 | |||
| 897 | ✗ | fwhm(ok); | |
| 898 | |||
| 899 | ✗ | if(!*ok) | |
| 900 | { | ||
| 901 | ✗ | return 0; | |
| 902 | } | ||
| 903 | |||
| 904 | ✗ | if(!m_pointCount) | |
| 905 | { | ||
| 906 | ✗ | *ok = false; | |
| 907 | ✗ | return 0; | |
| 908 | } | ||
| 909 | |||
| 910 | ✗ | m_mzStep = (FWHM_PEAK_SPAN_FACTOR * m_fwhm) / m_pointCount; | |
| 911 | |||
| 912 | ✗ | return m_mzStep; | |
| 913 | } | ||
| 914 | |||
| 915 | /*! | ||
| 916 | \brief Resets this MassPeakShaperConfig instance to default values like at | ||
| 917 | construction time. | ||
| 918 | */ | ||
| 919 | void | ||
| 920 | ✗ | MassPeakShaperConfig::reset() | |
| 921 | { | ||
| 922 | // Values to start over. | ||
| 923 | |||
| 924 | ✗ | m_resolution = 0; | |
| 925 | ✗ | m_fwhm = 0; | |
| 926 | ✗ | m_referencePeakMz = 0; | |
| 927 | ✗ | m_pointCount = 0; | |
| 928 | ✗ | m_withBins = false; | |
| 929 | ✗ | m_binSizeDivisor = 6; | |
| 930 | ✗ | m_binSize = 0; | |
| 931 | ✗ | m_isBinSizeFixed = false; | |
| 932 | ✗ | m_mzStep = 0; | |
| 933 | ✗ | m_massPeakShapeType = MassPeakShapeType::NOT_SET; | |
| 934 | ✗ | } | |
| 935 | |||
| 936 | /*! | ||
| 937 | \brief Calculates the various parameters of the peak shape using member data. | ||
| 938 | |||
| 939 | This function first checks that all the required data are set. Then this | ||
| 940 | functions computes the FWHM value required to shape the peak centroid. Once the | ||
| 941 | basic data have been computed or set, the parameters of the shape are computed: | ||
| 942 | c, a, gamma. | ||
| 943 | |||
| 944 | Returns true if the computation was successful, false otherwise. | ||
| 945 | */ | ||
| 946 | bool | ||
| 947 | ✗ | MassPeakShaperConfig::resolve() | |
| 948 | { | ||
| 949 | // We need to try to set all the relevant parameters by calculation. | ||
| 950 | |||
| 951 | ✗ | bool ok = false; | |
| 952 | |||
| 953 | // These are the essential parameters: | ||
| 954 | |||
| 955 | ✗ | if(!m_referencePeakMz) | |
| 956 | ✗ | return false; | |
| 957 | |||
| 958 | ✗ | if(!m_fwhm && !m_resolution) | |
| 959 | ✗ | return false; | |
| 960 | |||
| 961 | ✗ | if(!m_pointCount) | |
| 962 | ✗ | return false; | |
| 963 | |||
| 964 | // At this point we should be able to compute the relevant data. | ||
| 965 | |||
| 966 | // The FWHM is the *leading* value for the determination of the peak shape's | ||
| 967 | // width at half maximum. If that FWHM value is 0, then we resort to the | ||
| 968 | // resolution. Both R and FWHM cannot be 0! | ||
| 969 | ✗ | if(m_fwhm) | |
| 970 | { | ||
| 971 | // If we have FWHM, immediately try to compute the resolution as we'll | ||
| 972 | // need it later. FWHM takes precedence over resolution! | ||
| 973 | ✗ | resolution(&ok); | |
| 974 | |||
| 975 | ✗ | if(!ok) | |
| 976 | ✗ | return false; | |
| 977 | } | ||
| 978 | else | ||
| 979 | { | ||
| 980 | // We should be able to compute FWHM by resorting to the resolution. | ||
| 981 | |||
| 982 | ✗ | fwhm(&ok); | |
| 983 | |||
| 984 | ✗ | if(!ok) | |
| 985 | ✗ | return false; | |
| 986 | } | ||
| 987 | |||
| 988 | // Now check if we have and can compute the bins. | ||
| 989 | // But we do this only if the user has not stated that the bin size has to | ||
| 990 | // be set manually. | ||
| 991 | |||
| 992 | // qDebug() << "In the resolve, check the bin size"; | ||
| 993 | |||
| 994 | ✗ | binSize(&ok); | |
| 995 | |||
| 996 | ✗ | if(!ok) | |
| 997 | ✗ | return false; | |
| 998 | |||
| 999 | ✗ | mzStep(&ok); | |
| 1000 | |||
| 1001 | ✗ | if(!ok) | |
| 1002 | ✗ | return false; | |
| 1003 | |||
| 1004 | // Now the other parameters for the shape. | ||
| 1005 | |||
| 1006 | ✗ | c(&ok); | |
| 1007 | |||
| 1008 | ✗ | if(!ok) | |
| 1009 | ✗ | return false; | |
| 1010 | |||
| 1011 | ✗ | a(&ok); | |
| 1012 | |||
| 1013 | ✗ | if(!ok) | |
| 1014 | ✗ | return false; | |
| 1015 | |||
| 1016 | ✗ | gamma(&ok); | |
| 1017 | |||
| 1018 | ✗ | if(!ok) | |
| 1019 | ✗ | return false; | |
| 1020 | |||
| 1021 | ✗ | return true; | |
| 1022 | } | ||
| 1023 | |||
| 1024 | /*! | ||
| 1025 | \brief Returns a string representing this MassPeakShaperConfig instance. | ||
| 1026 | |||
| 1027 | No verification whatsoever is performed. | ||
| 1028 | */ | ||
| 1029 | QString | ||
| 1030 | ✗ | MassPeakShaperConfig::toString() | |
| 1031 | { | ||
| 1032 | ✗ | QString string; | |
| 1033 | |||
| 1034 | ✗ | bool ok = resolve(); | |
| 1035 | |||
| 1036 | ✗ | if(!ok) | |
| 1037 | ✗ | return QString(); | |
| 1038 | |||
| 1039 | ✗ | QString peak_shape_text; | |
| 1040 | ✗ | if(m_massPeakShapeType == MassPeakShapeType::GAUSSIAN) | |
| 1041 | ✗ | peak_shape_text = "Gaussian"; | |
| 1042 | ✗ | if(m_massPeakShapeType == MassPeakShapeType::LORENTZIAN) | |
| 1043 | ✗ | peak_shape_text = "Lorentzian"; | |
| 1044 | |||
| 1045 | ✗ | QString with_bins_text; | |
| 1046 | ✗ | if(m_withBins) | |
| 1047 | with_bins_text += | ||
| 1048 | ✗ | QString("With bins of size: %1 m/z.\n").arg(m_binSize, 0, 'f', 10); | |
| 1049 | else | ||
| 1050 | ✗ | with_bins_text = "Without bins.\n"; | |
| 1051 | |||
| 1052 | ✗ | string = QString( | |
| 1053 | "%1 peak shaping:\n" | ||
| 1054 | "Configuration for reference m/z value: %2\n" | ||
| 1055 | "Resolution: %3\n" | ||
| 1056 | "FWHM: %4\n" | ||
| 1057 | "%5\n" | ||
| 1058 | "Number of points to shape the peak: %6\n" | ||
| 1059 | "c: %7\n" | ||
| 1060 | "c^2: %8\n" | ||
| 1061 | ✗ | "mz step: %9\n\n") | |
| 1062 | ✗ | .arg(peak_shape_text) | |
| 1063 | ✗ | .arg(m_referencePeakMz, 0, 'f', 5) | |
| 1064 | ✗ | .arg(m_resolution) | |
| 1065 | ✗ | .arg(m_fwhm, 0, 'f', 5) | |
| 1066 | ✗ | .arg(with_bins_text) | |
| 1067 | ✗ | .arg(m_pointCount) | |
| 1068 | ✗ | .arg(c(&ok), 0, 'f', 5) | |
| 1069 | ✗ | .arg(c(&ok) * c(&ok), 0, 'f', 5) | |
| 1070 | ✗ | .arg(m_mzStep, 0, 'f', 5); | |
| 1071 | |||
| 1072 | ✗ | return string; | |
| 1073 | ✗ | } | |
| 1074 | |||
| 1075 | } // namespace libXpertMass | ||
| 1076 | |||
| 1077 | } // namespace MsXpS | ||
| 1078 |