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 |
|
|
/////////////////////// Std lib includes |
35 |
|
|
#include <set> |
36 |
|
|
#include <cassert> |
37 |
|
|
|
38 |
|
|
|
39 |
|
|
/////////////////////// Qt includes |
40 |
|
|
#include <QDebug> |
41 |
|
|
#include <QFile> |
42 |
|
|
#include <QIODevice> |
43 |
|
|
|
44 |
|
|
|
45 |
|
|
/////////////////////// IsoSpec |
46 |
|
|
#include <IsoSpec++/isoSpec++.h> |
47 |
|
|
#include <IsoSpec++/element_tables.h> |
48 |
|
|
|
49 |
|
|
|
50 |
|
|
/////////////////////// Local includes |
51 |
|
|
#include "IsotopicDataManualConfigHandler.hpp" |
52 |
|
|
|
53 |
|
|
|
54 |
|
|
namespace MsXpS |
55 |
|
|
{ |
56 |
|
|
|
57 |
|
|
namespace libXpertMass |
58 |
|
|
{ |
59 |
|
|
|
60 |
|
|
|
61 |
|
|
/*! |
62 |
|
|
\class MsXpS::libXpertMass::IsotopicDataManualConfigHandler |
63 |
|
|
\inmodule libXpertMass |
64 |
|
|
\ingroup PolChemDefBuildingdBlocks |
65 |
|
|
\inheaderfile IsotopicDataManualConfigHandler.hpp |
66 |
|
|
|
67 |
|
|
\brief The IsotopicDataManualConfigHandler class handles a peculiar kind of |
68 |
|
|
\l{IsotopicData} that cannot be handled with the other handlers. |
69 |
|
|
|
70 |
|
|
This kind of IsotopicData handler is typically used when definition of brand |
71 |
|
|
new chemical element isotopes are to be performed. For example, if one works |
72 |
|
|
with radioactive carbon C14, then that isotope is not available in the |
73 |
|
|
IsoSpec's library and cannot be inserted in these data using the |
74 |
|
|
\l{IsotopicDataUserConfigHandler}. |
75 |
|
|
|
76 |
|
|
One interesting feature of this kind of IsotopicData formalism is that these |
77 |
|
|
data collectively describe a chemical elemental composition formula, |
78 |
|
|
like, for glucose: C6H12O6. Each chemical element is decribed using isotopes |
79 |
|
|
with mass/abundance pairs. There is thus virtually no limitation on the |
80 |
|
|
complexity of the isotopic distribution to be defined. The format of these data |
81 |
|
|
stored on file is nothing like the format used to store Library- or |
82 |
|
|
User-Config- isotopic data (\l{IsotopicDataLibraryHandler}, |
83 |
|
|
\l{IsotopicDataUserConfigHandler}). |
84 |
|
|
|
85 |
|
|
In the example below we are defining the isotopic composition of |
86 |
|
|
radiolabelled glucose (C6H12O6) where only two of the the six C atoms are 14[C] |
87 |
|
|
atoms with a radiolabelling efficiency of 95%: |
88 |
|
|
|
89 |
|
|
\code |
90 |
|
|
[Element] |
91 |
|
|
symbol C count 4 |
92 |
|
|
# The four atoms that are not labelled appear with natural |
93 |
|
|
# abundances for both stable isotopes |
94 |
|
|
[Isotopes] 2 |
95 |
|
|
mass 12.0 prob 0.989 |
96 |
|
|
mass 13.003354 prob 0.010788 |
97 |
|
|
[Element] |
98 |
|
|
# The two atoms that are 95% labelled with 14[C] need to use |
99 |
|
|
# a new artificial symbol |
100 |
|
|
symbol Cx count 2 |
101 |
|
|
[Isotopes] 3 |
102 |
|
|
# 5% of non labelled atoms are of natural 12[C] abundance |
103 |
|
|
mass 12.000 prob 0.05*0.989211941850466 |
104 |
|
|
# 5% of non labelled atoms are of natural 13[C] abundance |
105 |
|
|
mass 13.0033548352 prob 0.05*0.010788058149533084 |
106 |
|
|
# The remaining 95% of the atoms are 14[C] atoms with abundance 100% |
107 |
|
|
mass 14.003241989 prob 0.95*1.00 |
108 |
|
|
[Element] |
109 |
|
|
symbol H count 12 |
110 |
|
|
[Isotopes] 2 |
111 |
|
|
mass 1.0078250 prob 0.99988 |
112 |
|
|
mass 2.01410177 prob 0.00011570 |
113 |
|
|
[Element] |
114 |
|
|
symbol O count 6 |
115 |
|
|
[Isotopes] 3 |
116 |
|
|
mass 15.9949 prob 0.99756 |
117 |
|
|
mass 16.999 prob 0.000380 |
118 |
|
|
mass 17.999 prob 0.002051 |
119 |
|
|
\endcode |
120 |
|
|
|
121 |
|
|
Comments are allowed and are on lines that have as their first non-space |
122 |
|
|
character the '#' character. These lines are ignored when loading data. |
123 |
|
|
|
124 |
|
|
The data can be loaded from and written to file. |
125 |
|
|
|
126 |
|
|
\sa IsotopicDataLibraryHandler, IsotopicDataUserConfigHandler |
127 |
|
|
*/ |
128 |
|
|
|
129 |
|
|
/*! |
130 |
|
|
\variable IsotopicDataManualConfigHandler::m_symbolCountMap |
131 |
|
|
|
132 |
|
|
Holds symbol/count pairs to document the count of any symbol in the isotopic |
133 |
|
|
data. This symbol count is stored in the file using the following format: |
134 |
|
|
|
135 |
|
|
\code |
136 |
|
|
[Element] |
137 |
|
|
symbol C count 6 |
138 |
|
|
\endcode |
139 |
|
|
|
140 |
|
|
The number of carbon atoms in the formula being defined is 6, as in glucose: |
141 |
|
|
C6H1206. |
142 |
|
|
*/ |
143 |
|
|
|
144 |
|
|
/*! |
145 |
|
|
\typedef IsotopicDataManualConfigHandlerSPtr |
146 |
|
|
\relates IsotopicDataManualConfigHandler |
147 |
|
|
|
148 |
|
|
Synonym for std::shared_ptr<IsotopicDataManualConfigHandler>. |
149 |
|
|
*/ |
150 |
|
|
|
151 |
|
|
/*! |
152 |
|
|
\typedef IsotopicDataManualConfigHandlerCstSPtr |
153 |
|
|
\relates IsotopicDataManualConfigHandler |
154 |
|
|
|
155 |
|
|
Synonym for std::shared_ptr<const IsotopicDataManualConfigHandler>. |
156 |
|
|
*/ |
157 |
|
|
|
158 |
|
|
/*! |
159 |
|
|
\brief Constructs the \l{IsotopicDataManualConfigHandler} with \a file_name. |
160 |
|
|
*/ |
161 |
|
28 |
IsotopicDataManualConfigHandler::IsotopicDataManualConfigHandler( |
162 |
|
28 |
const QString &file_name) |
163 |
|
28 |
: IsotopicDataBaseHandler(file_name) |
164 |
|
|
{ |
165 |
|
28 |
} |
166 |
|
|
|
167 |
|
|
/*! |
168 |
|
|
\brief Constructs the \l{IsotopicDataManualConfigHandler}. |
169 |
|
|
|
170 |
|
|
\a isotopic_data_sp Isotopic data |
171 |
|
|
|
172 |
|
|
\a file_name File name |
173 |
|
|
*/ |
174 |
|
✗ |
IsotopicDataManualConfigHandler::IsotopicDataManualConfigHandler( |
175 |
|
✗ |
IsotopicDataSPtr isotopic_data_sp, const QString &file_name) |
176 |
|
✗ |
: IsotopicDataBaseHandler(isotopic_data_sp, file_name) |
177 |
|
|
{ |
178 |
|
✗ |
} |
179 |
|
|
|
180 |
|
|
/*! |
181 |
|
|
\brief Destructs the \l{IsotopicDataManualConfigHandler}. |
182 |
|
|
*/ |
183 |
|
64 |
IsotopicDataManualConfigHandler::~IsotopicDataManualConfigHandler() |
184 |
|
|
{ |
185 |
|
|
// qDebug(); |
186 |
|
64 |
} |
187 |
|
|
|
188 |
|
|
/*! |
189 |
|
|
\brief Assigns \a map to m_symbolCountMap. |
190 |
|
|
*/ |
191 |
|
|
void |
192 |
|
✗ |
IsotopicDataManualConfigHandler::setSymbolCountMap(const SymbolCountMap &map) |
193 |
|
|
{ |
194 |
|
✗ |
m_symbolCountMap = map; |
195 |
|
✗ |
} |
196 |
|
|
|
197 |
|
|
/*! |
198 |
|
|
\brief Returns a reference to m_symbolCountMap. |
199 |
|
|
*/ |
200 |
|
|
const SymbolCountMap & |
201 |
|
✗ |
IsotopicDataManualConfigHandler::getSymbolCountMap() const |
202 |
|
|
{ |
203 |
|
✗ |
return m_symbolCountMap; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
/*! |
207 |
|
|
\brief Loads isotopic data from \a file_name. |
208 |
|
|
|
209 |
|
|
Returns the count of \l{Isotope}s that were allocated and stored in the |
210 |
|
|
msp_isotopicData member. |
211 |
|
|
*/ |
212 |
|
|
std::size_t |
213 |
|
16 |
IsotopicDataManualConfigHandler::loadData(const QString &file_name) |
214 |
|
|
{ |
215 |
|
|
// File format: |
216 |
|
|
// |
217 |
|
|
// [Element] |
218 |
|
|
// symbol C count 6 |
219 |
|
|
// [Isotopes] 2 |
220 |
|
|
// mass 12.0 prob 0.989 |
221 |
|
|
// mass 13.003354 prob 0.010788 |
222 |
|
|
// [Element] |
223 |
|
|
// symbol H count 13 |
224 |
|
|
// [Isotopes] 2 |
225 |
|
|
// mass 1.0078250 prob 0.99988 |
226 |
|
|
// mass 2.01410177 prob 0.00011570 |
227 |
|
|
// [Element] |
228 |
|
|
// symbol O count 6 |
229 |
|
|
// [Isotopes] 3 |
230 |
|
|
// mass 15.9949 prob 0.99756 |
231 |
|
|
// mass 16.999 prob 0.000380 |
232 |
|
|
// mass 17.999 prob 0.002051 |
233 |
|
|
// |
234 |
|
|
|
235 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 |
if(file_name.isEmpty()) |
236 |
|
|
{ |
237 |
|
✗ |
qDebug("File name is emtpy. Failed to open file for reading."); |
238 |
|
✗ |
return 0; |
239 |
|
|
} |
240 |
|
|
|
241 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
QFile file(file_name); |
242 |
|
|
|
243 |
2/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
16 |
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) |
244 |
|
|
{ |
245 |
|
✗ |
qDebug() << "Failed to open file for reading."; |
246 |
|
✗ |
return 0; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
// File-parsing helper variables. |
250 |
|
16 |
bool was_started_one_element = false; |
251 |
|
16 |
bool was_symbol_count_line = false; |
252 |
|
16 |
bool was_isotopes_count_line = false; |
253 |
|
16 |
bool was_mass_prob_line = false; |
254 |
|
|
|
255 |
|
|
// Instantiate a symbol that we'll use as a place holder for the element name. |
256 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
QString symbol = ""; |
257 |
|
|
|
258 |
|
|
// Instantiate a count to document the symbol count. |
259 |
|
16 |
std::size_t element_count = 0; |
260 |
|
|
|
261 |
|
|
// Instantiate a count to document the number of isotopes that were defined |
262 |
|
|
// for a given element. |
263 |
|
16 |
std::size_t element_isotope_count = 0; |
264 |
|
|
|
265 |
|
|
// Increment each time an isotope is parsed and added to the vector *for a |
266 |
|
|
// given element stanza*. This helps sanity checking. |
267 |
|
16 |
std::size_t added_isotopes_for_element = 0; |
268 |
|
|
|
269 |
|
|
// Maintain a counter of the whole count of isotopes for sanity checks. |
270 |
|
16 |
std::size_t all_parsed_isotopes_count = 0; |
271 |
|
|
|
272 |
|
16 |
double mass = 0; |
273 |
|
16 |
double prob = 0; |
274 |
|
|
|
275 |
|
16 |
bool ok = false; |
276 |
|
|
|
277 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 |
QRegularExpression comment_regexp("^\\s*#"); |
278 |
|
|
|
279 |
|
|
QRegularExpression symbol_count_regexp( |
280 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 |
"^\\s*symbol\\s+([A-Z][a-z]?)\\s+count\\s+(\\d+)"); |
281 |
|
|
|
282 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 |
QRegularExpression isotopes_regexp("^\\s*\\[Isotopes\\]\\s(\\d+)"); |
283 |
|
|
|
284 |
|
|
// QRegularExpression massProbRegexp = QRegularExpression( |
285 |
|
|
//"^\\s+mass\\s+(\\d*\\.?\\d*[e]?[-]?[+]?\\d*)\\s+prob\\s+([^\\d^\\.^-]+)(-?" |
286 |
|
|
//"\\d*\\.?\\d*[e]?[-]?[+]?\\d*)"); |
287 |
|
|
|
288 |
|
|
QRegularExpression mass_prob_regexp = QRegularExpression( |
289 |
|
|
"^\\s*mass\\s(\\d*\\.?\\d*[e]?[-]?[+]?\\d*)\\sprob\\s(\\d*\\.?\\d*[e]?[" |
290 |
|
|
"-]" |
291 |
|
|
"?[" |
292 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 |
"+]?\\d*)"); |
293 |
|
|
|
294 |
|
|
// qDebug() << "The mass prob regexp is valid?" << |
295 |
|
|
// massProbRegexp.isValid(); |
296 |
|
|
|
297 |
|
|
// mass 13.003354835200 |
298 |
|
|
// prob 0.010788058149533083507343178553128382191061973571777343750000 |
299 |
|
|
|
300 |
|
|
// Make sure we clear the room. |
301 |
|
|
|
302 |
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 |
msp_isotopicData->clear(); |
303 |
|
|
|
304 |
|
16 |
std::vector<IsotopeSPtr> element_isotopes; |
305 |
|
|
|
306 |
|
|
// This set is to ensure that we do not have twice the same element frame |
307 |
|
|
// (that is, with the same symbol). |
308 |
|
|
|
309 |
|
16 |
std::set<QString> symbol_set; |
310 |
|
|
|
311 |
|
|
// File format: |
312 |
|
|
|
313 |
|
|
// [Element] |
314 |
|
|
// symbol C count 6 |
315 |
|
|
// [Isotopes] 2 |
316 |
|
|
// mass 12.0 prob 0.989 |
317 |
|
|
// mass 13.003354 prob 0.010788 |
318 |
|
|
|
319 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
QTextStream in(&file); |
320 |
|
|
|
321 |
3/4
✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 456 times.
✓ Branch 4 taken 16 times.
|
472 |
while(!in.atEnd()) |
322 |
|
|
{ |
323 |
1/2
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
|
456 |
QString line = in.readLine(); |
324 |
|
|
|
325 |
|
|
// Ignore empty lines |
326 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 456 times.
|
456 |
if(line.length() < 1) |
327 |
|
✗ |
continue; |
328 |
|
|
|
329 |
|
|
|
330 |
1/2
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
|
456 |
line = line.simplified(); |
331 |
|
|
|
332 |
|
|
// qDebug() << "Current line:" << line; |
333 |
|
|
|
334 |
|
|
// Ignore comment lines |
335 |
1/2
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
|
456 |
QRegularExpressionMatch match = comment_regexp.match(line); |
336 |
3/4
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 104 times.
✓ Branch 4 taken 352 times.
|
456 |
if(match.hasMatch()) |
337 |
|
104 |
continue; |
338 |
|
|
|
339 |
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 288 times.
|
352 |
if(line == "[Element]") |
340 |
|
|
{ |
341 |
|
|
// qDebug() << "That's the [Element] stanza opening line."; |
342 |
|
|
|
343 |
|
|
// We are starting a new Element stanza. It cannot be that we both |
344 |
|
|
// have already started one Element stanza and that not a single |
345 |
|
|
// mass and probability line had been encountered. Either this is the |
346 |
|
|
// very first Element stanza that we read and was_started_one_element |
347 |
|
|
// is false or we were reading one Element stanza that has finished |
348 |
|
|
// and then was_mass_prob_line has to be true. |
349 |
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
|
64 |
if(was_started_one_element && !was_mass_prob_line) |
350 |
|
|
{ |
351 |
|
✗ |
qDebug() << "Error: one element is complete but has no isotopes."; |
352 |
|
✗ |
return 0; |
353 |
|
|
} |
354 |
|
|
|
355 |
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
|
64 |
if(was_started_one_element) |
356 |
|
|
{ |
357 |
|
|
|
358 |
|
|
// qDebug() |
359 |
|
|
//<< "We had already seen the [Element] stanza opening line."; |
360 |
|
|
|
361 |
|
|
// We are starting a new Element configuration stanza, but in |
362 |
|
|
// fact another was already cooking. We need to terminate it. |
363 |
|
|
|
364 |
|
|
// Sanity check: the number of purportedly listed isotopes needs |
365 |
|
|
// to be identical to the number of isotopes actually added to the |
366 |
|
|
// vector of isotopes. |
367 |
|
|
|
368 |
3/6
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
|
96 |
if(element_isotope_count != element_isotopes.size() || |
369 |
|
48 |
added_isotopes_for_element != element_isotopes.size()) |
370 |
|
|
{ |
371 |
|
✗ |
qDebug() << "Error. We did not parse the expected number of " |
372 |
|
✗ |
"isotopes."; |
373 |
|
✗ |
return 0; |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
// qDebug() << "And there are the right number of isotopes |
377 |
|
|
// cooked."; |
378 |
|
|
|
379 |
|
|
// At this point we have everything we need to add this new |
380 |
|
|
// chemical set. |
381 |
|
|
|
382 |
|
|
// qDebug() << "Creating new chemical set."; |
383 |
|
|
|
384 |
2/4
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
|
48 |
if(!newChemicalSet( |
385 |
|
|
symbol, element_count, element_isotopes, false)) |
386 |
|
|
{ |
387 |
|
✗ |
qDebug() << "Failed to add new chemical set."; |
388 |
|
✗ |
return 0; |
389 |
|
|
} |
390 |
|
|
|
391 |
|
|
// qDebug() << "The completed chemical set: " |
392 |
|
|
//"symbol/element_count/isotope_count:" |
393 |
|
|
//<< symbol << "/" << element_count << "/" |
394 |
|
|
//<< element_isotopes.size(); |
395 |
|
|
|
396 |
|
|
// Sanity check: the total count of added isotopes for this symbol |
397 |
|
|
// needs to correct. |
398 |
|
|
|
399 |
|
48 |
if(added_isotopes_for_element != |
400 |
2/4
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
|
48 |
msp_isotopicData->getIsotopeCountBySymbol(symbol)) |
401 |
|
✗ |
qFatal("Programming error."); |
402 |
|
|
|
403 |
|
|
// Now clear for next run. |
404 |
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 |
symbol = ""; |
405 |
|
48 |
element_isotope_count = 0; |
406 |
|
48 |
added_isotopes_for_element = 0; |
407 |
|
48 |
element_isotopes.clear(); |
408 |
|
|
} |
409 |
|
|
|
410 |
|
|
// Tell that we actually have entered the first line of an Element |
411 |
|
|
// stanza. |
412 |
|
64 |
was_started_one_element = true; |
413 |
|
|
|
414 |
|
|
// Reset all the other values so that we know we are just at the |
415 |
|
|
// beginning of the parsing work. |
416 |
|
64 |
was_symbol_count_line = false; |
417 |
|
64 |
was_isotopes_count_line = false; |
418 |
|
64 |
was_mass_prob_line = false; |
419 |
|
|
|
420 |
|
|
// Go the next line. |
421 |
|
64 |
continue; |
422 |
|
|
} |
423 |
|
|
|
424 |
|
|
// At this point we are already inside of the [Element] stanza. Parse the |
425 |
|
|
// various lines inside it. |
426 |
|
|
|
427 |
|
|
// File format: |
428 |
|
|
|
429 |
|
|
// [Element] |
430 |
|
|
// symbol C count 6 |
431 |
|
|
// [Isotopes] 2 |
432 |
|
|
// mass 12.0 prob 0.989 |
433 |
|
|
// mass 13.003354 prob 0.010788 |
434 |
|
|
|
435 |
1/2
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 |
match = symbol_count_regexp.match(line); |
436 |
3/4
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 224 times.
|
288 |
if(match.hasMatch()) |
437 |
|
|
{ |
438 |
|
|
|
439 |
|
|
// qDebug() << "Matched the symbol count line."; |
440 |
|
|
|
441 |
|
|
// If we are parsing "symbol C count 100", then it is not possible |
442 |
|
|
// that we did not encounter before [Element] or that we already have |
443 |
|
|
// parsed one same line as "symbol C count 100". |
444 |
|
|
|
445 |
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
|
64 |
if(!was_started_one_element || was_symbol_count_line) |
446 |
|
|
{ |
447 |
|
✗ |
qDebug() << "Error encountered in the symbol/count line."; |
448 |
|
✗ |
return 0; |
449 |
|
|
} |
450 |
|
|
|
451 |
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
|
64 |
symbol = match.captured(1); |
452 |
|
|
|
453 |
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
|
64 |
element_count = match.captured(2).toInt(&ok); |
454 |
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
|
64 |
if(!ok || !element_count) |
455 |
|
|
{ |
456 |
|
✗ |
qDebug() << "Error encountered in the symbol/count line."; |
457 |
|
✗ |
return 0; |
458 |
|
|
} |
459 |
|
|
|
460 |
|
|
// Now check if that symbol was encountered already, which would be an |
461 |
|
|
// error. |
462 |
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
|
64 |
auto res = symbol_set.insert(symbol); |
463 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 |
if(!res.second) |
464 |
|
|
{ |
465 |
|
|
// We did not insert the symbol because one already existed. That |
466 |
|
|
// is an error. |
467 |
|
|
|
468 |
|
✗ |
qDebug() << "An element by symbol" << symbol |
469 |
|
|
<< "has already been processed: " |
470 |
|
✗ |
"this is not permitted."; |
471 |
|
✗ |
return 0; |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
// qDebug() << "Processed element symbol:" << symbol |
475 |
|
|
//<< "with count:" << element_count; |
476 |
|
|
|
477 |
|
|
// Do not store the element symbol/count pair yet, we'll wait to |
478 |
|
|
// encounter a new Element stanza which will close this one. |
479 |
|
|
|
480 |
|
64 |
was_symbol_count_line = true; |
481 |
|
64 |
was_isotopes_count_line = false; |
482 |
|
64 |
was_mass_prob_line = false; |
483 |
|
|
|
484 |
|
64 |
continue; |
485 |
|
64 |
} |
486 |
|
|
// End of |
487 |
|
|
// line matched the symbol/count regexp |
488 |
|
|
|
489 |
|
|
// File format: |
490 |
|
|
|
491 |
|
|
// [Element] |
492 |
|
|
// symbol C count 6 |
493 |
|
|
// [Isotopes] 2 |
494 |
|
|
// mass 12.0 prob 0.989 |
495 |
|
|
// mass 13.003354 prob 0.010788 |
496 |
|
|
|
497 |
1/2
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
|
224 |
match = isotopes_regexp.match(line); |
498 |
3/4
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 160 times.
|
224 |
if(match.hasMatch()) |
499 |
|
|
{ |
500 |
|
|
|
501 |
|
|
// qDebug() << "Matched the [Isotopes] count stanza opening line."; |
502 |
|
|
|
503 |
|
|
// We cannot be parsing the [Isotopes] stanza opening header if we |
504 |
|
|
// have not previously parsed the symbol/count line. |
505 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 |
if(!was_symbol_count_line) |
506 |
|
|
{ |
507 |
|
✗ |
qDebug() << "Error encounteredd in the isotopes lines."; |
508 |
|
✗ |
return 0; |
509 |
|
|
} |
510 |
|
|
|
511 |
|
|
// Store the number of isotopes for the current Element. |
512 |
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
|
64 |
element_isotope_count = match.captured(1).toInt(&ok); |
513 |
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
|
64 |
if(!ok || !element_isotope_count) |
514 |
|
|
{ |
515 |
|
✗ |
qDebug() << "Error encounteredd in the isotopes lines."; |
516 |
|
✗ |
return 0; |
517 |
|
|
} |
518 |
|
|
|
519 |
|
|
// qDebug() << "The isotope count is:" << element_isotope_count; |
520 |
|
|
|
521 |
|
64 |
was_isotopes_count_line = true; |
522 |
|
64 |
was_symbol_count_line = false; |
523 |
|
64 |
was_mass_prob_line = false; |
524 |
|
|
|
525 |
|
64 |
continue; |
526 |
|
|
} |
527 |
|
|
// End of |
528 |
|
|
// line matched the [Isotopes] count regexp |
529 |
|
|
|
530 |
|
|
// File format: |
531 |
|
|
|
532 |
|
|
// [Element] |
533 |
|
|
// symbol C count 6 |
534 |
|
|
// [Isotopes] 2 |
535 |
|
|
// mass 12.0 prob 0.989 |
536 |
|
|
// mass 13.003354 prob 0.010788 |
537 |
|
|
|
538 |
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 |
match = mass_prob_regexp.match(line); |
539 |
2/4
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 160 times.
✗ Branch 4 not taken.
|
160 |
if(match.hasMatch()) |
540 |
|
|
{ |
541 |
|
|
|
542 |
|
|
// qDebug() << "Matched the mass prob line."; |
543 |
|
|
|
544 |
|
|
// If we match an isotope's mass/prob line, either --- at previous |
545 |
|
|
// line --- we had seen the [Isotopes] stanza opening line or we had |
546 |
|
|
// seen another mass prob line. |
547 |
|
|
|
548 |
|
|
|
549 |
3/4
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96 times.
|
160 |
if(!was_isotopes_count_line && !was_mass_prob_line) |
550 |
|
|
{ |
551 |
|
✗ |
qDebug() << "Error encountered in the mass/prob line."; |
552 |
|
✗ |
return 0; |
553 |
|
|
} |
554 |
|
|
|
555 |
2/4
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
|
160 |
mass = match.captured(1).toDouble(&ok); |
556 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
|
160 |
if(!ok) |
557 |
|
|
{ |
558 |
|
✗ |
qDebug() << "Error encountered in the mass/prob line."; |
559 |
|
✗ |
return 0; |
560 |
|
|
} |
561 |
|
|
|
562 |
2/4
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
|
160 |
prob = match.captured(2).toDouble(&ok); |
563 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
|
160 |
if(!ok) |
564 |
|
|
{ |
565 |
|
✗ |
qDebug() << "Error encountered in the mass/prob line."; |
566 |
|
✗ |
return 0; |
567 |
|
|
} |
568 |
|
|
|
569 |
|
|
// At this point we have everything we need to actually create the |
570 |
|
|
// isotope by symbol and mass and prob. There are a number of fields |
571 |
|
|
// that are left to value 0 but this is of no worries. |
572 |
|
|
|
573 |
|
|
// qDebug() << "Iterated in isotope:" << symbol << ":" << mass << "/" |
574 |
|
|
//<< prob; |
575 |
|
|
|
576 |
|
|
// At this point create a brand new Isotope with the relevant data. |
577 |
|
|
|
578 |
|
|
// Isotope::Isotope(int id, |
579 |
|
|
// QString element, |
580 |
|
|
// QString symbol, |
581 |
|
|
// int atomicNo, |
582 |
|
|
// double mass, |
583 |
|
|
// int massNo, |
584 |
|
|
// int extraNeutrons, |
585 |
|
|
// double probability, |
586 |
|
|
// double lnProbability, |
587 |
|
|
// bool radioactive) |
588 |
|
|
|
589 |
|
|
// There are a number of fields that are left to value 0 but this is |
590 |
|
|
// of no worries. Store the isotope in the vector of isotopes that |
591 |
|
|
// will be added to the isotopic data later when finishing the parsing |
592 |
|
|
// of the element frame widget. |
593 |
|
|
|
594 |
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 |
element_isotopes.push_back(std::make_shared<libXpertMass::Isotope>( |
595 |
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 |
0, symbol, symbol, 0, mass, 0, 0, prob, 0, false)); |
596 |
|
|
|
597 |
|
160 |
++added_isotopes_for_element; |
598 |
|
160 |
++all_parsed_isotopes_count; |
599 |
|
|
|
600 |
|
|
// qDebug() << "The atom now is:" << atom.asText(); |
601 |
|
|
|
602 |
|
160 |
was_mass_prob_line = true; |
603 |
|
160 |
was_isotopes_count_line = false; |
604 |
|
160 |
was_symbol_count_line = false; |
605 |
|
|
|
606 |
|
160 |
continue; |
607 |
|
|
} |
608 |
|
|
// End of |
609 |
|
|
// line matched the isotope mass/prob regexp |
610 |
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 456 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 456 times.
✗ Branch 7 not taken.
|
912 |
} |
611 |
|
|
|
612 |
|
|
|
613 |
|
|
// We have finished iterating in the file's lines but we were parsing an atom, |
614 |
|
|
// append it. |
615 |
|
|
|
616 |
|
|
// Sanity check |
617 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 |
if(!was_started_one_element) |
618 |
|
|
{ |
619 |
|
✗ |
qDebug() << "Error: not a single element could be parsed."; |
620 |
|
✗ |
return 0; |
621 |
|
|
} |
622 |
|
|
|
623 |
|
|
// Sanity check: the number of purportedly listed isotopes needs |
624 |
|
|
// to be identical to the number of isotopes actually added to the |
625 |
|
|
// vector of isotopes. |
626 |
|
|
|
627 |
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 16 times.
|
32 |
if(element_isotope_count != element_isotopes.size() || |
628 |
|
16 |
added_isotopes_for_element != element_isotopes.size()) |
629 |
|
|
{ |
630 |
|
✗ |
qDebug() << "Error. We did not parse the expected number of " |
631 |
|
✗ |
"isotopes."; |
632 |
|
✗ |
return 0; |
633 |
|
|
} |
634 |
|
|
|
635 |
|
|
// At this point we have everything we need to add this new |
636 |
|
|
// chemical set. Do not yet update the mass maps, we'll do at the end of the |
637 |
|
|
// process. |
638 |
|
|
|
639 |
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
|
16 |
if(!newChemicalSet(symbol, element_count, element_isotopes, false)) |
640 |
|
|
{ |
641 |
|
✗ |
qDebug() << "Failed to add new chemical set."; |
642 |
|
✗ |
return 0; |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
// qDebug() << "The completed chemical set: " |
646 |
|
|
//"symbol/element_count/isotope_count:" |
647 |
|
|
//<< symbol << "/" << element_count << "/" << element_isotopes.size(); |
648 |
|
|
|
649 |
|
|
// Sanity check: the total count of added isotopes for this symbol |
650 |
|
|
// needs to correct. |
651 |
|
|
|
652 |
|
16 |
if(added_isotopes_for_element != |
653 |
2/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
16 |
msp_isotopicData->getIsotopeCountBySymbol(symbol)) |
654 |
|
✗ |
qFatal("Programming error."); |
655 |
|
|
|
656 |
|
|
// Sanity check: the total count of isotopes added to the isotopic data member |
657 |
|
|
// datum needs to match the total count of parsed isotopes. |
658 |
2/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
16 |
if(all_parsed_isotopes_count != msp_isotopicData->size()) |
659 |
|
✗ |
qFatal("Programming error."); |
660 |
|
|
|
661 |
|
|
// We have touched the isotopic data, ensure the maps are current. |
662 |
2/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
16 |
if(!msp_isotopicData->updateMassMaps()) |
663 |
|
✗ |
qFatal("Programming error. Failed to update the mass maps."); |
664 |
|
|
|
665 |
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 |
return msp_isotopicData->size(); |
666 |
|
16 |
} |
667 |
|
|
|
668 |
|
|
/*! |
669 |
|
|
\brief Write all the IsotopicData to \a file_name. |
670 |
|
|
|
671 |
|
|
If \a file_name is empty, m_fileName is tried. If both are empty, the |
672 |
|
|
function returns 0. If any one of the file names are correct (file_name takes |
673 |
|
|
precedence over m_fileName), then m_fileName is set to that file name. |
674 |
|
|
|
675 |
|
|
The format of the file consists in a single line of data per \l{Isotope} as |
676 |
|
|
created using the Isotope::toString() function. Each isotope is output to |
677 |
|
|
its own line. |
678 |
|
|
|
679 |
|
|
Returns the count of \l{Isotope}s written to file or 0 if the file does not |
680 |
|
|
exist or is not readable. |
681 |
|
|
|
682 |
|
|
\sa Isotope::Isotope(const QString &text) |
683 |
|
|
*/ |
684 |
|
|
std::size_t |
685 |
|
4 |
IsotopicDataManualConfigHandler::writeData(const QString &file_name) |
686 |
|
|
{ |
687 |
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()) |
688 |
|
✗ |
return 0; |
689 |
|
|
|
690 |
|
4 |
QString temp_file_name; |
691 |
|
|
|
692 |
|
|
// The passed filename takes precedence over the member datum. So copy |
693 |
|
|
// that file name to the member datum. |
694 |
|
|
|
695 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
if(!file_name.isEmpty()) |
696 |
|
4 |
temp_file_name = file_name; |
697 |
|
|
else |
698 |
|
✗ |
temp_file_name = m_fileName; |
699 |
|
|
|
700 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
QFile file(temp_file_name); |
701 |
|
|
|
702 |
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)) |
703 |
|
|
{ |
704 |
|
✗ |
qDebug("Failed to open file for writing."); |
705 |
|
✗ |
return false; |
706 |
|
|
} |
707 |
|
|
|
708 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
QTextStream out(&file); |
709 |
|
|
|
710 |
|
|
out |
711 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
<< "# This file contains isotopic data in a format that can accommodate\n"; |
712 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
out << "# comments in the form of lines beginning with the '#' character.\n"; |
713 |
|
|
|
714 |
|
4 |
std::size_t isotope_count = 0; |
715 |
|
|
|
716 |
|
|
// We want to write the isotopic data exactly in the same order as we might |
717 |
|
|
// have loaded them. This is why we need to iterated in the vector of isotopes |
718 |
|
|
// and not the in the map that is ordered according to the symbols (the keys). |
719 |
|
|
|
720 |
|
4 |
QString last_symbol; |
721 |
|
|
|
722 |
2/2
✓ Branch 7 taken 40 times.
✓ Branch 8 taken 4 times.
|
44 |
for(auto item : msp_isotopicData->m_isotopes) |
723 |
|
|
{ |
724 |
1/2
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
|
40 |
QString symbol = item->getSymbol(); |
725 |
|
|
|
726 |
|
|
// We only write the  [Element] and [Isotopes] stanza header once for each |
727 |
|
|
// new symbol found in the iterated items. |
728 |
|
|
|
729 |
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 24 times.
|
40 |
if(symbol != last_symbol) |
730 |
|
|
{ |
731 |
|
|
|
732 |
|
|
// This is the first time we encounter an isotope by symbol, we open a |
733 |
|
|
// new Element stanza. |
734 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
out << "[Element]\n"; |
735 |
|
|
|
736 |
|
|
// We now need to write the symbol count line. If the symbol key is |
737 |
|
|
// not found, throws an exception. |
738 |
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 |
int symbol_count = m_symbolCountMap.at(symbol); |
739 |
|
|
out |
740 |
4/8
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 16 times.
✗ Branch 11 not taken.
|
48 |
<< QString("\tsymbol %1 count %2\n").arg(symbol).arg(symbol_count); |
741 |
|
|
|
742 |
|
|
// We also need to write the Isotopes stanza: |
743 |
|
|
int symbol_isotope_count = |
744 |
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 |
msp_isotopicData->getIsotopeCountBySymbol(symbol); |
745 |
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
|
32 |
out << QString("\t[Isotopes] %1\n").arg(symbol_isotope_count); |
746 |
|
|
} |
747 |
|
|
|
748 |
|
|
// At this point we can write the currently iterated isotope's mass:prob |
749 |
|
|
// pair. |
750 |
|
|
|
751 |
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
40 |
out << QString("\t\tmass %1 prob %2\n") |
752 |
2/4
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
|
80 |
.arg(item->getMass(), 0, 'f', 60) |
753 |
3/6
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 40 times.
✗ Branch 9 not taken.
|
40 |
.arg(item->getProbability(), 0, 'f', 60); |
754 |
|
|
|
755 |
|
40 |
last_symbol = symbol; |
756 |
|
|
|
757 |
|
40 |
++isotope_count; |
758 |
|
40 |
} |
759 |
|
|
|
760 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
out.flush(); |
761 |
|
|
|
762 |
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 |
file.close(); |
763 |
|
|
|
764 |
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()) |
765 |
|
✗ |
qFatal("Programming error. Failed to write all the isotopes to file."); |
766 |
|
|
|
767 |
|
|
// Now we know that temp_file_name is fine. Store into m_fileName. |
768 |
|
4 |
m_fileName = temp_file_name; |
769 |
|
|
|
770 |
|
4 |
return isotope_count; |
771 |
|
4 |
} |
772 |
|
|
|
773 |
|
|
/*! |
774 |
|
|
\brief Add a set of \l{Isotope}s belonging to chemical element \a symbol. |
775 |
|
|
|
776 |
|
|
The count of atoms of \a symbol is defined with \a element_count. The |
777 |
|
|
isotopes to be added are provided in \a isotopes. |
778 |
|
|
|
779 |
|
|
If the new chemical data pertain to a symbol that was already added to the |
780 |
|
|
IsotopicData, then that is an error. |
781 |
|
|
|
782 |
|
|
If \a update_maps is true, the \l{IsotopicData} maps need to be updated. |
783 |
|
|
|
784 |
|
|
Returns false if the new chemical data pertain to a \a symbol that was |
785 |
|
|
already added to the IsotopicData. |
786 |
|
|
|
787 |
|
|
\sa IsotopicData::updateMonoMassMap(), IsotopicData::updateAvgMassMap() |
788 |
|
|
*/ |
789 |
|
|
bool |
790 |
|
64 |
IsotopicDataManualConfigHandler::newChemicalSet( |
791 |
|
|
const QString &symbol, |
792 |
|
|
int element_count, |
793 |
|
|
const std::vector<IsotopeSPtr> &isotopes, |
794 |
|
|
bool update_maps) |
795 |
|
|
{ |
796 |
|
|
// It is of uttermost importance that we update the symbol/count pair because |
797 |
|
|
// that is going to be used when performing the IsoSpec arrays configuration |
798 |
|
|
// and later isotopic cluster calculations. |
799 |
|
|
|
800 |
|
|
std::pair<SymbolCountMapIter, bool> res = |
801 |
1/2
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 |
m_symbolCountMap.insert(std::pair<QString, int>(symbol, element_count)); |
802 |
|
|
|
803 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 |
if(!res.second) |
804 |
|
|
{ |
805 |
|
|
// Sanity check: it is not possible to add new chemical sets by a given |
806 |
|
|
// symbol multiple times. |
807 |
|
|
|
808 |
|
✗ |
qDebug() << "Error: isotopes by that symbol: " << symbol |
809 |
|
✗ |
<< "were already found in the isotopic data set."; |
810 |
|
|
|
811 |
|
✗ |
return false; |
812 |
|
|
} |
813 |
|
|
|
814 |
1/2
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 |
std::size_t count_before = msp_isotopicData->size(); |
815 |
|
|
|
816 |
|
|
// Update the mass maps according to second param below. |
817 |
1/2
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 |
msp_isotopicData->appendNewIsotopes(isotopes, update_maps); |
818 |
|
|
|
819 |
1/2
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 |
std::size_t count_after = msp_isotopicData->size(); |
820 |
|
|
|
821 |
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
|
64 |
if(count_after - count_before != isotopes.size()) |
822 |
|
✗ |
qFatal("Programming error."); |
823 |
|
|
|
824 |
|
64 |
return true; |
825 |
|
|
} |
826 |
|
|
|
827 |
|
|
/*! |
828 |
|
|
\brief Returns a string containing a formula corresponding to the |
829 |
|
|
IsotopicData. |
830 |
|
|
|
831 |
|
|
The formula is actually computed using the symbol/count pairs stored in |
832 |
|
|
m_symbolCountMap. |
833 |
|
|
*/ |
834 |
|
|
QString |
835 |
|
✗ |
IsotopicDataManualConfigHandler::craftFormula() const |
836 |
|
|
{ |
837 |
|
✗ |
QString formula; |
838 |
|
|
|
839 |
|
✗ |
for(auto item : m_symbolCountMap) |
840 |
|
✗ |
formula.append(QString("%1%2").arg(item.first).arg(item.second)); |
841 |
|
|
|
842 |
|
✗ |
return formula; |
843 |
|
✗ |
} |
844 |
|
|
|
845 |
|
|
/*! |
846 |
|
|
\brief Returns the count of \l{Isotope}s in this collection. |
847 |
|
|
*/ |
848 |
|
|
std::size_t |
849 |
|
✗ |
IsotopicDataManualConfigHandler::checkConsistency() |
850 |
|
|
{ |
851 |
|
✗ |
return msp_isotopicData->size(); |
852 |
|
|
} |
853 |
|
|
|
854 |
|
|
|
855 |
|
|
} // namespace libXpertMass |
856 |
|
|
|
857 |
|
|
} // namespace MsXpS |
858 |
|
|
|
859 |
|
|
|
860 |
|
|
#if 0 |
861 |
|
|
|
862 |
|
|
Example from IsoSpec. |
863 |
|
|
|
864 |
|
|
const int elementNumber = 2; |
865 |
|
|
const int isotopeNumbers[2] = {2,3}; |
866 |
|
|
|
867 |
|
|
const int atomCounts[2] = {2,1}; |
868 |
|
|
|
869 |
|
|
|
870 |
|
|
const double hydrogen_masses[2] = {1.00782503207, 2.0141017778}; |
871 |
|
|
const double oxygen_masses[3] = {15.99491461956, 16.99913170, 17.9991610}; |
872 |
|
|
|
873 |
|
|
const double* isotope_masses[2] = {hydrogen_masses, oxygen_masses}; |
874 |
|
|
|
875 |
|
|
const double hydrogen_probs[2] = {0.5, 0.5}; |
876 |
|
|
const double oxygen_probs[3] = {0.5, 0.3, 0.2}; |
877 |
|
|
|
878 |
|
|
const double* probs[2] = {hydrogen_probs, oxygen_probs}; |
879 |
|
|
|
880 |
|
|
IsoLayeredGenerator iso(Iso(elementNumber, isotopeNumbers, atomCounts, isotope_masses, probs), 0.99); |
881 |
|
|
|
882 |
|
|
#endif |
883 |
|
|
|