libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
mzintegrationparams.cpp
Go to the documentation of this file.
1/* BEGIN software license
2 *
3 * msXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright(C) 2009,...,2018 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/////////////////////// StdLib includes
34#include <cmath>
35#include <map>
36
37/////////////////////// Qt includes
38#include <QDateTime>
39#include <QDebug>
40#include <QFile>
41#include <QString>
42
43/////////////////////// pappsomspp includes
46
47/////////////////////// Local includes
49
50namespace pappso
51{
52
53//! Map relating the BinningType to a textual representation
54std::map<MzIntegrationParams::BinningType, QString> binningTypeMap{
58
60getBinningTypeFromString(const QString &text)
61{
62 std::map<MzIntegrationParams::MzIntegrationParams::BinningType,
63 QString>::const_iterator the_iterator_const =
64 std::find_if(
65 binningTypeMap.begin(),
66 binningTypeMap.end(),
67 [text](const std::pair<MzIntegrationParams::BinningType, QString> &pair) {
68 return pair.second == text;
69 });
70
71 if(the_iterator_const != binningTypeMap.end())
72 return the_iterator_const->first;
73
75}
76
77MzIntegrationParams::MzIntegrationParams(QObject *parent): QObject(parent)
78{
79}
80
81MzIntegrationParams::MzIntegrationParams(const QString &text, QObject *parent)
82 : QObject(parent)
83{
84 initialize(text);
85}
86
88 double min_mz,
89 double max_mz,
91 pappso::PrecisionPtr bin_size_model,
92 int bin_size_divisor,
93 int decimal_places,
94 bool remove_zero_val_data_points,
95 QObject *parent)
96 : QObject(parent),
97 m_smallestMz(min_mz),
98 m_greatestMz(max_mz),
99 m_binningType(binning_type),
100 m_binSizeModel(bin_size_model),
101 m_binSizeDivisor(bin_size_divisor),
102 m_decimalPlaces(decimal_places),
103 m_removeZeroValDataPoints(remove_zero_val_data_points)
104{
105 if(m_binSizeModel == nullptr)
107
108 // qDebug() << "MetaObject?" << this->metaObject()->className();
109}
110
114
116MzIntegrationParams::clone(QObject *parent) const
117{
118 MzIntegrationParams *mz_integration_params_p =
126 parent);
127
128 return mz_integration_params_p;
129}
130
133{
134 // qDebug() << "Initializing MzIntegrationParams using text:" << text;
135
137
138 if(text.isEmpty())
139 return initialization_result;
140
141 reset();
142
143 // Expected text: "Smallest (first) m/z:294.725158\nGreatest (last)
144 // m/z:2055.002453\nDecimal places:-1\nBinning type:2\nBin size model:0.05
145 // dalton\nBin size divisor:1\nRemove 0-val data points:1\n"
146
147 // In order to consider that the parameters were correctly read, we need
148 // some of the members to effectively be set from the settings values.
149
150 bool binning_type_set = false;
151 bool decimal_places_set = false;
152 bool bin_size_model_set = false;
153 bool bin_size_divisor_set = false;
154 bool remove_zero_data_points_set = false;
155
156 QStringList string_list = text.split("\n");
157
158 for(int iter = 0; iter < string_list.size(); ++iter)
159 {
160 QString iter_string = string_list.at(iter);
161
162 // qDebug() << "Iterating in string:" << iter_string;
163
164 if(iter_string.contains("Binning type:"))
165 {
167 getBinningTypeFromString(iter_string.split(':').last()));
168 binning_type_set = true;
169 }
170 else if(iter_string.contains("Bin size model:"))
171 {
173 PrecisionFactory::fromString(iter_string.split(':').last()));
174 bin_size_model_set = true;
175 }
176 else if(iter_string.contains("Bin size divisor:"))
177 {
178 setBinSizeDivisor(iter_string.split(':').last().toInt());
179 bin_size_divisor_set = true;
180 }
181 else if(iter_string.contains("Decimal places:"))
182 {
183 setDecimalPlaces(iter_string.split(':').last().toInt());
184 decimal_places_set = true;
185 }
186 else if(iter_string.contains("Remove 0-val data points:"))
187 {
188 setRemoveZeroValDataPoints(iter_string.split(':').last().toInt());
189 remove_zero_data_points_set = true;
190 }
191 }
192
193 // qDebug() << "At this point the initialization is done and this"
194 // " MzIntegrationParams instance is: "
195 // << toString();
196
197 if(binning_type_set)
198 initialization_result |= InitializationResult::BINNING_TYPE;
199 if(bin_size_model_set)
200 initialization_result |= InitializationResult::BIN_SIZE_MODEL;
201 if(bin_size_divisor_set)
202 initialization_result |= InitializationResult::BIN_SIZE_DIVISOR;
203 if(decimal_places_set)
204 initialization_result |= InitializationResult::DECIMAL_PLACES;
205
206 if(remove_zero_data_points_set)
207 initialization_result |= InitializationResult::REMOVE_ZERO_DATA_POINTS;
208
209 return initialization_result;
210}
211
212void
214 double max_mz,
216 pappso::PrecisionPtr bin_size_model,
217 int bin_size_divisor,
218 int decimal_places,
219 bool remove_zero_val_data_points,
220 QObject *parent)
221{
222 setSmallestMz(min_mz);
223 setGreatestMz(max_mz);
224 setBinningType(binning_type);
225 setBinSizeModel(bin_size_model);
226 setBinSizeDivisor(bin_size_divisor);
227 setDecimalPlaces(decimal_places);
228 setRemoveZeroValDataPoints(remove_zero_val_data_points);
229
230 setParent(parent);
231}
232
233void
247
248void
250 QObject *parent)
251{
252 Q_ASSERT(other_p != nullptr);
253 initialize(*other_p, parent);
254}
255
256// Initialize this MzIntegrationParams using other but only for members that
257// were effectively set upon reading from a text string (see initialize
258// (QString)).
259void
261 InitializationResult initialization_results)
262{
263 if(static_cast<bool>(
264 initialization_results &
267
268 if(static_cast<bool>(
269 initialization_results &
272
273 if(static_cast<bool>(
274 initialization_results &
277
278 if(static_cast<bool>(
279 initialization_results &
282}
283
284void
286{
287 if(m_smallestMz != value)
288 m_smallestMz = value;
289
290 emit smallestMzChanged();
291}
292
293void
295{
296 if(value == m_smallestMz)
297 return;
298
299 m_smallestMz = value;
300 emit smallestMzChanged();
301}
302
303double
308
309void
311{
312 if(m_greatestMz == value)
313 return;
314
315 m_greatestMz = value;
316 emit greatestMzChanged();
317}
318
319void
321{
322 if(value > m_greatestMz)
323 {
324 m_greatestMz = value;
325 emit greatestMzChanged();
326 }
327}
328
329double
334
335void
336MzIntegrationParams::setMzValues(double smallest, double greatest)
337{
338 setSmallestMz(smallest);
339 setGreatestMz(greatest);
340}
341
342void
345{
346 if(m_binningType == binning_type)
347 return;
348
349 m_binningType = binning_type;
350 emit binningTypeChanged();
351}
352
358
359
360int
365
366void
368{
369 if(m_binSizeModel == bin_size_model_p)
370 return;
371
372 m_binSizeModel = bin_size_model_p;
373
374 if(m_binSizeModel == nullptr)
376
377 emit binSizeModelChanged();
378}
379
385
386void
388{
389 if(m_binSizeDivisor == divisor)
390 return;
391
392 m_binSizeDivisor = divisor;
394}
395
396int
401
402void
408
409double
414
415void
417{
418 if(m_decimalPlaces == decimal_places)
419 return;
420
421 m_decimalPlaces = decimal_places;
423}
424
425void
427{
428 if(m_removeZeroValDataPoints == removeOrNot)
429 return;
430
431 m_removeZeroValDataPoints = removeOrNot;
433}
434
435bool
440
441//! Reset the instance to default values.
442void
444{
445 // Each function handles the emission of the corresponding changed
446 // notification.
447 setSmallestMz(std::numeric_limits<double>::max());
448 setGreatestMz(std::numeric_limits<double>::min());
454}
455
456bool
458{
459 int errors = 0;
460
462 {
463 // qDebug() << "m_smallestMz:" << m_smallestMz;
464 // qDebug() << "smallest is max:" << (m_smallestMz ==
465 // std::numeric_limits<double>::max());
466 errors += (m_smallestMz == std::numeric_limits<double>::max() ? 1 : 0);
467
468 // qDebug() << "m_greatestMz:" << m_greatestMz;
469 // qDebug() << "greatest is min:" << (m_greatestMz ==
470 // std::numeric_limits<double>::min());
471 errors += (m_greatestMz == std::numeric_limits<double>::min() ? 1 : 0);
472 }
473
474 if(errors)
475 {
476 qCritical() << "The m/z integration parameters are invalid.";
477 }
478
479 return !errors;
480}
481
482bool
484{
485 return (m_smallestMz < std::numeric_limits<double>::max()) &&
486 (m_greatestMz >= std::numeric_limits<double>::min());
487}
488
489std::vector<double>
491{
492 // qDebug() << "mp_precision:" << mp_precision->toString();
493
494 std::vector<double> bins;
495
497 {
498 // If no binning is to be performed, fine.
499 return bins;
500 }
502 {
503 // Use only data in the MzIntegrationParams member data.
504 return createArbitraryBins();
505 }
507 {
508 qFatal() << "Programming error. "
509 "Please use the createBins(pappso::MassSpectrumCstSPtr "
510 "mass_spectrum_csp) overload.";
511 }
512
513 return bins;
514}
515
516std::vector<double>
518{
519 // qDebug();
520
521 std::vector<double> bins;
522
524 {
525 // If no binning is to be performed, fine.
526 return bins;
527 }
529 {
530 // Use only data in the MzIntegrationParams member data.
531 return createArbitraryBins();
532 }
534 {
535 // qDebug();
536
537 // Use the first spectrum to perform the data-based bins
538
539 return createDataBasedBins(mass_spectrum_csp);
540 }
541
542 return bins;
543}
544
545std::vector<double>
547{
548 // Now starts the tricky stuff. Depending on the binning size model, we need
549 // to take diverse actions.
550
551 if(!isValid())
552 qFatal() << "Programming error. The MzIntegrationParams::BinningLogic is "
553 "not valid, cannot create bins.";
554
555 // qDebug() << "Binning logic:" << toString();
556
557 qDebug() << qSetRealNumberPrecision(6) << "The smallest and greatest m/z values:" << m_smallestMz
558 << "-" << m_greatestMz;
559
560 // Compute the number of decimals required to faithfully account for the
561 // precision needed to represent the binned data. We do this by computing
562 // some sort of bin size and checking how many decimals we need to described it.
563
564 // We cannot have a smallest m/z that is 0 because that impairs the computation of the
565 // bins (see below). In case the m_smallestMz value is 0 we craft one temporary value
566 // by computing half of the range:
567
568 // In certain circumstances, the bin size is not enough to properly render
569 // hyper-high resolution data (like the theoretical isotopic cluster data
570 // generated in silico). In that case, the bin size, computed using the
571 // precision object, is divided by the m_binSizeDivisor, which normally is
572 // set to 6 as the default because that is the empirical observation that
573 // it gives the most nicely shaped peaks.
574 Q_ASSERT(m_binSizeDivisor >= 1);
575
576
577 // Instantiate the vector of mz double_s that we'll feed with the bins.
578 std::vector<double> bins;
579
580 double bin_size;
581
582 if(!m_smallestMz)
583 {
585 {
586 // The caller has intelligently set an indicative bin size. Use it.
587 bin_size = m_indicativeBinSize;
588 qDebug() << qSetRealNumberPrecision(6)
589 << "The indicative bin size is being used:" << bin_size;
590 }
591 else
592 {
593 double half_way_mz = 0;
594 half_way_mz = (m_greatestMz - m_smallestMz) / 2;
595
596 qDebug() << " Target min_mz:" << m_smallestMz << "and max_mz:" << m_greatestMz
597 << "half_way_mz:" << half_way_mz;
598 bin_size = m_binSizeModel->delta(half_way_mz) / m_binSizeDivisor;
599 qDebug() << qSetRealNumberPrecision(6)
600 << "The m/z range half way strategy is being used for bin size:" << bin_size;
601 }
602 }
603 else
604 {
605 bin_size = m_binSizeModel->delta(m_smallestMz) / m_binSizeDivisor;
606 qDebug() << qSetRealNumberPrecision(6) << "The normally computed bin size:" << bin_size;
607 }
608
609 qDebug() << qSetRealNumberPrecision(6) << "The bin size was computed to be" << bin_size;
610
611 // Only compute the decimal places if they were not configured already.
612 if(m_decimalPlaces == -1)
613 {
614 // qDebug() << "Now checking how many decimal places are needed.";
615
616 // We want as many decimal places as there are 0s between the integral
617 // part of the double and the first non-0 cipher. For example, if
618 // binSize is 0.004, zero decimals is 2 and m_decimalPlaces is set to 3,
619 // because we want decimals up to 4 included.
620
622
623 qDebug() << "With binSize" << bin_size
624 << " m_decimalPlaces was computed to be:" << m_decimalPlaces;
625 }
626
627 qDebug() << "m_decimalPlaces: " << m_decimalPlaces;
628
629 // Now that we have defined the value of m_decimalPlaces, let's use that
630 // value.
631 double first_mz =
633 double last_mz =
635
636 qDebug() << qSetRealNumberPrecision(10)
637 << "After having accounted for the decimals, new min/max values:"
638 << "Very first data point to start from:" << first_mz
639 << "Very last data point to reach: " << last_mz;
640
641 double previous_mz_bin;
642 double current_mz;
643
644 // Store that very first value for later use in the loop.
645 // The bins are nothing more than:
646 //
647 // 1. The first mz (that is the smallest mz value)
648 // 2. A sequence of mz values corresponding to that first mz value
649 // incremented by the bin size calculated each time using the precision
650 // facility (res, ppm, dalton logic).
651
652 bins.push_back(first_mz);
653
654 // The previous_mz_bin cannot be 0, otherwise the m_binSizeModel->delta() will
655 // return 0 and we won't be able to create bins.
656
657 if(!first_mz)
658 {
659 bins.push_back(bin_size);
660 previous_mz_bin = bin_size;
661 }
662 else
663 {
664 previous_mz_bin = first_mz;
665 }
666
667 // qDebug() << qSetRealNumberPrecision(6) << "Pushed back first rounded mz:" << previous_mz_bin;
668
669 // Now continue adding mz values until we have reached the end of the
670 // spectrum, that is the max_mz value, as converted using the decimals to
671 // last_mz.
672
673 // debugCount value used below for debugging purposes.
674 // int debugCount = 0;
675
676 while(previous_mz_bin <= last_mz)
677 {
678 // The size of bin is calculated dynamically using the
679 // precision object that computes it with its specifications:
680 // res or ppm or dalton.
681 current_mz = previous_mz_bin + m_binSizeModel->delta(previous_mz_bin) / m_binSizeDivisor;
682
683 // qDebug() << qSetRealNumberPrecision(6) << "previous mz bin: " << previous_mz_bin
684 // << "and current mz: " << current_mz;
685
686 // Now apply on the obtained mz value the decimals that were either set
687 // or computed earlier.
688
689 double current_rounded_mz = Utils::roundValueToDecimalPlaces(current_mz,
691 /*round_up*/ true);
692
693 // qDebug() << qSetRealNumberPrecision(50)
694 // << "after rounding, current mz becomes: " << current_rounded_mz;
695
696 // If rounding makes the new value identical to the previous one, then
697 // that means that we need to decrease roughness.
698
699 if(current_rounded_mz == previous_mz_bin)
700 {
702
703 qDebug() << "It was required to increment decimal places to" << m_decimalPlaces;
704 current_rounded_mz = Utils::roundValueToDecimalPlaces(current_mz,
706 /*round_up*/ true);
707
708 qDebug().noquote() << "Because current rounded mz is equal to previous mz bin, we had to "
709 "increment decimal places by one while creating the bins "
710 "in MzIntegrationParams::BinningType::ARBITRARY mode.";
711 }
712
713 bins.push_back(current_rounded_mz);
714
715 // qDebug() << qSetRealNumberPrecision(50)
716 // << "Pushed back current rounded mz:" << current_rounded_mz;
717
718
719 // Use the local_mz value for the storage of the previous mz bin.
720 previous_mz_bin = current_rounded_mz;
721 }
722
723 // #if 0
724
725 QString bins_with_delta = binsToStringWithDeltas(bins);
726
727 QString file_name = "/tmp/massSpecArbitraryBins.txt-at-" +
728 QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss");
729
730 qDebug() << "Writing the list of bins setup in the mass spectrum in file " << file_name;
731
732 Q_ASSERT(Utils::writeToFile(bins_with_delta, file_name));
733
734 // #endif
735
736 qDebug() << "Prepared " << bins.size() << "arbitrary bins starting with mz" << bins.front()
737 << "ending with mz" << bins.back();
738
739 return bins;
740}
741
742std::vector<double>
744 pappso::MassSpectrumCstSPtr mass_spectrum_csp)
745{
746 // The mass spectrum passed as parameters has intrinsic bins in it. These bins
747 // are nothing else than the succession of m/z values in it.
748
749 // The very first thing to do is replicate that spectrum into a local copy
750 // of bins (simple double values), and during that step recompute the m/z
751 // value (x value) according to the decimals settings in this instance, if
752 // that is required (that is m_decimalPlaces != -1).
753
754 QList<double> bins;
755 QList<double> deltas;
756 QList<double> resolutions;
757
758 double left_mz_value = 0;
759 double right_mz_value = 0;
760 double mz_delta = 0;
761 double resolution = 0;
762
763 // We need three bins to compute a number of values.
764 if(mass_spectrum_csp->size() < 3)
765 {
766 std::vector<double> bins_vector(bins.constBegin(), bins.constEnd());
767 return bins_vector;
768 }
769
770 // Make sure the spectrum is sorted, as this function takes for granted
771 // that the DataPoint instances are sorted in ascending x (== mz) value
772 // order.
773 pappso::MassSpectrum mass_spectrum_copy = *mass_spectrum_csp;
774 mass_spectrum_copy.sortMz();
775
776 std::vector<pappso::DataPoint>::const_iterator iterator_const =
777 mass_spectrum_copy.cbegin();
778
779 // We need to see the first value
780 left_mz_value = iterator_const->x;
781
782 if(m_decimalPlaces != -1)
783 left_mz_value =
784 Utils::roundValueToDecimalPlaces(left_mz_value, m_decimalPlaces, /*round_up*/ true);
785
786 qDebug() << qSetRealNumberPrecision(6)
787 << "left_mz_value in the template mass spectrum:" << left_mz_value;
788
789 bins.append(left_mz_value);
790 // No delta nor resolution can be computed for the first m/z
791 // because their computation requires to compare the second m/z with
792 // the first m/z, and in turn for all the remaining m/z values.
793 deltas.append(0.0);
794 resolutions.append(0.0);
795
796 // We used the first bin, go to the next!
797 ++iterator_const;
798 while(iterator_const != mass_spectrum_copy.cend())
799 {
800 right_mz_value = iterator_const->x;
801
802 qDebug() << qSetRealNumberPrecision(6)
803 << "right_mz_value:" << right_mz_value;
804
805 if(m_decimalPlaces != -1)
806 right_mz_value =
807 Utils::roundValueToDecimalPlaces(right_mz_value, m_decimalPlaces, /*round_up*/ true);
808
809 bins.append(right_mz_value);
810
811 mz_delta = right_mz_value - left_mz_value;
812 deltas.append(mz_delta);
813 Q_ASSERT(mz_delta != 0.0);
814
815 resolution = right_mz_value / mz_delta;
816 resolutions.append(resolution);
817
818 left_mz_value = right_mz_value;
819 ++iterator_const;
820 }
821
822 // At this point we have the bins that match those in the template mass
823 // spectrum.
824
825 // #if 0
826
827 // We want to check them.
828 std::vector<double> bins_vector(bins.constBegin(), bins.constEnd());
829
830 QString bins_with_delta = binsToStringWithDeltas(bins_vector);
831
832 QString file_name =
833 "/tmp/massSpecDataBasedTemplateBinsWithDeltas.txt-at-" +
834 QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss");
835
836 // qDebug() << "Writing the list of bins setup in the mass spectrum in file "
837 // << file_name;
838
839 Q_ASSERT(Utils::writeToFile(bins_with_delta, file_name));
840
841 // #endif
842
843 // Done, we now have bins and deltas in between each bin and its following
844 // bin.
845
846 // Now, there are specificities:
847 //
848 // If the user has set m_smallestMz and/or m_greatestMz, then we
849 // still have to work to do. That is because the user wants us to keep
850 // the binning as found in the template mass spectrum passed as parameter, but
851 // they also want that the m/z range of the bins be potentially larger, if
852 // either m_smallestMz is smaller than the first bin value or if
853 // m_greatestMz is larger than the last bin value, or BOTH.
854
855 // The difficulty here is that we need to know the logic that has been used
856 // in the first place for the generation of the bins in the template mass
857 // spectrum.
858
859 // Some metrics:
860
861 // We could check if the bins have the same width all along the m/z range.
862
863 // Delta should be constant if the bins were calculated with dalton logic.
864
865 bool uniform_deltas = false;
866 std::size_t deltas_count = deltas.size();
867 // We cannot really take the first delta because it is 0.00000.
868 double first_delta = deltas.at(1);
869 double middle_delta = deltas.at(deltas_count / 2);
870 double last_delta = deltas.at(deltas_count - 1);
871
872 if(first_delta == middle_delta && middle_delta == last_delta)
873 uniform_deltas = true;
874
875 // qDebug() << "Deltas are uniform or not?" << uniform_deltas;
876 // qDebug() << qSetRealNumberPrecision(6) << "First delta:" << first_delta
877 // << "Middle delta:" << middle_delta << "Last delta:" << last_delta;
878
879 // Resolution should be constant if the bins were calculated with resolution
880 // logic. Remember : Res = m/z / Delta m/z.
881 bool uniform_resolutions = false;
882 std::size_t resolutions_count = resolutions.size();
883 // We cannot really take the first resolution because it is 0.00000.
884 double first_resolution = resolutions.at(01);
885 double middle_resolution = resolutions.at(resolutions_count / 2);
886 double last_resolution = resolutions.at(resolutions_count - 1);
887
888 if(first_resolution == middle_resolution &&
889 middle_resolution == last_resolution)
890 uniform_resolutions = true;
891
892 // qDebug() << "Deltas are uniform or not?" << uniform_resolutions;
893 // qDebug() << qSetRealNumberPrecision(6) << "First resolution:" <<
894 // first_resolution
895 // << "Middle resolution:" << middle_resolution << "Last resolution:"
896 // << last_resolution;
897
898 // Now that we have the metric about the bins, we can start checking the other
899 // parameters of the creation of bins:
900 // m_smallestMz vs m_greatestMz
901
902 // In theory, m_smallestMz and m_greatestMz were designed for the arbitrary
903 // binning method, but it is imaginable that one would want to combine to an
904 // existing spectrum a new spectrum that is larger than the existing
905 // one, either on the left or on the right.
906
907 double first_bin_mz = bins.first();
908 double last_bin_mz = bins.last();
909
910 // qDebug() << qSetRealNumberPrecision(6) << "smallest_mz:" << m_smallestMz
911 // << "greatest_mz:" << m_greatestMz;
912
913 // Now we can check if the [m_smallestMz -- m_greatestMz] m/z value range
914 // extends farther on the left or on the right or both compared to the bins
915 // range.
916
917 // Now that we have the real smallest and greatest m/z values that might be
918 // std::max() and std::min() respectively if not set by the user. So all we
919 // have to do is check them against the first and last bin values.
920
921 // The list of prepended bins on the left of the existing bins. By starting
922 // with first_bin_mz, we maintain the phase with the bins in the mass spectrum
923 // passed as parameter.
924
925 if(m_smallestMz < first_bin_mz)
926 {
927 // qDebug() << "A starting m/z value is smaller than the first bin in the
928 // "
929 // "spectrum";
930
931 // We will have to craft bins to the left of first_bin_mz up to
932 // smallest_mz. There are going to be different strategies depending on
933 // what we discovered above. We will prepend the newly created bins to the
934 // bins QList (thanks QList).
935
936 double bin_mz = first_bin_mz;
937
938 if(uniform_deltas)
939 {
940 // That is the simplest situation.
941
942 while(bin_mz > m_smallestMz)
943 {
944 double new_bin_mz = bin_mz - first_delta;
945 bins.prepend(new_bin_mz);
946 bin_mz = new_bin_mz;
947 }
948 }
949 else if(uniform_resolutions)
950 {
951 // Remember: Res = m/z / Delta m/z.
952
953 while(bin_mz > m_smallestMz)
954 {
955 double new_bin_mz = bin_mz - (bin_mz / first_resolution);
956 bins.prepend(new_bin_mz);
957 bin_mz = new_bin_mz;
958 }
959 }
960 }
961
962 // Now make sure we append any necessary bin (same logic as above).
963 // By starting with last_bin_mz, we maintain the phase with the bins in the
964 // mass spectrum passed as parameter.
965
966 if(m_greatestMz > last_bin_mz)
967 {
968 // qDebug() << "A stopping m/z value is greater than the last bin in the "
969 // "spectrum";
970
971 // Craft bins to the right of the bins m/z range, that is append
972 // new bins.
973
974 double bin_mz = last_bin_mz;
975
976 if(uniform_deltas)
977 {
978 // That is the simplest situation.
979
980 while(bin_mz < m_greatestMz)
981 {
982 double new_bin_mz = bin_mz + first_delta;
983 bins.append(new_bin_mz);
984 bin_mz = new_bin_mz;
985 }
986 }
987 else if(uniform_resolutions)
988 {
989 // Remember: Res = m/z / Delta m/z.
990
991 while(bin_mz > m_greatestMz)
992 {
993 double new_bin_mz = bin_mz + (bin_mz / first_resolution);
994 bins.append(new_bin_mz);
995 bin_mz = new_bin_mz;
996 }
997 }
998 }
999
1000 // At this point we should have bins over the full range of m/z values
1001 // required by the user and in phase with those transmitted via the
1002 // mass spectrum argument.
1003
1004 // Convert to std::vector<double> and return.
1005 std::vector<double> full_bins_vector(bins.constBegin(), bins.constEnd());
1006
1007#if 0
1008
1009 bins_with_delta = binsToStringWithDeltas(full_bins_vector);
1010
1011 file_name = "/tmp/massSpecDataBasedFullBinsWithDeltas.txt-at-" +
1012 QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss");
1013
1014 qDebug() << "Writing the list of bins setup in the mass spectrum in file "
1015 << file_name;
1016
1017 Q_ASSERT(Utils::writeToFile(bins_with_delta, file_name));
1018
1019#endif
1020
1021 // qDebug() << "Prepared " << bins.size() << "data-based bins starting with
1022 // mz"
1023 // << bins.front() << "ending with mz" << bins.back();
1024
1025 return full_bins_vector;
1026}
1027
1028std::vector<double>
1030 pappso::MassSpectrumCstSPtr mass_spectrum_csp)
1031{
1032 // The bins must be calculated using those in mass_spectrum_csp as a template.
1033
1034 // qDebug();
1035
1036 std::vector<double> bins;
1037
1038 if(mass_spectrum_csp->size() < 2)
1039 return bins;
1040
1041 // Make sure the spectrum is sorted, as this function takes for granted
1042 // that the DataPoint instances are sorted in ascending x (== mz) value
1043 // order.
1044 pappso::MassSpectrum sorted_mass_spectrum = *mass_spectrum_csp;
1045 sorted_mass_spectrum.sortMz();
1046
1047 double min_mz = m_smallestMz;
1048
1049 // qDebug() << "The min_mz:" << min_mz;
1050
1051 if(m_decimalPlaces != -1)
1052 min_mz = ceil((min_mz * pow(10, m_decimalPlaces)) - 0.49) /
1053 pow(10, m_decimalPlaces);
1054
1055 // Two values for the definition of a MassSpectrumBin.
1056
1057 // The first value of the mz range that defines the bin. This value is part
1058 // of the bin.
1059 double start_mz_in = min_mz;
1060
1061 // The second value of the mz range that defines the bin. This value is
1062 // *not* part of the bin.
1063 double end_mz_out;
1064
1065 std::vector<pappso::DataPoint>::const_iterator it =
1066 sorted_mass_spectrum.begin();
1067
1068 double prev_mz = it->x;
1069
1070 if(m_decimalPlaces != -1)
1071 prev_mz = ceil((prev_mz * pow(10, m_decimalPlaces)) - 0.49) /
1072 pow(10, m_decimalPlaces);
1073
1074 ++it;
1075
1076 while(it != sorted_mass_spectrum.end())
1077 {
1078 double next_mz = it->x;
1079
1080 if(m_decimalPlaces != -1)
1081 next_mz = ceil((next_mz * pow(10, m_decimalPlaces)) - 0.49) /
1082 pow(10, m_decimalPlaces);
1083
1084 double step = next_mz - prev_mz;
1085 end_mz_out = start_mz_in + step;
1086
1087 if(m_decimalPlaces != -1)
1088 end_mz_out = ceil((end_mz_out * pow(10, m_decimalPlaces)) - 0.49) /
1089 pow(10, m_decimalPlaces);
1090
1091 // The data point that is crafted has a 0 y-value. The binning must
1092 // indeed not create artificial intensity data.
1093
1094 // qDebug() << "Pushing back bin:" << start_mz_in << end_mz_out;
1095
1096 bins.push_back(start_mz_in);
1097
1098 // Prepare next bin
1099 start_mz_in = end_mz_out;
1100
1101 // Update prev_mz to be the current one for next iteration.
1102 prev_mz = next_mz;
1103
1104 // Now go to the next DataPoint instance.
1105 ++it;
1106 }
1107
1108#if 0
1109
1110 QString fileName = "/tmp/massSpecDataBasedBins.txt";
1111
1112 qDebug() << "Writing the list of bins setup in the "
1113 "mass spectrum in file "
1114 << fileName;
1115
1116 QFile file(fileName);
1117 file.open(QIODevice::WriteOnly);
1118
1119 QTextStream fileStream(&file);
1120
1121 for(auto &&bin : m_bins)
1122 fileStream << QString("[%1-%2]\n")
1123 .arg(bin.startMzIn, 0, 'f', 10)
1124 .arg(bin.endMzOut, 0, 'f', 10);
1125
1126 fileStream.flush();
1127 file.close();
1128
1129 qDebug() << "elements."
1130 << "starting with mz" << m_bins.front().startMzIn << "ending with mz"
1131 << m_bins.back().endMzOut;
1132
1133#endif
1134
1135 return bins;
1136}
1137
1138// This is for documentation, not for outputting the string used in the
1139// settings that are saved on disk.
1140QString
1141MzIntegrationParams::toString(int offset, const QString &spacer) const
1142{
1143 // The space-containing string that reflects the offset at which
1144 // new text lines should be added to start with.
1145 QString offset_lead;
1146
1147 for(int iter = 0; iter < offset; ++iter)
1148 offset_lead += spacer;
1149
1150 QString text = offset_lead;
1151 text += "m/z integration parameters:\n";
1152
1153 QString new_lead = QString("%1%2").arg(offset_lead, spacer);
1154
1155 text += new_lead;
1156 if(m_smallestMz != std::numeric_limits<double>::max())
1157 text.append(
1158 QString::asprintf("Smallest (first) m/z: %.6f\n", m_smallestMz));
1159
1160 text += new_lead;
1161 if(m_greatestMz != std::numeric_limits<double>::min())
1162 text.append(QString::asprintf("Greatest (last) m/z: %.6f\n", m_greatestMz));
1163
1164 text += new_lead;
1165 text += QString("Remove 0-val data points: %1\n")
1166 .arg(m_removeZeroValDataPoints ? "true" : "false");
1167
1168 text += new_lead;
1169 text.append("Binning logic:\n");
1170
1171 new_lead += spacer;
1172
1173 text += new_lead;
1174 text.append(
1175 QString("Binning type:%1\n").arg(::pappso::binningTypeMap[m_binningType]));
1176
1177 text += new_lead;
1178 text.append(QString("Bin size model: %1\n").arg(m_binSizeModel->toString()));
1179
1180 text += new_lead;
1181 text.append(QString("Bin size divisor: %2\n").arg(m_binSizeDivisor));
1182
1183 text += new_lead;
1184 text.append(QString("Decimal places: %1\n").arg(m_decimalPlaces));
1185
1186 return text;
1187}
1188
1189// This version is used to craft the string that enables the initialization.
1190QString
1192{
1193 QString text;
1194
1195 // In the string for saving settings, we do not ouput the m/z values.
1196 text.append(
1197 QString("Binning type:%1\n").arg(::pappso::binningTypeMap[m_binningType]));
1198 text.append(QString("Bin size model: %1\n").arg(m_binSizeModel->toString()));
1199 text.append(QString("Bin size divisor: %2\n").arg(m_binSizeDivisor));
1200 text.append(QString("Decimal places:%1\n").arg(m_decimalPlaces));
1201 text.append(
1202 QString("Remove 0-val data points:%1\n").arg(m_removeZeroValDataPoints));
1203
1204 // qDebug().noquote() << "Returning text:\n" << text;
1205
1206 return text;
1207}
1208
1209QString
1211 const std::vector<double> bins) const
1212{
1213 QString bins_with_delta;
1214 double previous_bin_value = 0;
1215
1216 for(auto &&value : bins)
1217 {
1218 double delta = value - previous_bin_value;
1219 bins_with_delta += QString("%1 - %2\n")
1220 .arg(value, 0, 'f', m_decimalPlaces)
1221 .arg(delta, 0, 'f', m_decimalPlaces);
1222 previous_bin_value = value;
1223 }
1224
1225 return bins_with_delta;
1226}
1227
1228
1229} // namespace pappso
Class to represent a mass spectrum.
void sortMz()
Sort the DataPoint instances of this spectrum.
The MzIntegrationParams class provides the parameters definining how m/z integrations must be perform...
MzIntegrationParams(QObject *parent=nullptr)
InitializationResult initialize(const QString &text)
std::vector< double > createDataBasedBinsOld(pappso::MassSpectrumCstSPtr massSpectrum)
void setBinSizeModel(pappso::PrecisionPtr bin_size_model_p)
std::vector< double > createArbitraryBins()
QString binsToStringWithDeltas(const std::vector< double > bins) const
pappso::PrecisionPtr m_binSizeModel
pappso::PrecisionPtr getBinSizeModel() const
@ DATA_BASED
binning based on mass spectral data
@ ARBITRARY
binning based on arbitrary bin size value
MzIntegrationParams * clone(QObject *parent=nullptr) const
void setMzValues(double smallest, double greatest)
void setBinningType(BinningType binningType)
void reset()
Reset the instance to default values.
std::vector< double > createDataBasedBins(pappso::MassSpectrumCstSPtr massSpectrum)
void setDecimalPlaces(int decimal_places)
std::vector< double > createBins()
void setRemoveZeroValDataPoints(bool removeOrNot=true)
static PrecisionPtr getResInstance(pappso_double value)
get a resolution precision pointer
static PrecisionPtr fromString(const QString &str)
get a precision pointer from a string
Definition precision.cpp:80
static PrecisionPtr getPpmInstance(pappso_double value)
get a ppm precision pointer
static double roundValueToDecimalPlaces(double value, int decimal_places, bool round_up=true)
Definition utils.cpp:371
static bool writeToFile(const QString &text, const QString &file_name)
Definition utils.cpp:216
static int zeroDecimalsInValue(pappso_double value)
Determine the number of zero decimals between the decimal point and the first non-zero decimal.
Definition utils.cpp:102
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
MzIntegrationParams::BinningType getBinningTypeFromString(const QString &text)
std::map< MzIntegrationParams::BinningType, QString > binningTypeMap
Map relating the BinningType to a textual representation.
std::shared_ptr< const MassSpectrum > MassSpectrumCstSPtr
const PrecisionBase * PrecisionPtr
Definition precision.h:122