GCC Code Coverage Report


./
File: src/XpertMass/IsotopicDataUserConfigHandler.cpp
Date: 2024-08-24 11:26:06
Lines:
53/66
80.3%
Functions:
5/6
83.3%
Branches:
52/100
52.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 /////////////////////// Qt includes
35 #include <QDebug>
36
37
38 /////////////////////// IsoSpec
39 #include <IsoSpec++/isoSpec++.h>
40 #include <IsoSpec++/element_tables.h>
41
42
43 /////////////////////// Local includes
44 #include "globals.hpp"
45 #include "PeakCentroid.hpp"
46 #include "IsotopicDataUserConfigHandler.hpp"
47
48
49 namespace MsXpS
50 {
51
52 namespace libXpertMass
53 {
54
55
56 /*!
57 \class MsXpS::libXpertMass::IsotopicDataUserConfigHandler
58 \inmodule libXpertMass
59 \ingroup PolChemDefBuildingdBlocks
60 \inheaderfile IsotopicDataUserConfigHandler.hpp
61
62 \brief The IsotopicDataUserConfigHandler class handles user-defined
63 \l{IsotopicData}.
64
65 The data can be loaded and written to file. The
66 format of the data is based on the Isotope::toString() implementation that
67 outputs each \l{Isotope}'s data in a separate line.
68
69 Comments are allowed and are on lines that start with the '#' character.
70 These lines are ignored when loading data.
71
72 \sa IsotopicDataLibraryHandler, IsotopicDataManualConfigHandler,
73 Isotope::toString()
74 */
75
76 /*!
77 \brief Constructs the \l{IsotopicDataUserConfigHandler}.
78
79 m_fileName is set to \a file_name
80 */
81 5 IsotopicDataUserConfigHandler::IsotopicDataUserConfigHandler(
82 5 const QString &file_name)
83 5 : IsotopicDataBaseHandler(file_name)
84 {
85 5 }
86
87 /*!
88 \brief Constructs the \l{IsotopicDataUserConfigHandler}.
89
90 The instance will have its isotopic data member pointing to \a
91 isotopic_data_sp.
92
93 m_fileName is set to \a file_name
94 */
95 396 IsotopicDataUserConfigHandler::IsotopicDataUserConfigHandler(
96 396 IsotopicDataSPtr isotopic_data_sp, const QString &file_name)
97
1/2
✓ Branch 2 taken 396 times.
✗ Branch 3 not taken.
396 : IsotopicDataBaseHandler(isotopic_data_sp, file_name)
98 {
99 396 }
100
101 /*!
102 \brief Destructs the \l{IsotopicDataUserConfigHandler}.
103
104 Nothing is explicitely deleted in the destructor.
105 */
106 810 IsotopicDataUserConfigHandler::~IsotopicDataUserConfigHandler()
107 {
108 // qDebug();
109 810 }
110
111 /*!
112 \brief Loads isotopic data from \a file_name.
113
114 The format of the file consists in a single line of data per \l{Isotope} as
115 created using the Isotope::toString() function. Each line is used to create an
116 Isotope with the text-based constructor.
117
118 Returns the count of \l{Isotope}s created or 0 if the file does not exist or
119 is not readable.
120
121 \sa Isotope::Isotope(const QString &text)
122 */
123 std::size_t
124 412 IsotopicDataUserConfigHandler::loadData(const QString &file_name)
125 {
126 // qDebug() << "Loading isotopic data from file:" << file_name;
127
128 // See the Isotope::toString() function that is used to write the isotopic
129 // data to file. We thus expect exactly that format from the file.
130
131
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 412 times.
412 if(file_name.isEmpty())
132 {
133 qDebug("File name is emtpy. Failed to open file for reading.");
134 return 0;
135 }
136
137
1/2
✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
412 QFile file(file_name);
138
139
2/4
✓ Branch 2 taken 412 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 412 times.
412 if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
140 {
141 qDebug("Failed to open file for reading.");
142 return 0;
143 }
144
145 // We may have written comment to the file in the form of #<text> lines
146
2/4
✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 412 times.
✗ Branch 5 not taken.
412 QRegularExpression commentRegexp("^\\s*#.*$");
147
148
1/2
✓ Branch 2 taken 412 times.
✗ Branch 3 not taken.
412 msp_isotopicData->clear();
149
150 412 std::size_t isotope_count = 0;
151
152
1/2
✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
412 QTextStream in(&file);
153
154
3/4
✓ Branch 1 taken 119908 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 119496 times.
✓ Branch 4 taken 412 times.
119908 while(!in.atEnd())
155 {
156
2/4
✓ Branch 1 taken 119496 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 119496 times.
✗ Branch 5 not taken.
119496 QString line = in.readLine().simplified();
157
158 // qDebug() << "simplified line:" << line;
159
160 // Ignore empty or comment lines
161
10/14
✓ Branch 1 taken 119480 times.
✓ Branch 2 taken 16 times.
✓ Branch 4 taken 119480 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 119480 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 824 times.
✓ Branch 10 taken 118656 times.
✓ Branch 11 taken 119480 times.
✓ Branch 12 taken 16 times.
✓ Branch 14 taken 840 times.
✓ Branch 15 taken 118656 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
238976 if(line.length() < 1 || commentRegexp.match(line).hasMatch())
162 840 continue;
163
164
1/2
✓ Branch 1 taken 118656 times.
✗ Branch 2 not taken.
118656 IsotopeSPtr isotope_sp = std::make_shared<Isotope>(line);
165
166 // We do not want to update the mono/avg maps each time we load an
167 // isotope. We'll call the relevant function later.
168
1/2
✓ Branch 3 taken 118656 times.
✗ Branch 4 not taken.
118656 msp_isotopicData->appendNewIsotope(isotope_sp, false);
169
170 118656 ++isotope_count;
171
2/2
✓ Branch 2 taken 118656 times.
✓ Branch 3 taken 840 times.
119496 }
172 // End of
173 // while(!in.atEnd())
174
175 // qDebug() << "Finished creating all the Isotope instances.";
176
177
1/2
✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
412 file.close();
178
179 // At this point, it seems that the loading went fine.
180
181 // Because we have touched the m_isotopes vector, we need to update the
182 // mono/avg masses map.
183
184
2/4
✓ Branch 2 taken 412 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 412 times.
412 if(!msp_isotopicData->updateMassMaps())
185 qFatal("Programming error. Failed to update the mass maps.");
186
187
2/4
✓ Branch 2 taken 412 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 412 times.
412 if(isotope_count != msp_isotopicData->size())
188 qFatal("Programming error. Failed to load all the isotopes to file.");
189
190
1/2
✓ Branch 2 taken 412 times.
✗ Branch 3 not taken.
412 return msp_isotopicData->size();
191 412 }
192
193 /*!
194 \brief Writes isotopic data to \a file_name.
195
196 If \a file_name is empty, m_fileName is tried. If both are empty, the
197 function returns 0. If any one of the file names are correct (file_name takes
198 precedence over m_fileName), then m_fileName is set to that file name.
199
200 The format of the file consists in a single line of data per \l{Isotope} as
201 created using the Isotope::toString() function. Each isotope is output to
202 its own line.
203
204 Returns the count of \l{Isotope}s written to file or 0 if the file does not
205 exist or is not readable.
206
207 \sa Isotope::Isotope(const QString &text)
208 */
209 std::size_t
210 4 IsotopicDataUserConfigHandler::writeData(const QString &file_name)
211 {
212 // Although the isotopic data were loaded from the IsoSpec library tables, we
213 // might be willing to store these data to a file.
214
215
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
4 if(file_name.isEmpty() && m_fileName.isEmpty())
216 return 0;
217
218 4 QString temp_file_name;
219
220 // The passed filename takes precedence over the member datum. So copy
221 // that file name to the member datum.
222
223
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if(!file_name.isEmpty())
224 4 temp_file_name = file_name;
225 else
226 temp_file_name = m_fileName;
227
228
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QFile file(temp_file_name);
229
230
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
231 {
232 qDebug("Failed to open file for writing.");
233 return 0;
234 }
235
236
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QTextStream out(&file);
237
238 out
239
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 << "# This file contains isotopic data in a format that can accommodate\n";
240 out
241
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 << "# comments in the form of lines beginning with the '#' character.\n\n";
242
243 4 std::size_t isotope_count = 0;
244
245
2/2
✓ Branch 7 taken 1152 times.
✓ Branch 8 taken 4 times.
1156 for(auto item : msp_isotopicData->m_isotopes)
246 {
247
2/4
✓ Branch 2 taken 1152 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1152 times.
✗ Branch 6 not taken.
1152 out << item->toString();
248 // We need to add it because toString() does not terminate the line with
249 // a new line character.
250
1/2
✓ Branch 1 taken 1152 times.
✗ Branch 2 not taken.
1152 out << "\n";
251
252 1152 ++isotope_count;
253 1152 }
254
255
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 out.flush();
256
257
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 file.close();
258
259
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if(isotope_count != msp_isotopicData->size())
260 qFatal("Programming error. Failed to write all the isotopes to file.");
261
262 // Now we know that temp_file_name is fine. Store into m_fileName.
263 4 m_fileName = temp_file_name;
264
265 4 return isotope_count;
266 4 }
267
268
269 std::size_t
270 IsotopicDataUserConfigHandler::checkConsistency()
271 {
272 return msp_isotopicData->size();
273 }
274
275
276 } // namespace libXpertMass
277
278 } // namespace MsXpS
279
280
281 #if 0
282
283 Example from IsoSpec.
284
285 const int elementNumber = 2;
286 const int isotopeNumbers[2] = {2,3};
287
288 const int atomCounts[2] = {2,1};
289
290
291 const double hydrogen_masses[2] = {1.00782503207, 2.0141017778};
292 const double oxygen_masses[3] = {15.99491461956, 16.99913170, 17.9991610};
293
294 const double* isotope_masses[2] = {hydrogen_masses, oxygen_masses};
295
296 const double hydrogen_probs[2] = {0.5, 0.5};
297 const double oxygen_probs[3] = {0.5, 0.3, 0.2};
298
299 const double* probs[2] = {hydrogen_probs, oxygen_probs};
300
301 IsoLayeredGenerator iso(Iso(elementNumber, isotopeNumbers, atomCounts,
302 isotope_masses, probs), 0.99);
303
304 #endif
305