GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/PolChemDef.cpp
Date: 2025-11-20 01:41:33
Lines:
582/864
67.4%
Functions:
41/66
62.1%
Branches:
673/1665
40.4%

Line Branch Exec Source
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
34 ////////////////////////////// Stdlib includes
35 #include <map>
36 #include <vector>
37
38 /////////////////////// Qt includes
39 #include <QDebug>
40 #include <QFileInfo>
41 #include <QDir>
42
43
44 /////////////////////// Local includes
45 #include "MsXpS/libXpertMassCore/PolChemDef.hpp"
46 #include "MsXpS/libXpertMassCore/Monomer.hpp"
47 #include "MsXpS/libXpertMassCore/CrossLinker.hpp"
48 #include "MsXpS/libXpertMassCore/CleavageAgent.hpp"
49 #include "MsXpS/libXpertMassCore/FragmentationPathway.hpp"
50 #include "MsXpS/libXpertMassCore/IsotopicDataLibraryHandler.hpp"
51 #include "MsXpS/libXpertMassCore/IsotopicDataUserConfigHandler.hpp"
52
53
54 int polChemDefSPtrMetaTypeId =
55 qRegisterMetaType<MsXpS::libXpertMassCore::PolChemDefSPtr>("PolChemDefSPtr");
56
57 int polChemDefCstSPtrMetaTypeId =
58 qRegisterMetaType<MsXpS::libXpertMassCore::PolChemDefCstSPtr>(
59 "PolChemDefCstSPtr");
60
61 namespace MsXpS
62 {
63 namespace libXpertMassCore
64 {
65
66 /*!
67 \class MsXpS::libXpertMassCore::PolChemDef
68 \inmodule libXpertMassCore
69 \ingroup PolChemDef
70 \inheaderfile PolChemDef.hpp
71
72 \brief The PolChemDef class provides a complete set of chemical entities
73 fully qualifying a polymer chemistry definition, like Proteins, Saccharides or
74 Nucleic acids.
75
76 The PolChemDef class provides a full set of chemical entity definitions
77 (\l{Isotope}s, \l{Monomer}s, chemical \l{Modif}ications, \l{CrossLink}s),
78 chemical reaction models (in the liquid or gas phase, like \l Polymer cleavage:
79 \l CleavageAgent or \l Oligomer fragmentation: \l FragmentationPathway)\dots
80 */
81
82 /*!
83 \variable MsXpS::libXpertMassCore::PolChemDef::m_name
84
85 \brief The name of the polymer chemistry definition, like \e{protein-1-letter}
86 or \e{nucac}, for example.
87
88 This name is typically identical to both the name of the directory where all
89 the data defining this \c PolChemDef is stored and the name of the XML file
90 that contains the definition itself.
91 */
92
93 /*!
94 \variable MsXpS::libXpertMassCore::PolChemDef::m_xmlDataFilePath
95
96 \brief The path to the XML data file that contains the description of this
97 polymer chemistry definition.
98 */
99
100
101 /*!
102 \variable MsXpS::libXpertMassCore::PolChemDef::m_isotopicDataFilePath
103
104 \brief The path to the file that contains this polymer chemistry definition's
105 isotopic data.
106 */
107
108 /*!
109 \variable MsXpS::libXpertMassCore::PolChemDef::m_leftCap
110
111 \brief The \l Formula that defines how of the left end of a polymer
112 sequence of this \l PolChemDef needs to be capped in order to finalize the
113 polymerization state of the \l Polymer sequence.
114
115 \sa PolChemDef::m_rightCap
116 */
117
118 /*!
119 \variable MsXpS::libXpertMassCore::PolChemDef::m_rightCap
120
121 \brief The \l Formula that defines how of the right end of a polymer
122 sequence of this \l PolChemDef needs to be capped in order to finalize the
123 polymerization state of the \l Polymer sequence.
124
125 \sa PolChemDef::m_leftCap
126 */
127
128 /*!
129 \variable MsXpS::libXpertMassCore::PolChemDef::m_codeLength
130
131 \brief The maximum length of a \l Monomer code in this defintion.
132
133 The valid syntax of a Monomer code is that the first character of the code is
134 uppercase and all the remaining ones are lowercase. The total number of
135 characters cannot exceed m_codeLength.
136 */
137
138 /*!
139 \variable MsXpS::libXpertMassCore::PolChemDef::m_delimitedCodes
140
141 \brief The set of \l Monomer codes separated by '@' characters, like
142 "@Ala@Tyr@Phe@".
143 */
144
145 /*!
146 \variable MsXpS::libXpertMassCore::PolChemDef::m_ionizer
147
148 \brief The \l{Ionizer}{ionization agent} that governs the manner the \l
149 Polymer sequences of this polymer chemistry definition are ionized by default.
150 */
151
152 /*!
153 \variable MsXpS::libXpertMassCore::PolChemDef::msp_isotopicData
154
155 \brief The isotopic data defining the fundamentals of this \l PolChemDef
156 instance.
157 */
158
159 /*!
160 \variable MsXpS::libXpertMassCore::PolChemDef::m_monomers
161
162 \brief The container of \l{Monomer}s defined to be part of this \l PolChemDef
163 instance.
164 */
165
166
167 /*!
168 \variable MsXpS::libXpertMassCore::PolChemDef::m_modifs
169
170 \brief The container of \l{Modif}s defined to be part of this \l PolChemDef
171 instance.
172 */
173
174 /*!
175 \variable MsXpS::libXpertMassCore::PolChemDef::m_crossLinkers
176
177 The container of \l{CrossLinker}s defined to be part of this \l PolChemDef
178 instance.
179 */
180
181 /*!
182 \variable MsXpS::libXpertMassCore::PolChemDef::m_cleavageAgents
183
184 \brief The container of \l{CleavageAgent}s defining the various ways to cleave
185 \l Polymer sequences of this \l PolChemDef instance.
186 */
187
188 /*!
189 \variable MsXpS::libXpertMassCore::PolChemDef::m_fragmentationPathways
190
191 \brief The container of \l{FragmentationPathway}s defining the various ways to
192 fragment \l Oligomer sequences of this \l PolChemDef instance.
193 */
194
195 /*!
196 \variable MsXpS::libXpertMassCore::PolChemDef::m_polChemDefs
197
198 \brief The container of \l PolChemDef instances available in the repositories.
199 */
200
201
202 /*!
203 \variable MsXpS::libXpertMassCore::POL_CHEM_DEF_FILE_FORMAT_VERSION
204
205 \brief The latest version of the format of the file containing the
206 polymer chemistry definition.
207
208 Brought to 1 30 january 2023 for massXpert2
209 Brought to 2 10 november 2024 for massXpert2
210 */
211
212 const int POL_CHEM_DEF_FILE_FORMAT_VERSION = 2;
213
214 /*!
215 \brief Constructs a polymer chemistry definition.
216 */
217
3/6
✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 77 times.
✗ Branch 8 not taken.
77 PolChemDef::PolChemDef()
218 {
219 77 }
220
221 /*!
222 \brief Constructs a polymer chemistry definition on the basis of \a
223 pol_chem_def_spec.
224
225 The \a pol_chem_def_spec polymer chemistry definition specification provides
226 the name of the polymer chemistry definition and of the file that contains
227 it.
228 */
229
4/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
3 PolChemDef::PolChemDef(const PolChemDefSpec &pol_chem_def_spec)
230 {
231
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_name = pol_chem_def_spec.getName();
232
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 m_xmlDataFilePath = pol_chem_def_spec.getFilePath();
233
0/2
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 }
234
235 /*!
236 \brief Destroys the polymer chemistry definition
237 */
238 156 PolChemDef::~PolChemDef()
239 {
240
2/2
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 77 times.
158 }
241
242 /*!
243 \brief Sets the \a name of this PolChemDef instance.
244 */
245 void
246 71 PolChemDef::setName(const QString &name)
247 {
248 71 m_name = name;
249 71 }
250
251 /*!
252 \brief Returns the name of this PolChemDef instance.
253 */
254 QString
255 4 PolChemDef::getName() const
256 {
257
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 return m_name;
258 }
259
260 /*!
261 \brief Sets the \a file_path of this PolChemDef instance.
262 */
263 void
264 72 PolChemDef::setXmlDataFilePath(const QString &file_path)
265 {
266 72 m_xmlDataFilePath = file_path;
267 72 }
268
269 /*!
270 \brief Returns the file path of this PolChemDef instance.
271 */
272 QString
273 3 PolChemDef::getXmlDataFilePath() const
274 {
275
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 return m_xmlDataFilePath;
276 }
277
278 /*!
279 \brief Returns the absolute directory path of this PolChemDef instance.
280 */
281 QString
282 1 PolChemDef::getXmlDataDirPath() const
283 {
284 // qDebug() << "The xml data file path:" << m_xmlDataFilePath;
285
286 1 QFileInfo fileInfo(m_xmlDataFilePath);
287
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QDir dir(fileInfo.dir());
288
289 // qDebug() << "Returning the pol chem def data dir path:" <<
290
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 dir.absolutePath();
291
292
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return dir.absolutePath();
293 1 }
294
295 /*!
296 \brief Sets the path of the isotopic data file to \a file_path.
297 */
298 void
299 68 PolChemDef::setIsotopicDataFilePath(const QString &file_path)
300 {
301 68 m_isotopicDataFilePath = file_path;
302 68 }
303
304 /*!
305 \brief Returns the path of the isotopic data file.
306 */
307 QString
308 69 PolChemDef::getIsotopicDataFilePath() const
309 {
310
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 return m_isotopicDataFilePath;
311 }
312
313 /*!
314 \brief Returns the path of the isotopic data file.
315
316 The deduction is based on the fact that the file should have
317 "isotopic-data.dat" as its name.
318 */
319 QString
320 70 PolChemDef::deduceIsotopicDataFilePath() const
321 {
322 // From the xml data file path, deduce the file name of the isotopic data.
323 70 QFileInfo file_info(m_xmlDataFilePath);
324
325
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 70 times.
70 if(!file_info.exists())
326 qFatal(
327 "Programming error. The polymer chemistry definition file could not be "
328 "found.");
329
330
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 QDir dir(file_info.dir());
331
332
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 QString isotopic_data_file_path =
333
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
140 dir.absolutePath() + QDir::separator() + "isotopic-data.dat";
334
335 70 return isotopic_data_file_path;
336 70 }
337
338 /*!
339 \brief Sets the left cap \a formula.
340 */
341 void
342 PolChemDef::setLeftCap(const Formula &formula)
343 {
344 m_leftCap = formula;
345 }
346
347 /*!
348 \brief Returns the left cap formula.
349 */
350 const Formula &
351 1019 PolChemDef::getLeftCap() const
352 {
353 1019 return m_leftCap;
354 }
355
356 /*!
357 \brief Sets the right cap \a formula.
358 */
359 void
360 PolChemDef::setRightCap(const Formula &formula)
361 {
362 m_rightCap = formula;
363 }
364
365 /*!
366 \brief Returns the right cap formula.
367 */
368 const Formula &
369 987 PolChemDef::getRightCap() const
370 {
371 987 return m_rightCap;
372 }
373
374 /*!
375 \brief Sets the \a code_length.
376 */
377 void
378 PolChemDef::setCodeLength(int code_length)
379 {
380 m_codeLength = code_length;
381 }
382
383 /*!
384 \brief Returns the code length.
385 */
386 int
387 133226 PolChemDef::getCodeLength() const
388 {
389 133226 return m_codeLength;
390 }
391
392 /*!
393 \brief Sets the ionizer to \a ionizer.
394 */
395 void
396 PolChemDef::setIonizer(const Ionizer &ionizer)
397 {
398 m_ionizer = ionizer;
399 }
400
401 /*!
402 \brief Returns a const reference to the ionizer.
403 */
404 const Ionizer &
405 1 PolChemDef::getIonizerCstRef() const
406 {
407 1 return m_ionizer;
408 }
409
410 /*!
411 \brief Returns a pointer to the ionizer.
412 */
413 Ionizer &
414 PolChemDef::getIonizerRef()
415 {
416 return m_ionizer;
417 }
418
419 /*!
420 \brief Sets the isotopic data to \a isotopic_data_sp.
421 */
422 void
423 PolChemDef::setIsotopicDataSPtr(IsotopicDataSPtr isotopic_data_sp)
424 {
425 msp_isotopicData = isotopic_data_sp;
426 }
427
428 /*!
429 \brief Returns the isotopic data as const shared pointer..
430 */
431 IsotopicDataCstSPtr
432 422743 PolChemDef::getIsotopicDataCstSPtr() const
433 {
434 422743 return msp_isotopicData;
435 }
436
437 /*!
438 \brief Returns the isotopic data as non-const shared pointer..
439 */
440 IsotopicDataSPtr
441 136 PolChemDef::getIsotopicDataSPtr()
442 {
443 136 return msp_isotopicData;
444 }
445
446 //////////////////// MODIFS //////////////////////
447 //////////////////// MODIFS //////////////////////
448
449 /*!
450 \brief Returns a const reference to the list of modifications.
451 */
452 const std::vector<ModifSPtr> &
453 13 PolChemDef::getModifsCstRef() const
454 {
455 13 return m_modifs;
456 }
457
458 /*!
459 \brief Returns a pointer to the list of modifications.
460 */
461 std::vector<ModifSPtr> &
462 PolChemDef::getModifsRef()
463 {
464 return m_modifs;
465 }
466
467 /*!
468 \brief Returns a pointer to the Modif instance known under \a name.
469
470 If no Modif by that \a name is known, nullptr is returned.
471 */
472 ModifCstSPtr
473 396 PolChemDef::getModifCstSPtrByName(const QString &name) const
474 {
475
2/2
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 1 times.
396 ModifsCstIterator the_iterator_cst = std::find_if(
476
10/12
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 396 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 395 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 395 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 395 times.
✓ Branch 13 taken 1 times.
✓ Branch 20 taken 396 times.
✗ Branch 21 not taken.
3560 m_modifs.cbegin(), m_modifs.cend(), [name](const auto &modif_csp) {
477 5115 return modif_csp->getName() == name;
478 });
479
480
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 392 times.
396 if(the_iterator_cst == m_modifs.cend())
481 4 return nullptr;
482
483 392 return (*the_iterator_cst);
484 }
485
486 /*!
487 \brief Returns the index of the \l Modif in the member container of
488 these instances or -1 if that was not found.
489
490 The search is performed using the \a name of the Modif.
491 */
492 int
493 PolChemDef::getModifIndexByName(const QString &name) const
494 {
495 ModifsCstIterator the_iterator_cst = std::find_if(
496 m_modifs.cbegin(), m_modifs.cend(), [name](const auto &modif_csp) {
497 bool same_name = (modif_csp->getName() == name);
498 return same_name;
499 });
500
501 if(the_iterator_cst == m_modifs.cend())
502 return -1;
503
504 return std::distance(m_modifs.cbegin(), the_iterator_cst);
505 }
506
507 //////////////////// MONOMERS //////////////////////
508 //////////////////// MONOMERS //////////////////////
509
510 /*!
511 \brief Returns a const reference to the list of modifications.
512 */
513 const std::vector<MonomerSPtr> &
514 13 PolChemDef::getMonomersCstRef() const
515 {
516 13 return m_monomers;
517 }
518
519 /*!
520 \brief Returns a pointer to the list of Monomer instances.
521 */
522 std::vector<MonomerSPtr> &
523 PolChemDef::getMonomersRef()
524 {
525 return m_monomers;
526 }
527
528 /*!
529 \brief Returns a pointer to the Monomer instance known under \a name.
530
531 If no Monomer by that \a name is known, nullptr is returned.
532 */
533 MonomerSPtr
534 10 PolChemDef::getMonomerCstSPtrByName(const QString &name) const
535 {
536
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 MonomersCstIterator the_iterator_cst = std::find_if(
537
10/12
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 9 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 9 times.
✓ Branch 13 taken 1 times.
✓ Branch 20 taken 10 times.
✗ Branch 21 not taken.
86 m_monomers.cbegin(), m_monomers.cend(), [name](const auto &monomer_csp) {
538 204 return monomer_csp->getName() == name;
539 });
540
541
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if(the_iterator_cst == m_monomers.cend())
542 4 return nullptr;
543
544 6 return (*the_iterator_cst);
545 }
546
547 /*!
548 \brief Returns a pointer to the Monomer instance known under \a code.
549
550 If no Monomer by that \a code is known, nullptr is returned.
551 */
552 MonomerSPtr
553 75381 PolChemDef::getMonomerCstSPtrByCode(const QString &code) const
554 {
555
1/2
✓ Branch 0 taken 75381 times.
✗ Branch 1 not taken.
75381 MonomersCstIterator the_iterator_cst = std::find_if(
556
6/12
✓ Branch 0 taken 75381 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 75381 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 75381 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 75381 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 75381 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 75381 times.
✗ Branch 21 not taken.
678429 m_monomers.cbegin(), m_monomers.cend(), [code](const auto &monomer_csp) {
557 738413 return monomer_csp->getCode() == code;
558 });
559
560
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 75366 times.
75381 if(the_iterator_cst == m_monomers.cend())
561 15 return nullptr;
562
563 75366 return (*the_iterator_cst);
564 }
565
566 /*!
567 \brief Returns the index of the \l Monomer in the member container of
568 these instances or -1 if that was not found.
569
570 The search is performed using the \a name of the Monomer.
571 */
572 int
573 PolChemDef::getMonomerIndexByName(const QString &name) const
574 {
575 MonomersCstIterator the_iterator_cst = std::find_if(
576 m_monomers.cbegin(), m_monomers.cend(), [name](const auto &monomer_csp) {
577 bool same_name = (monomer_csp->getName() == name);
578 return same_name;
579 });
580
581 if(the_iterator_cst == m_monomers.cend())
582 return -1;
583
584 return std::distance(m_monomers.cbegin(), the_iterator_cst);
585 }
586
587 /*!
588 \brief Returns the index of the \l Monomer in the member container of
589 these instances or -1 if that was not found.
590
591 The search is performed using the \a code of the Monomer.
592 */
593 int
594 PolChemDef::getMonomerIndexByCode(const QString &code) const
595 {
596 MonomersCstIterator the_iterator_cst = std::find_if(
597 m_monomers.cbegin(), m_monomers.cend(), [code](const auto &monomer_csp) {
598 bool same_code = (monomer_csp->getCode() == code);
599 return same_code;
600 });
601
602 if(the_iterator_cst == m_monomers.cend())
603 return -1;
604
605 return std::distance(m_monomers.cbegin(), the_iterator_cst);
606 }
607
608 //////////////////// CROSSLINKERS //////////////////////
609 //////////////////// CROSSLINKERS //////////////////////
610
611 /*!
612 \brief Returns a const reference to the list of modifications.
613 */
614 const std::vector<CrossLinkerSPtr> &
615 4 PolChemDef::getCrossLinkersCstRef() const
616 {
617 4 return m_crossLinkers;
618 }
619
620 /*!
621 \brief Returns a pointer to the list of CrossLinker instances.
622 */
623 std::vector<CrossLinkerSPtr> &
624 PolChemDef::getCrossLinkersRef()
625 {
626 return m_crossLinkers;
627 }
628
629 /*!
630 \brief Returns a pointer to the CrossLinker instance known under \a name.
631
632 If no CrossLinker by that \a name is known, nullptr is returned.
633 */
634 CrossLinkerCstSPtr
635 69 PolChemDef::getCrossLinkerCstSPtrByName(const QString &name) const
636 {
637
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 CrossLinkersCstIterator the_iterator_cst =
638 138 std::find_if(m_crossLinkers.cbegin(),
639 m_crossLinkers.cend(),
640
6/12
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 69 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 69 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 69 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 69 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 69 times.
✗ Branch 21 not taken.
621 [name](const auto &crossLinker_csp) {
641 121 bool same_name = (crossLinker_csp->getName() == name);
642 121 return same_name;
643 });
644
645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 if(the_iterator_cst == m_crossLinkers.cend())
646 return nullptr;
647
648 69 return (*the_iterator_cst);
649 }
650
651 //////////////////// CLEAVAGE AGENTS //////////////////////
652 //////////////////// CLEAVAGE AGENTS //////////////////////
653
654 /*!
655 \brief Returns a const reference to the list of modifications.
656 */
657 const std::vector<CleavageAgentSPtr> &
658 1 PolChemDef::getCleavageAgentsCstRef() const
659 {
660 1 return m_cleavageAgents;
661 }
662
663 /*!
664 \brief Returns a pointer to the list of CleavageAgent instances.
665 */
666 std::vector<CleavageAgentSPtr> &
667 PolChemDef::getCleavageAgentsRef()
668 {
669 return m_cleavageAgents;
670 }
671
672 /*!
673 \brief Returns a pointer to the CleavageAgent instance known under \a name.
674
675 If no CleavageAgent by that \a name is known, nullptr is returned.
676 */
677 CleavageAgentCstSPtr
678 8 PolChemDef::getCleavageAgentCstSPtrByName(const QString &name) const
679 {
680
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 CleavageAgentsCstIterator the_iterator_cst =
681 16 std::find_if(m_cleavageAgents.cbegin(),
682 m_cleavageAgents.cend(),
683
10/12
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 7 times.
✓ Branch 13 taken 1 times.
✓ Branch 20 taken 8 times.
✗ Branch 21 not taken.
68 [name](const auto &cleavage_agent_csp) {
684
6/14
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 5 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
12 bool same_name = (cleavage_agent_csp->getName() == name);
685 return same_name;
686 });
687
688
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if(the_iterator_cst == m_cleavageAgents.cend())
689 1 return nullptr;
690
691 7 return (*the_iterator_cst);
692 }
693
694 /*!
695 \brief Returns the index of the \l CleavageAgent in the member container of
696 these instances or -1 if that was not found.
697
698 The search is performed using the \a name of the CleavageAgent.
699 */
700 int
701 PolChemDef::getCleavageAgentIndexByName(const QString &name) const
702 {
703 CleavageAgentsCstIterator the_iterator_cst =
704 std::find_if(m_cleavageAgents.cbegin(),
705 m_cleavageAgents.cend(),
706 [name](const auto &cleavage_agent_csp) {
707 bool same_name = (cleavage_agent_csp->getName() == name);
708 return same_name;
709 });
710
711 if(the_iterator_cst == m_cleavageAgents.cend())
712 return -1;
713
714 return std::distance(m_cleavageAgents.cbegin(), the_iterator_cst);
715 }
716
717 //////////////////// FRAGMENTATION PATHWAYS //////////////////////
718 //////////////////// FRAGMENTATION PATHWAYS //////////////////////
719
720 /*!
721 \brief Returns a const reference to the list of modifications.
722 */
723 const std::vector<FragmentationPathwaySPtr> &
724 1 PolChemDef::getFragmentationPathwaysCstRef() const
725 {
726 1 return m_fragmentationPathways;
727 }
728
729 /*!
730 \brief Returns a pointer to the list of FragmentationPathway instances.
731 */
732 std::vector<FragmentationPathwaySPtr> &
733 PolChemDef::getFragmentationPathwaysRef()
734 {
735 return m_fragmentationPathways;
736 }
737
738 /*!
739 \brief Returns a pointer to the FragmentationPathway instance known under \a
740 name.
741
742 If no FragmentationPathway by that \a name is known, nullptr is returned.
743 */
744 FragmentationPathwayCstSPtr
745 4 PolChemDef::getFragmentationPathwayCstSPtrByName(const QString &name) const
746 {
747
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 FragmentationPathwaysCstIterator the_iterator_cst =
748 8 std::find_if(m_fragmentationPathways.cbegin(),
749 m_fragmentationPathways.cend(),
750
6/12
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 20 taken 4 times.
✗ Branch 21 not taken.
36 [name](const auto &fragmentation_pathway_csp) {
751 bool same_name =
752
8/14
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
7 (fragmentation_pathway_csp->getName() == name);
753 return same_name;
754 });
755
756
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(the_iterator_cst == m_fragmentationPathways.cend())
757 return nullptr;
758
759 4 return (*the_iterator_cst);
760 }
761
762 /*!
763 \brief Returns the index of the \l FragmentationPathway in the member container
764 of these instances or -1 if that was not found.
765
766 The search is performed using the \a name of the FragmentationPathway.
767 */
768 int
769 PolChemDef::getFragmentationPathwayIndexByName(const QString &name) const
770 {
771 FragmentationPathwaysCstIterator the_iterator_cst =
772 std::find_if(m_fragmentationPathways.cbegin(),
773 m_fragmentationPathways.cend(),
774 [name](const auto &cleavage_agent_csp) {
775 bool same_name = (cleavage_agent_csp->getName() == name);
776 return same_name;
777 });
778
779 if(the_iterator_cst == m_fragmentationPathways.cend())
780 return -1;
781
782 return std::distance(m_fragmentationPathways.cbegin(), the_iterator_cst);
783 }
784
785 /*!
786 \brief Constructs a string with the codes of all the \l{Monomer}s in this
787 PolChemDef instance.
788
789 The codes are delimited by the '@' character.
790
791 Returns true.
792 */
793 bool
794 PolChemDef::calculateDelimitedCodes()
795 {
796 // We have to produce a QString containing all the codes from the
797 // monomers known to this polymer chemistry definition.
798
799 m_delimitedCodes.clear();
800 m_delimitedCodes.append('@');
801
802 for(auto monomer_csp : m_monomers)
803 {
804
805 m_delimitedCodes.append(monomer_csp->getCode());
806 m_delimitedCodes.append('@');
807 }
808
809 // Close the string with a delim char:
810 m_delimitedCodes.append('@');
811
812 return true;
813 }
814
815 /*!
816 \brief Returns a string with the codes of all the \l{Monomer}s in this
817 PolChemDef instance.
818
819 The codes are delimited by the '@' character.
820 */
821 const QString &
822 PolChemDef::getDelimitedCodes()
823 {
824 if(m_delimitedCodes.isEmpty())
825 calculateDelimitedCodes();
826
827 return m_delimitedCodes;
828 }
829
830 /*!
831 \brief Returns a string list with the mass difference between all the
832 \l{Monomer}s in this PolChemDef instace.
833
834 If the difference is below the \a threshold, the difference is added to
835 the string list, otherwise it is skipped. The masses that are compared
836 between every two monomers is of \a mass_type.
837 */
838 QStringList
839 PolChemDef::differenceBetweenMonomers(double threshold,
840 Enums::MassType mass_type)
841 {
842 // qDebug()
843 // << "threshold" << threshold;
844
845 QStringList difference_list;
846
847 if(mass_type != Enums::MassType::MONO && mass_type != Enums::MassType::AVG)
848 {
849 qDebug() << "Please set the mass type "
850 "to either Enums::MassType::MONO or "
851 "Enums::MassType::AVG";
852 return difference_list;
853 }
854
855 // We iterate in the list of monomers and compute a difference of
856 // mass for each monomer with respect to all the other ones. If
857 // the mass difference is less or equal to the threshold, then the
858 // pair is returned.
859
860 if(m_monomers.size() < 2)
861 return difference_list;
862
863 MonomersCstIterator iterator_outer_loop_cst = m_monomers.cbegin();
864
865 while(iterator_outer_loop_cst != m_monomers.cend())
866 {
867 Monomer outer_monomer = *(*iterator_outer_loop_cst);
868
869 outer_monomer.calculateMasses(/*IsotopicDataCstSPtr*/ nullptr);
870
871 MonomersCstIterator iterator_inner_loop_cst = m_monomers.cbegin();
872
873 while(iterator_inner_loop_cst != m_monomers.cend())
874 {
875 if(*iterator_outer_loop_cst == *iterator_inner_loop_cst)
876 {
877 ++iterator_inner_loop_cst;
878 continue;
879 }
880
881 Monomer inner_monomer = *(*iterator_inner_loop_cst);
882
883 inner_monomer.calculateMasses(/*IsotopicDataCstSPtr*/ nullptr);
884
885 // At this point we have the masses for both monomers.
886
887 double mass_diff = 0;
888
889 if(mass_type == Enums::MassType::MONO)
890 {
891 mass_diff = outer_monomer.getMass(Enums::MassType::MONO) -
892 inner_monomer.getMass(Enums::MassType::MONO);
893 }
894 else
895 //(monoOrAvg == Enums::MassType::AVG)
896 {
897 mass_diff = outer_monomer.getMass(Enums::MassType::AVG) -
898 inner_monomer.getMass(Enums::MassType::AVG);
899 }
900
901 // At this point, make sure that diff is within the
902 // threshold. Note that to avoid duplicates, we remove all
903 // values that are negative.
904
905 if(mass_diff >= 0 && mass_diff <= threshold)
906 {
907 QString line = QString("%1 - %2 = %3")
908 .arg(outer_monomer.getName())
909 .arg(inner_monomer.getName())
910 .arg(mass_diff);
911
912 difference_list.append(line);
913 }
914 ++iterator_inner_loop_cst;
915 }
916 ++iterator_outer_loop_cst;
917 }
918
919 return difference_list;
920 }
921
922 //////////////// OPERATORS /////////////////////
923
924
925 /*!
926 \brief Returns true if this PolChemDef is equal to \a other, false otherwise.
927
928 The comparison is deep, with all the various chemical entities in the
929 various containers being compared (not their pointers, but the objects
930 themselves).
931
932 \note The names and the data file paths are not compared, because this
933 comparison operator is aimed at comparing the chemistries of the PolChemDef.
934 */
935 bool
936 1 PolChemDef::isChemicallyEquivalent(const PolChemDef &other) const
937 {
938
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(&other == this)
939 return true;
940
941 1 if(m_name != other.m_name)
942 {
943 1 qDebug() << "The names are not identical.";
944 }
945
946
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(m_leftCap != other.m_leftCap)
947 {
948 qDebug() << "The left caps are not identical.";
949 return false;
950 }
951
952
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(m_rightCap != other.m_rightCap)
953 {
954 qDebug() << "The right caps are not identical.";
955 return false;
956 }
957
958
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_codeLength != other.m_codeLength)
959 {
960 qDebug() << "The code lengths are not identical.";
961 return false;
962 }
963
964
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_delimitedCodes != other.m_delimitedCodes)
965 {
966 qDebug() << "The delimited codes are not identical.";
967 return false;
968 }
969
970
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(m_ionizer != other.m_ionizer)
971 {
972 qDebug() << "The ionizers are not identical.";
973 return false;
974 }
975
976
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if(msp_isotopicData != nullptr && other.msp_isotopicData != nullptr)
977 {
978 1 qDebug() << "Now checking the isotopic data";
979
980
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(*msp_isotopicData.get() != *other.msp_isotopicData.get())
981 {
982 qDebug() << "The isotopic data are not identical.";
983 return false;
984 }
985 }
986
987
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_modifs.size() != other.m_modifs.size())
988 {
989 qDebug() << "The modifs containers have not the same sizes.";
990 return false;
991 }
992
993 ModifsCstIterator this_modif_iterator_cst = m_modifs.cbegin();
994 ModifsCstIterator other_modif_iterator_cst = other.m_modifs.cbegin();
995
996
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
27 while(this_modif_iterator_cst != m_modifs.cend() &&
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 other_modif_iterator_cst != other.m_modifs.cend())
998 {
999
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 const Modif this_modif = *(*this_modif_iterator_cst);
1000
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 const Modif other_modif = *(*other_modif_iterator_cst);
1001
1002
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if(this_modif != other_modif)
1003 {
1004 qDebug() << "At least one modification is not identical in both "
1005 "PolChemDef entities.";
1006 return false;
1007 }
1008
1009 26 ++this_modif_iterator_cst;
1010 26 ++other_modif_iterator_cst;
1011 26 }
1012
1013 // qDebug() << "The Modif instances are identical.";
1014
1015
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_monomers.size() != other.m_monomers.size())
1016 {
1017 qDebug() << "The monomers containers have not the same sizes.";
1018 return false;
1019 }
1020
1021 MonomersCstIterator this_monomer_iterator_cst = m_monomers.cbegin();
1022 MonomersCstIterator other_monomer_iterator_cst = other.m_monomers.cbegin();
1023
1024
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
22 while(this_monomer_iterator_cst != m_monomers.cend() &&
1025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 other_monomer_iterator_cst != other.m_monomers.cend())
1026 {
1027
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 const Monomer this_monomer = *(*this_monomer_iterator_cst);
1028
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 const Monomer other_monomer = *(*other_monomer_iterator_cst);
1029
1030
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
21 if(this_monomer != other_monomer)
1031 {
1032 qDebug()
1033 << "At least one monomer is not identical in both PolChemDef "
1034 "entities.";
1035 return false;
1036 }
1037
1038 21 ++this_monomer_iterator_cst;
1039 21 ++other_monomer_iterator_cst;
1040 21 }
1041
1042 // qDebug() << "The Monomer instances are identical.";
1043
1044
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_crossLinkers.size() != other.m_crossLinkers.size())
1045 {
1046 qDebug() << "The cross-linkers containers have not the same sizes.";
1047 return false;
1048 }
1049
1050 CrossLinkersCstIterator this_cross_linker_iterator_cst =
1051 m_crossLinkers.cbegin();
1052 CrossLinkersCstIterator other_cross_linker_iterator_cst =
1053 other.m_crossLinkers.cbegin();
1054
1055
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
3 while(this_cross_linker_iterator_cst != m_crossLinkers.cend() &&
1056
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 other_cross_linker_iterator_cst != other.m_crossLinkers.cend())
1057 {
1058
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const CrossLinker this_cross_linker = *(*this_cross_linker_iterator_cst);
1059 2 const CrossLinker other_cross_linker =
1060
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 *(*other_cross_linker_iterator_cst);
1061
1062
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 if(this_cross_linker != other_cross_linker)
1063 {
1064 qDebug().noquote()
1065 << "At least one cross-linker is not identical in both "
1066 "PolChemDef entities: \n"
1067 << this_cross_linker.toString() << "\nvs\n"
1068 << other_cross_linker.toString();
1069 return false;
1070 }
1071
1072 2 ++this_cross_linker_iterator_cst;
1073 2 ++other_cross_linker_iterator_cst;
1074 2 }
1075
1076 // qDebug() << "The CrossLinker instances are identical.";
1077
1078
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_cleavageAgents.size() != other.m_cleavageAgents.size())
1079 {
1080 qDebug()
1081 << "The cleavage specifications containers have not the same sizes.";
1082 return false;
1083 }
1084
1085 CleavageAgentsCstIterator this_cleavage_agent_iterator_cst =
1086 m_cleavageAgents.cbegin();
1087 CleavageAgentsCstIterator other_cleavage_agent_iterator_cst =
1088 other.m_cleavageAgents.cbegin();
1089
1090
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 while(this_cleavage_agent_iterator_cst != m_cleavageAgents.cend() &&
1091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 other_cleavage_agent_iterator_cst != other.m_cleavageAgents.cend())
1092 {
1093
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 CleavageAgent this_cleavage_agent;
1094
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 this_cleavage_agent.initialize(*(*this_cleavage_agent_iterator_cst));
1095
1096
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 CleavageAgent other_cleavage_agent;
1097
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 other_cleavage_agent.initialize(*(*other_cleavage_agent_iterator_cst));
1098
1099
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if(this_cleavage_agent != other_cleavage_agent)
1100 {
1101 qDebug().noquote()
1102 << "At least one cleavage specification is not identical in "
1103 "both PolChemDef entities:\n"
1104 << this_cleavage_agent.toString() << "\nvs\n"
1105 << other_cleavage_agent.toString();
1106 return false;
1107 }
1108
1109 8 ++this_cleavage_agent_iterator_cst;
1110 8 ++other_cleavage_agent_iterator_cst;
1111 8 }
1112
1113 // qDebug() << "The CleavageAgent instances are identical.";
1114
1115
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(m_fragmentationPathways.size() != other.m_fragmentationPathways.size())
1116 {
1117 qDebug() << "The fragmentation specifications containers have not the "
1118 "same sizes.";
1119 return false;
1120 }
1121
1122 FragmentationPathwaysCstIterator this_fragmentation_pathway_iterator_cst =
1123 m_fragmentationPathways.cbegin();
1124 FragmentationPathwaysCstIterator other_fragmentation_pathway_iterator_cst =
1125 other.m_fragmentationPathways.cbegin();
1126
1127
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 while(this_fragmentation_pathway_iterator_cst !=
1128
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 m_fragmentationPathways.cend() &&
1129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 other_fragmentation_pathway_iterator_cst !=
1130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 other.m_fragmentationPathways.cend())
1131 {
1132 7 const FragmentationPathway this_fragmentation_pathway =
1133
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 *(*this_fragmentation_pathway_iterator_cst);
1134 7 const FragmentationPathway other_fragmentation_pathway =
1135
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 *(*other_fragmentation_pathway_iterator_cst);
1136
1137
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 if(this_fragmentation_pathway != other_fragmentation_pathway)
1138 {
1139 qDebug() << "At least one fragmentation specification is not "
1140 "identical in both PolChemDef entities.";
1141 return false;
1142 }
1143
1144 7 ++this_fragmentation_pathway_iterator_cst;
1145 7 ++other_fragmentation_pathway_iterator_cst;
1146 7 }
1147
1148 // qDebug() << "The FragmentationPathway instances are identical.";
1149
1150 return true;
1151 }
1152
1153 /*!
1154 \brief Returns true if this PolChemDef is equal to \a other, false otherwise.
1155
1156 The comparison is deep, with all the various chemical entities in the
1157 various containers being compared (not their pointers, but the objects
1158 themselves).
1159
1160 \note The names and the data file paths are not compared, because this
1161 comparison operator is aimed at comparing the chemistries of the PolChemDef.
1162 */
1163 bool
1164 PolChemDef::operator==(const PolChemDef &other) const
1165 {
1166 if(&other == this)
1167 return true;
1168
1169 if(!isChemicallyEquivalent(other))
1170 {
1171 qDebug() << "The PolChemDef are not chemically identical.";
1172 return false;
1173 }
1174
1175 if(m_name != other.m_name)
1176 {
1177 qDebug() << "The names are not identical.";
1178 }
1179
1180 if(m_xmlDataFilePath != other.m_xmlDataFilePath)
1181 {
1182 qDebug() << "The definition file paths are not identical.";
1183 }
1184
1185 if(m_isotopicDataFilePath != other.m_isotopicDataFilePath)
1186 {
1187 qDebug() << "The isotopic data file paths are not identical.";
1188 }
1189
1190 return true;
1191 }
1192
1193 /*!
1194 \brief Returns true if \c this and \a other differ.
1195
1196 Returns the negated result of operator==().
1197 */
1198 bool
1199 PolChemDef::operator!=(const PolChemDef &other) const
1200 {
1201 if(&other == this)
1202 return false;
1203
1204 return !operator==(other);
1205 }
1206
1207 /*!
1208 \brief Loads the isotopic data stored in the file \a file_path.
1209
1210 The data loaded from file are parsed and validated. Upon parsing of the
1211 file, the data are stored in the \a pol_chem_def_sp instance's isotopic
1212 data member.
1213
1214 If \a file_path is empty, it is reconstructed using the directory of the
1215 polymer chemistry definition and the fact that the isotopic data file name
1216 is "isotopic-data.dat".
1217
1218 Returns the count of parsed isotopes.
1219 */
1220 std::size_t
1221 69 PolChemDef::loadIsotopicData(PolChemDefSPtr pol_chem_def_sp,
1222 const QString &file_path)
1223 {
1224 // There are three situations:
1225 //
1226 // 1. The file_path exists and the data are loaded from there.
1227 //
1228 // 2. A file named isotopic-data.dat is found in the polymer chemistry
1229 // definition directory and it is loaded.
1230 //
1231 // 3. No file named isotopic-data.dat is found in the polymer chemistry
1232 // defintion directory and then data are loaded from the IsoSpec tables.
1233
1234 // If the provided argument is not empty and actually describes an
1235 // existing file, then save the data there.
1236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 QString local_file_path(file_path);
1237
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 QFileInfo local_file_info(local_file_path);
1238
1239
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
69 if(local_file_path.isEmpty() || !local_file_info.exists())
1240 {
1241 // qDebug() << "The provided file name" << file_path << "does not
1242 // exist.";
1243
1244 // Then try the member datum that provides the name of the file from
1245 // which to load the isotopic data.
1246
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 local_file_path = pol_chem_def_sp->getIsotopicDataFilePath();
1247
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 local_file_info.setFile(local_file_path);
1248
1249
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
69 if(local_file_path.isEmpty() || !local_file_info.exists())
1250 {
1251 // qDebug() << "The member datum file name " << local_file_path
1252 //<< "does not exist.";
1253
1254 // Last resort: deduce the isotopic data file name from the
1255 // directory of the polymer chemistry definition.
1256
1257
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 local_file_path = pol_chem_def_sp->deduceIsotopicDataFilePath();
1258
1259 // qDebug() << "Crafted the isotopic-data.dat file path:"
1260 //<< local_file_path;
1261
1262 // Finally for a later last check:
1263
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 local_file_info.setFile(local_file_path);
1264 }
1265 }
1266
1267 // qDebug() << "Allocating brand new isotopic data instance.";
1268
1269 // At this point we can delete the pre-exsting isotopic data.
1270
3/6
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 69 times.
✗ Branch 6 not taken.
69 pol_chem_def_sp->msp_isotopicData = std::make_shared<IsotopicData>();
1271
1272 // Allocate a specific handler to the kind of isotopic data (library
1273 // tables or user file).
1274
1275 69 std::size_t count = 0;
1276
1277
4/6
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 69 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 1 times.
69 if(local_file_path.isEmpty() || !local_file_info.exists())
1278 {
1279 // qDebug() << "Loading the isotopic data from the library.";
1280
1281 1 IsotopicDataLibraryHandler isotopic_data_handler(
1282
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 pol_chem_def_sp->msp_isotopicData);
1283
1284 1 qsizetype non_isotope_skipped_items = 0;
1285
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 count = isotopic_data_handler.loadData(non_isotope_skipped_items);
1286 1 }
1287 else
1288 {
1289 // qDebug() << "Loading the isotopic data from file:" << local_file_path;
1290
1291 68 IsotopicDataUserConfigHandler isotopic_data_handler(
1292
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
136 pol_chem_def_sp->msp_isotopicData);
1293
1294
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 count = isotopic_data_handler.loadData(local_file_path);
1295
1296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if(!count)
1297 {
1298 qDebug() << "Failed to load any isotopic data.";
1299 return false;
1300 }
1301
1302 // Now set the file path to the pol chem def.
1303
1304
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 pol_chem_def_sp->setIsotopicDataFilePath(local_file_path);
1305 68 }
1306
1307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 if(!count)
1308 {
1309 qDebug() << "Failed to load any isotopic data.";
1310 return false;
1311 }
1312
1313 return count;
1314 69 }
1315
1316 /*!
1317 \brief Writes the isotopic data in the \a pol_chem_def_sp PolChemDef
1318 instance to file \a file_path.
1319
1320 Returns the count of isotopes written to file.
1321 */
1322 std::size_t
1323 PolChemDef::writeIsotopicData(PolChemDefSPtr pol_chem_def_sp,
1324 const QString &file_path)
1325 {
1326 // There are three situations:
1327 //
1328 // 1. The file_path is not empty and the data are saved there.
1329 //
1330 // 2. The file_path is empty and the data are stored in the member file
1331 // path name (if not empty).
1332 //
1333 // 3. The file path is crafted from the directory of the polymer
1334 // chemistry definition.
1335
1336
1337 // Whatever the situation, the isotopic data handler we need here is
1338 // this one:
1339 IsotopicDataUserConfigHandler isotopic_data_handler(
1340 pol_chem_def_sp->msp_isotopicData);
1341
1342 // We'll instantiate the proper isotopic data handler depending on the
1343 // situation.
1344
1345 if(!file_path.isEmpty())
1346 {
1347 // We have a file name, store in there.
1348 pol_chem_def_sp->setIsotopicDataFilePath(file_path);
1349 return isotopic_data_handler.writeData(file_path);
1350 }
1351
1352 // Check the member datum.
1353
1354 if(!pol_chem_def_sp->m_isotopicDataFilePath.isEmpty())
1355 {
1356 // We have a file name, store in there.
1357 return isotopic_data_handler.writeData(
1358 pol_chem_def_sp->m_isotopicDataFilePath);
1359 }
1360
1361 // Last resort: deduce the isotopic data file name from the directory
1362 // of the polymer chemistry definition.
1363
1364 QString local_file_path = pol_chem_def_sp->getXmlDataDirPath();
1365 QFileInfo local_file_info(local_file_path);
1366
1367 if(!local_file_info.exists())
1368 qFatal(
1369 "Programming error. At this stage the name of the polymer "
1370 "chemistry definition file should be known.");
1371
1372 QDir dir(local_file_info.dir());
1373
1374 local_file_path =
1375 dir.absolutePath() + QDir::separator() + "isotopic-data.dat";
1376
1377 pol_chem_def_sp->setIsotopicDataFilePath(local_file_path);
1378
1379 return isotopic_data_handler.writeData(local_file_path);
1380 }
1381
1382 /*!
1383 \brief Parses the polymer chemistry definition file and updates \a
1384 pol_chem_def_sp accordingly.
1385
1386 Upon parsing of the file and validation of the data, the \a
1387 pol_chem_def_sp is updated, essentially initializing it with the data from
1388 the file.
1389
1390 Note that the \a pol_chem_def_sp should have a working set of isotopic
1391 data.
1392
1393 Returns true if the parsing was successful and false otherwise.
1394 */
1395 bool
1396 67 PolChemDef::renderXmlPolChemDefFileVersion1(PolChemDefSPtr pol_chem_def_sp)
1397 {
1398 67 qDebug() << "Rendering PolChemDef file VERSION 1.";
1399
1400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if(pol_chem_def_sp == nullptr && pol_chem_def_sp.get() == nullptr)
1401 qFatalStream()
1402 << "Programming error. The PolChemDef pointer cannot be nullptr.";
1403
1404 // qDebug() << "The PolChemDef *:" << pol_chem_def_sp.get()
1405 //<< "and usage:" << pol_chem_def_sp.use_count();
1406
1407 ///////////////////// ATTENTION ///////////////////
1408 // Before reading the polymer chemistry data file, we need to make sure
1409 // we actually have read the isotopic data!
1410
1411 // qDebug() << "First check if we have isotopic data ready.";
1412
1413
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
134 if(pol_chem_def_sp->getIsotopicDataSPtr() == nullptr)
1414 {
1415 // qDebug() << "No isotopic data found in the polymer chemistry "
1416 // "definition, need to load the data.";
1417
1418 // First read the data!
1419 std::size_t count = pol_chem_def_sp->loadIsotopicData(pol_chem_def_sp);
1420
1421 if(!count)
1422 qFatal("Programming error. The isotopic data could not be loaded.");
1423
1424 // qDebug() << "At this point the isotopic data were loaded fine
1425 // with"
1426 //<< count << "isotopes loaded.";
1427 }
1428
1429
1/2
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
67 QDomDocument doc("polChemDefData");
1430
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 QDomElement element;
1431
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 QDomElement child;
1432
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 QDomElement indentedChild;
1433
1434
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 QFile file(pol_chem_def_sp->m_xmlDataFilePath);
1435
1436 // qDebug() << "The polymer chemistry definition file:"
1437 // << pol_chem_def_sp->m_xmlDataFilePath;
1438
1439 // The general structure of the file we are reading is this:
1440 //
1441 // <polchemdefinition version="1">
1442 // <polchemdefdata">
1443 // <name>protein</name>
1444 // <leftcap>+H</leftcap>
1445 // <rightcap>+OH</rightcap>
1446 // <codelen>1</codelen>
1447 // <ionizerule>
1448 // <formula>+H</formula>
1449 // <charge>1</charge>
1450 // <level>1</level>
1451 // </ionizerule>
1452 // <monomers>
1453 // <mnm>
1454 // <name>Glycine</name>
1455 // <code>G</code>
1456 // <formula>C2H3NO</formula>
1457 // </mnm>
1458 // </monomers>
1459 // <modifs>
1460 // <mdf>
1461 // <name>Phosphorylation</name>
1462 // <formula>-H+H2PO3</formula>
1463 // </mdf>
1464 // </modifs>
1465 // <cleavespecs>
1466 // <cls>
1467 // <name>CyanogenBromide</name>
1468 // <pattern>M/</pattern>
1469 // <clr>
1470 // <re-mnm-code>M</re-mnm-code>
1471 // <re-formula>-CH2S+O</re-formula>
1472 // </clr>
1473 // </cls>
1474 // </cleavespecs>
1475 // <fragspecs>
1476 // <fgs>
1477 // <name>a</name>
1478 // <end>LE</end>
1479 // <formula>-C1O1</formula>
1480 // <fgr>
1481 // <name>a-fgr-1</name>
1482 // <formula>+H200</formula>
1483 // <prev-mnm-code>E</prev-mnm-code>
1484 // <this-mnm-code>D</this-mnm-code>
1485 // <next-mnm-code>F</next-mnm-code>
1486 // <comment>comment here!</comment>
1487 // </fgr>
1488 // </fgs>
1489 // </fragspecs>
1490 // </polchemdefdata>
1491 // </polchemdefinition>
1492
1493
1494
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
67 if(!file.open(QIODevice::ReadOnly))
1495 return false;
1496
1497
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
67 if(!doc.setContent(&file))
1498 {
1499 qDebug() << "Failed to set doc content.";
1500
1501 file.close();
1502 return false;
1503 }
1504
1505
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 file.close();
1506
1507 // qDebug() << "Closed the polymer chemistry definition file.";
1508
1509
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 element = doc.documentElement();
1510
1511
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(element.tagName() != "polchemdefinition")
1512 {
1513 qDebug() << "Polymer chemistry definition file is erroneous\n";
1514 return false;
1515 }
1516
1517 ///////////////////////////////////////////////
1518 // Check the version of the document.
1519
1520 67 QString text;
1521
1522
3/6
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 67 times.
67 if(!element.hasAttribute("version"))
1523 text = "1";
1524 else
1525
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 text = element.attribute("version");
1526
1527 67 qDebug() << "The format of the definition:" << text;
1528
1529 67 bool ok = false;
1530
1531
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 int version = text.toInt(&ok, 10);
1532
1533
2/4
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
67 if(version != 1 || !ok)
1534 {
1535 qDebug() << "Polymer chemistry definition file has bad "
1536 "version number:"
1537 << version;
1538
1539 return false;
1540 }
1541
1542 //////////////////////////////////////////////
1543 // <polymer chemistry data>
1544
1545
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = element.firstChildElement();
1546
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "polchemdefdata")
1547 {
1548 qDebug() << "Polymer chemistry definition file is erroneous\n";
1549 return false;
1550 }
1551
1552 // <name>
1553
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.firstChildElement();
1554
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "name")
1555 return false;
1556
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 pol_chem_def_sp->m_name = child.text();
1557
1558 // <leftcap>
1559
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1560
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "leftcap")
1561 return false;
1562
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 pol_chem_def_sp->m_leftCap.setActionFormula(child.text());
1563
1564 // <rightcap>
1565
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1566
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "rightcap")
1567 return false;
1568
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 pol_chem_def_sp->m_rightCap.setActionFormula(child.text());
1569
1570 // <codelen>
1571
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1572
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "codelen")
1573 return false;
1574 67 ok = false;
1575
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
134 pol_chem_def_sp->m_codeLength = child.text().toInt(&ok);
1576
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
67 if(pol_chem_def_sp->m_codeLength == 0 && !ok)
1577 return false;
1578 67 qDebug() << "Now set the code length to" << pol_chem_def_sp->m_codeLength;
1579
1580 // <ionizerule>
1581
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1582
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "ionizerule")
1583 return false;
1584
1585 // It is essential that we endow the Ionizer with the IsotopicData !
1586
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
67 pol_chem_def_sp->m_ionizer.setIsotopicDataCstSPtr(
1587
1/3
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
67 pol_chem_def_sp->getIsotopicDataCstSPtr());
1588
1589 // Now we can render the Ionizer by looking into the <ionizerule> XML
1590 // element.
1591
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
67 if(!pol_chem_def_sp->m_ionizer.renderXmlIonizeRuleElement(child))
1592 return false;
1593
1594 // Finally, we have to ascertain that the Ionizer is valid.
1595 67 ErrorList error_list;
1596
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
67 if(!pol_chem_def_sp->m_ionizer.validate(&error_list))
1597 {
1598 qCritical() << "The Ionizer is invalid, with errors:"
1599 << Utils::joinErrorList(error_list, ", ");
1600 return false;
1601 }
1602
1603 67 qDebug() << "Now starting the rendering of the <monomers> element.";
1604
1605 // <monomers>
1606
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1607
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "monomers")
1608 return false;
1609
1610
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 indentedChild = child.firstChildElement();
1611
3/4
✓ Branch 1 taken 1474 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1407 times.
✓ Branch 4 taken 67 times.
1474 while(!indentedChild.isNull())
1612 {
1613 1407 qDebug() << "Now rendering one of all the mnm elements.";
1614
1615
2/4
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1407 times.
2814 if(indentedChild.tagName() != "mnm")
1616 {
1617 qCritical() << "The expected <mnm> element was not found.";
1618 return false;
1619 }
1620
1621 // Constructing a Monomer using the XML element ensures
1622 // that the masses are properly calculated for it, so
1623 // that MonomerCstSPtr point to fully qualified Monomer
1624 // instances that properly play the role of reference
1625 // throughout the chemical entities that involve Monomer
1626 // instances in the context of this PolChemDef.
1627
1/2
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
1407 MonomerSPtr monomer_sp =
1628 1407 std::make_shared<Monomer>(pol_chem_def_sp, indentedChild, version);
1629
1630
2/4
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1407 times.
1407 if(!monomer_sp->isValid())
1631 {
1632 qDebug() << "Failed to render mnm element.";
1633
1634 monomer_sp.reset();
1635 return false;
1636 }
1637
1638
1/2
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
1407 pol_chem_def_sp->m_monomers.push_back(monomer_sp);
1639
1640
3/8
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1407 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1407 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
2814 indentedChild = indentedChild.nextSiblingElement();
1641 1407 }
1642
1643 67 qDebug() << "Size of MonomerList:"
1644 << pol_chem_def_sp->getMonomersCstRef().size()
1645 << "pol chem def usage:" << pol_chem_def_sp.use_count();
1646
1647 67 qDebug() << "Now starting the rendering of the <modifs> element.";
1648
1649 // <modifs>
1650
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1651
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "modifs")
1652 return false;
1653
1654
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 indentedChild = child.firstChildElement();
1655
3/4
✓ Branch 1 taken 1809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1742 times.
✓ Branch 4 taken 67 times.
1809 while(!indentedChild.isNull())
1656 {
1657
2/4
✓ Branch 1 taken 1742 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1742 times.
✗ Branch 5 not taken.
3484 if(indentedChild.tagName() != "mdf")
1658 return false;
1659
1660
1/2
✓ Branch 1 taken 1742 times.
✗ Branch 2 not taken.
1742 ModifSPtr modif_sp =
1661 1742 std::make_shared<Modif>(pol_chem_def_sp, indentedChild, version);
1662
1663
2/4
✓ Branch 1 taken 1742 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1742 times.
1742 if(!modif_sp->isValid())
1664 {
1665 qCritical()
1666 << "Failed to render the Modif instance from an XML <mdf> element.";
1667 modif_sp.reset();
1668 return false;
1669 }
1670
1671
1/2
✓ Branch 1 taken 1742 times.
✗ Branch 2 not taken.
1742 pol_chem_def_sp->m_modifs.push_back(modif_sp);
1672
1673
3/8
✓ Branch 1 taken 1742 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1742 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1742 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
3484 indentedChild = indentedChild.nextSiblingElement();
1674 1742 }
1675
1676 67 qDebug() << "Size of ModifList:" << pol_chem_def_sp->getModifsCstRef().size()
1677 << "pol chem def usage:" << pol_chem_def_sp.use_count();
1678
1679 67 qDebug() << "Now starting the rendering of the <crosslinkers> element.";
1680
1681 // <crosslinkers>
1682 // Note that crosslinkers have appeared since version 3.
1683
1684
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1685
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "crosslinkers")
1686 return false;
1687
1688
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 indentedChild = child.firstChildElement();
1689
3/4
✓ Branch 1 taken 201 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 134 times.
✓ Branch 4 taken 67 times.
201 while(!indentedChild.isNull())
1690 {
1691
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
268 if(indentedChild.tagName() != "clk")
1692 return false;
1693
1694
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 CrossLinkerSPtr crossLinker_sp =
1695 134 std::make_shared<CrossLinker>(pol_chem_def_sp, indentedChild, version);
1696
1697
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 134 times.
134 if(!crossLinker_sp->isValid())
1698 {
1699 qCritical() << "Failed to render the CrossLinker instance from an "
1700 "XML <clk> element.";
1701 crossLinker_sp.reset();
1702 return false;
1703 }
1704
1705
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 pol_chem_def_sp->m_crossLinkers.push_back(crossLinker_sp);
1706
1707 134 qDebug() << "Rendered CrossLinker: " << crossLinker_sp->getName()
1708 << "with formula:" << crossLinker_sp->getFormula()
1709 << "with masses:"
1710 << crossLinker_sp->getMass(Enums::MassType::MONO) << "/"
1711 << crossLinker_sp->getMass(Enums::MassType::AVG);
1712
1713
3/8
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 134 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
268 indentedChild = indentedChild.nextSiblingElement();
1714 134 }
1715
1716 67 qDebug() << "Size of CrossLinker container:"
1717 << pol_chem_def_sp->getCrossLinkersCstRef().size()
1718 << "pol chem def usage:" << pol_chem_def_sp.use_count();
1719
1720 67 qDebug() << "Now starting the rendering of the <cleavespecs> element.";
1721
1722 // <cleavespecs>
1723
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1724
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "cleavespecs")
1725 {
1726 qCritical() << "Failed to load PolChemDef file: <cleavespecs> element "
1727 "not found.";
1728 return false;
1729 }
1730
1731
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 indentedChild = child.firstChildElement();
1732
3/4
✓ Branch 1 taken 603 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 536 times.
✓ Branch 4 taken 67 times.
603 while(!indentedChild.isNull())
1733 {
1734
2/4
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 536 times.
1072 if(indentedChild.tagName() != "cls")
1735 {
1736 qCritical()
1737 << "Failed to load PolChemDef file: <cls> element not found.";
1738 return false;
1739 }
1740
1741
1/2
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
536 CleavageAgentSPtr cleavage_agent_sp = std::make_shared<CleavageAgent>(
1742 536 pol_chem_def_sp, indentedChild, version);
1743
1744
2/4
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 536 times.
536 if(!cleavage_agent_sp->isValid())
1745 {
1746 qCritical() << "Failed to render the CleaveSpec instance from an "
1747 "XML <cls> element.";
1748 cleavage_agent_sp.reset();
1749 return false;
1750 }
1751
1752 // qDebug() << "Rendered CleavageAgent: " << cleavage_agent_sp->getName()
1753 // << "with pattern:" << cleavage_agent_sp->getPattern();
1754
1755
1/2
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
536 pol_chem_def_sp->m_cleavageAgents.push_back(cleavage_agent_sp);
1756
1757
1758
3/8
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 536 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 536 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
1072 indentedChild = indentedChild.nextSiblingElement();
1759 536 }
1760
1761 // qDebug() << "Size of CleavageAgent container:"
1762 // << pol_chem_def_sp->getCleavageAgentsCstRef().size()
1763 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
1764
1765 // qDebug() << "Now starting the rendering of the <fragspecs> element.";
1766
1767 // <fragspecs>
1768
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 child = child.nextSiblingElement();
1769
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
134 if(child.tagName() != "fragspecs")
1770 {
1771 qCritical()
1772 << "Failed to load PolChemDef file: <fragspecs> element not found.";
1773 return false;
1774 }
1775
1776
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 indentedChild = child.firstChildElement();
1777
3/4
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 469 times.
✓ Branch 4 taken 67 times.
536 while(!indentedChild.isNull())
1778 {
1779
2/4
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 469 times.
938 if(indentedChild.tagName() != "fgs")
1780 {
1781 qCritical()
1782 << "Failed to load PolChemDef file: <fgs> element not found.";
1783 return false;
1784 }
1785
1786
1/2
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
469 FragmentationPathwaySPtr fragmentation_pathway_sp =
1787 std::make_shared<FragmentationPathway>(
1788 469 pol_chem_def_sp, indentedChild, version);
1789
1790
2/4
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 469 times.
469 if(!fragmentation_pathway_sp->isValid())
1791 {
1792 qCritical() << "Failed to render the FragSpec instance from an "
1793 "XML <fgs> element.";
1794 fragmentation_pathway_sp.reset();
1795 return false;
1796 }
1797
1798 469 qDebug() << "Rendered FragmentationPathway: "
1799 << fragmentation_pathway_sp->getName();
1800
1801
1/2
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
469 pol_chem_def_sp->m_fragmentationPathways.push_back(
1802 fragmentation_pathway_sp);
1803
1804
3/8
✓ Branch 1 taken 469 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 469 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 469 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
938 indentedChild = indentedChild.nextSiblingElement();
1805 469 }
1806
1807 // qDebug() << "Size of FragmentationPathway container:"
1808 // << pol_chem_def_sp->getFragmentationPathwaysCstRef().size()
1809 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
1810
1811 // qDebug() << "Done rendering the PolChemDef file. Setting m_isValid to true "
1812 // "and returning it.";
1813
1814 67 pol_chem_def_sp->m_isValid = true;
1815
1816 67 return pol_chem_def_sp->m_isValid;
1817 134 }
1818
1819 /*!
1820 \brief Parses the polymer chemistry definition file and updates \a
1821 pol_chem_def_sp accordingly.
1822
1823 Upon parsing of the file and validation of the data, the \a
1824 pol_chem_def_sp is updated, essentially initializing it with the data from
1825 the file.
1826
1827 Note that the \a pol_chem_def_sp should have a working set of isotopic
1828 data.
1829
1830 Returns true if the parsing was successful and false otherwise.
1831 */
1832 bool
1833 1 PolChemDef::renderXmlPolChemDefFileVersion2(PolChemDefSPtr pol_chem_def_sp)
1834 {
1835 // qDebug() << "Rendering PolChemDef file VERSION 2.";
1836
1837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(pol_chem_def_sp == nullptr && pol_chem_def_sp.get() == nullptr)
1838 qFatalStream()
1839 << "Programming error. The PolChemDef pointer cannot be nullptr.";
1840
1841 // qDebug() << "The PolChemDef *:" << pol_chem_def_sp.get()
1842 //<< "and usage:" << pol_chem_def_sp.use_count();
1843
1844 ///////////////////// ATTENTION ///////////////////
1845 // Before reading the polymer chemistry data file, we need to make sure
1846 // we actually have read the isotopic data!
1847
1848 // qDebug() << "First check if we have isotopic data ready.";
1849
1850
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
2 if(pol_chem_def_sp->getIsotopicDataSPtr() == nullptr)
1851 {
1852 // qDebug() << "No isotopic data found in the polymer chemistry "
1853 // "definition, need to load the data.";
1854
1855 // First read the data!
1856 std::size_t count = pol_chem_def_sp->loadIsotopicData(pol_chem_def_sp);
1857
1858 if(!count)
1859 qFatal("Programming error. The isotopic data could not be loaded.");
1860
1861 // qDebug() << "At this point the isotopic data were loaded fine
1862 // with"
1863 //<< count << "isotopes loaded.";
1864 }
1865
1866
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 QDomDocument doc("polChemDefData");
1867
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QDomElement element;
1868
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QDomElement child;
1869
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QDomElement indentedChild;
1870
1871
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QFile file(pol_chem_def_sp->m_xmlDataFilePath);
1872
1873 // qDebug() << "The polymer chemistry definition file:"
1874 // << pol_chem_def_sp->m_xmlDataFilePath;
1875
1876 // The general structure of the file we are reading is this:
1877 //
1878 // <polchemdefinition version="1">
1879 // <polchemdefdata">
1880 // <name>protein</name>
1881 // <leftcap>+H</leftcap>
1882 // <rightcap>+OH</rightcap>
1883 // <codelen>1</codelen>
1884 // <ionizerule>
1885 // <formula>+H</formula>
1886 // <charge>1</charge>
1887 // <level>1</level>
1888 // </ionizerule>
1889 // <monomers>
1890 // <mnm>
1891 // <name>Glycine</name>
1892 // <code>G</code>
1893 // <formula>C2H3NO</formula>
1894 // </mnm>
1895 // </monomers>
1896 // <modifs>
1897 // <mdf>
1898 // <name>Phosphorylation</name>
1899 // <formula>-H+H2PO3</formula>
1900 // </mdf>
1901 // </modifs>
1902 // <cleavageagents>
1903 // <cla>
1904 // <name>CyanogenBromide</name>
1905 // <pattern>M/</pattern>
1906 // <clr>
1907 // <re-mnm-code>M</re-mnm-code>
1908 // <re-formula>-CH2S+O</re-formula>
1909 // </clr>
1910 // </cla>
1911 // </cleavageagents>
1912 // <fragmentationpathways>
1913 // <fgp>
1914 // <name>a</name>
1915 // <end>LE</end>
1916 // <formula>-C1O1</formula>
1917 // <fgr>
1918 // <name>a-fgr-1</name>
1919 // <formula>+H200</formula>
1920 // <prev-mnm-code>E</prev-mnm-code>
1921 // <this-mnm-code>D</this-mnm-code>
1922 // <next-mnm-code>F</next-mnm-code>
1923 // <comment>comment here!</comment>
1924 // </fgr>
1925 // </fgp>
1926 // </fragmentationpathways>
1927 // </polchemdefdata>
1928 // </polchemdefinition>
1929
1930
1931
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(!file.open(QIODevice::ReadOnly))
1932 return false;
1933
1934
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if(!doc.setContent(&file))
1935 {
1936 qDebug() << "Failed to set doc content.";
1937
1938 file.close();
1939 return false;
1940 }
1941
1942
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 file.close();
1943
1944 // qDebug() << "Closed the polymer chemistry definition file.";
1945
1946
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 element = doc.documentElement();
1947
1948
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(element.tagName() != "polchemdefinition")
1949 {
1950 qDebug() << "Polymer chemistry definition file is erroneous\n";
1951 return false;
1952 }
1953
1954 ///////////////////////////////////////////////
1955 // Check the version of the document.
1956
1957 1 QString text;
1958
1959
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
1 if(!element.hasAttribute("version"))
1960 text = "1";
1961 else
1962
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 text = element.attribute("version");
1963
1964 // qDebug() << "The format of the definition:" << text;
1965
1966 1 bool ok = false;
1967
1968
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 int version = text.toInt(&ok, 10);
1969
1970
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if(version != 2 || !ok)
1971 {
1972 // qDebug() << "Polymer chemistry definition file has bad "
1973 // "version number:"
1974 // << version;
1975
1976 return false;
1977 }
1978
1979 //////////////////////////////////////////////
1980 // <polymer chemistry data>
1981
1982
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = element.firstChildElement();
1983
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "polchemdefdata")
1984 {
1985 qDebug() << "Polymer chemistry definition file is erroneous\n";
1986 return false;
1987 }
1988
1989 // <name>
1990
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.firstChildElement();
1991
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "name")
1992 return false;
1993
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 pol_chem_def_sp->m_name = child.text();
1994
1995 // <leftcap>
1996
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
1997
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "leftcap")
1998 return false;
1999
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 pol_chem_def_sp->m_leftCap.setActionFormula(child.text());
2000
2001 // <rightcap>
2002
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2003
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "rightcap")
2004 return false;
2005
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 pol_chem_def_sp->m_rightCap.setActionFormula(child.text());
2006
2007 // <codelen>
2008
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2009
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "codelen")
2010 return false;
2011 1 ok = false;
2012
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 pol_chem_def_sp->m_codeLength = child.text().toInt(&ok);
2013
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if(pol_chem_def_sp->m_codeLength == 0 && !ok)
2014 return false;
2015 // qDebug() << "Set the code length to" << pol_chem_def_sp->m_codeLength;
2016
2017 // <ionizerule>
2018
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2019
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "ionizerule")
2020 return false;
2021
2022 // It is essential that we endow the Ionizer with the IsotopicData !
2023
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 pol_chem_def_sp->m_ionizer.setIsotopicDataCstSPtr(
2024
1/3
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 pol_chem_def_sp->getIsotopicDataCstSPtr());
2025
2026 // Now we can render the Ionizer by looking into the <ionizerule> XML
2027 // element.
2028
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(!pol_chem_def_sp->m_ionizer.renderXmlIonizeRuleElement(child))
2029 return false;
2030
2031 // Finally, we have to ascertain that the Ionizer is valid.
2032 1 ErrorList error_list;
2033
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if(!pol_chem_def_sp->m_ionizer.validate(&error_list))
2034 {
2035 qCritical() << "The Ionizer is invalid, with errors:"
2036 << Utils::joinErrorList(error_list, ", ");
2037 return false;
2038 }
2039
2040 // qDebug() << "Now starting the rendering of the <monomers> element.";
2041
2042 // <monomers>
2043
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2044
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "monomers")
2045 return false;
2046
2047
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 indentedChild = child.firstChildElement();
2048
3/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1 times.
22 while(!indentedChild.isNull())
2049 {
2050 // qDebug() << "Now rendering one of all the mnm elements.";
2051
2052
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
42 if(indentedChild.tagName() != "mnm")
2053 {
2054 qCritical() << "The expected <mnm> element was not found.";
2055 return false;
2056 }
2057
2058 // Constructing a Monomer using the XML element ensures
2059 // that the masses are properly calculated for it, so
2060 // that MonomerCstSPtr point to fully qualified Monomer
2061 // instances that properly play the role of reference
2062 // throughout the chemical entities that involve Monomer
2063 // instances in the context of this PolChemDef.
2064
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 MonomerSPtr monomer_sp =
2065 21 std::make_shared<Monomer>(pol_chem_def_sp, indentedChild, version);
2066
2067
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
21 if(!monomer_sp->isValid())
2068 {
2069 qDebug() << "Failed to render mnm element.";
2070
2071 monomer_sp.reset();
2072 return false;
2073 }
2074
2075
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 pol_chem_def_sp->m_monomers.push_back(monomer_sp);
2076
2077
3/8
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
42 indentedChild = indentedChild.nextSiblingElement();
2078 21 }
2079
2080 // qDebug() << "Size of MonomerList:"
2081 // << pol_chem_def_sp->getMonomersCstRef().size()
2082 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
2083
2084 // qDebug() << "Now starting the rendering of the <modifs> element.";
2085
2086 // <modifs>
2087
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2088
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "modifs")
2089 return false;
2090
2091
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 indentedChild = child.firstChildElement();
2092
3/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 1 times.
27 while(!indentedChild.isNull())
2093 {
2094
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 if(indentedChild.tagName() != "mdf")
2095 return false;
2096
2097
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 ModifSPtr modif_sp =
2098 26 std::make_shared<Modif>(pol_chem_def_sp, indentedChild, version);
2099
2100
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
26 if(!modif_sp->isValid())
2101 {
2102 qCritical()
2103 << "Failed to render the Modif instance from an XML <mdf> element.";
2104 modif_sp.reset();
2105 return false;
2106 }
2107
2108
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 pol_chem_def_sp->m_modifs.push_back(modif_sp);
2109
2110
3/8
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 26 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
52 indentedChild = indentedChild.nextSiblingElement();
2111 26 }
2112
2113 // qDebug() << "Size of ModifList:" << pol_chem_def_sp->getModifsCstRef().size()
2114 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
2115
2116 // qDebug() << "Now starting the rendering of the <crosslinkers> element.";
2117
2118 // <crosslinkers>
2119 // Note that crosslinkers have appeared since version 3.
2120
2121
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2122
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "crosslinkers")
2123 return false;
2124
2125
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 indentedChild = child.firstChildElement();
2126
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
3 while(!indentedChild.isNull())
2127 {
2128
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 if(indentedChild.tagName() != "clk")
2129 return false;
2130
2131
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CrossLinkerSPtr crossLinker_sp =
2132 2 std::make_shared<CrossLinker>(pol_chem_def_sp, indentedChild, version);
2133
2134
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 if(!crossLinker_sp->isValid())
2135 {
2136 qCritical() << "Failed to render the CrossLinker instance from an "
2137 "XML <clk> element.";
2138 crossLinker_sp.reset();
2139 return false;
2140 }
2141
2142
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pol_chem_def_sp->m_crossLinkers.push_back(crossLinker_sp);
2143
2144 // qDebug() << "Rendered CrossLinker: " << crossLinker_csp->getName()
2145 // << "with formula:" << crossLinker_csp->getFormula()
2146 // << "with masses:" <<
2147 // crossLinker_csp->getMass(Enums::MassType::MONO)
2148 // << "/" << crossLinker_csp->getMass(Enums::MassType::AVG);
2149
2150
3/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
4 indentedChild = indentedChild.nextSiblingElement();
2151 2 }
2152
2153 // qDebug() << "Size of CrossLinker container:"
2154 // << pol_chem_def_sp->getCrossLinkersCstRef().size()
2155 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
2156
2157 // qDebug() << "Now starting the rendering of the <cleavageagents> element.";
2158
2159 // <cleavageagents>
2160
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2161
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "cleavageagents")
2162 {
2163 qCritical() << "Failed to load PolChemDef file: <cleavageagents> element "
2164 "not found.";
2165 return false;
2166 }
2167
2168
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 indentedChild = child.firstChildElement();
2169
3/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 1 times.
9 while(!indentedChild.isNull())
2170 {
2171
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
16 if(indentedChild.tagName() != "cla")
2172 {
2173 qCritical()
2174 << "Failed to load PolChemDef file: <cla> element not found.";
2175 return false;
2176 }
2177
2178 // qDebug() << "Will allocate a new CleavageAgent instance->shared pointer.";
2179
2180
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 CleavageAgentSPtr cleavage_agent_sp = std::make_shared<CleavageAgent>(
2181 8 pol_chem_def_sp, indentedChild, version);
2182
2183
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if(!cleavage_agent_sp->isValid())
2184 {
2185 qCritical() << "Failed to render the CleavageAgent instance from an "
2186 "XML <cla> element.";
2187 cleavage_agent_sp.reset();
2188 return false;
2189 }
2190
2191
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 pol_chem_def_sp->m_cleavageAgents.push_back(cleavage_agent_sp);
2192
2193
3/8
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
16 indentedChild = indentedChild.nextSiblingElement();
2194 8 }
2195
2196 // qDebug() << "Size of CleavageAgent container:"
2197 // << pol_chem_def_sp->getCleavageAgentsCstRef().size()
2198 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
2199
2200 // qDebug()
2201 // << "Now starting the rendering of the <fragmentationpathways> element.";
2202
2203 // <fragmentationpathways>
2204
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 child = child.nextSiblingElement();
2205
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if(child.tagName() != "fragmentationpathways")
2206 return false;
2207
2208
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 indentedChild = child.firstChildElement();
2209
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1 times.
8 while(!indentedChild.isNull())
2210 {
2211
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
14 if(indentedChild.tagName() != "fgp")
2212 {
2213 qCritical()
2214 << "Failed to load PolChemDef file: <fgp> element not found.";
2215 return false;
2216 }
2217
2218
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 FragmentationPathwaySPtr fragmentation_pathway_sp =
2219 std::make_shared<FragmentationPathway>(
2220 7 pol_chem_def_sp, indentedChild, version);
2221
2222
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 if(!fragmentation_pathway_sp->isValid())
2223 {
2224 qCritical()
2225 << "Failed to render the FragmentationPathway instance from an "
2226 "XML <fgs> element.";
2227 fragmentation_pathway_sp.reset();
2228 return false;
2229 }
2230
2231
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 pol_chem_def_sp->m_fragmentationPathways.push_back(
2232 fragmentation_pathway_sp);
2233
2234
3/8
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
14 indentedChild = indentedChild.nextSiblingElement();
2235 7 }
2236
2237 // qDebug() << "Size of FragmentationPathway container:"
2238 // << pol_chem_def_sp->getFragmentationPathwaysCstRef().size()
2239 // << "pol chem def usage:" << pol_chem_def_sp.use_count();
2240
2241 // qDebug() << "Done rendering the PolChemDef file. Setting m_isValid to true "
2242 // "and returning it.";
2243
2244 1 pol_chem_def_sp->m_isValid = true;
2245
2246 1 return pol_chem_def_sp->m_isValid;
2247 2 }
2248
2249 /*!
2250 \brief Parses the polymer chemistry definition file and updates \a
2251 pol_chem_def_sp accordingly.
2252
2253 Upon parsing of the file and validation of the data, the \a
2254 pol_chem_def_sp is updated, essentially initializing it with the data from
2255 the file.
2256
2257 Note that the \a pol_chem_def_sp should have a working set of isotopic
2258 data.
2259
2260 Returns true if the parsing was successful and false otherwise.
2261 */
2262 bool
2263 68 PolChemDef::renderXmlPolChemDefFile(PolChemDefSPtr pol_chem_def_sp)
2264 {
2265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if(pol_chem_def_sp == nullptr && pol_chem_def_sp.get() == nullptr)
2266 qFatalStream()
2267 << "Programming error. The PolChemDef pointer cannot be nullptr.";
2268
2269 // qDebug() << "The PolChemDef *:" << pol_chem_def_sp.get()
2270 //<< "and usage:" << pol_chem_def_sp.use_count();
2271
2272 ///////////////////// ATTENTION ///////////////////
2273 // Before reading the polymer chemistry data file, we need to make sure
2274 // we actually have read the isotopic data!
2275
2276 // qDebug() << "First check if we have isotopic data ready.";
2277
2278
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 68 times.
136 if(pol_chem_def_sp->getIsotopicDataSPtr() == nullptr)
2279 {
2280 // qDebug() << "No isotopic data found in the polymer chemistry "
2281 // "definition, need to load the data.";
2282
2283 // First read the data!
2284 std::size_t count = pol_chem_def_sp->loadIsotopicData(pol_chem_def_sp);
2285
2286 if(!count)
2287 qFatal("Programming error. The isotopic data could not be loaded.");
2288
2289 // qDebug() << "At this point the isotopic data were loaded fine
2290 // with"
2291 //<< count << "isotopes loaded.";
2292 }
2293
2294
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 QDomDocument doc("polChemDefData");
2295
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 QDomElement element;
2296
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 QDomElement child;
2297
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 QDomElement indentedChild;
2298
2299
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 QFile file(pol_chem_def_sp->m_xmlDataFilePath);
2300
2301 // qDebug() << "The polymer chemistry definition file:"
2302 // << pol_chem_def_sp->m_xmlDataFilePath;
2303
2304 // The general structure of the file we are reading is this:
2305 //
2306 // <polchemdefinition version="1">
2307 // <polchemdefdata">
2308 // <name>protein</name>
2309 // <leftcap>+H</leftcap>
2310 // <rightcap>+OH</rightcap>
2311 // <codelen>1</codelen>
2312 // <ionizerule>
2313 // <formula>+H</formula>
2314 // <charge>1</charge>
2315 // <level>1</level>
2316 // </ionizerule>
2317 // <monomers>
2318 // <mnm>
2319 // <name>Glycine</name>
2320 // <code>G</code>
2321 // <formula>C2H3NO</formula>
2322 // </mnm>
2323 // </monomers>
2324 // <modifs>
2325 // <mdf>
2326 // <name>Phosphorylation</name>
2327 // <formula>-H+H2PO3</formula>
2328 // </mdf>
2329 // </modifs>
2330 // <cleavageagents>
2331 // <cla>
2332 // <name>CyanogenBromide</name>
2333 // <pattern>M/</pattern>
2334 // <clr>
2335 // <re-mnm-code>M</re-mnm-code>
2336 // <re-formula>-CH2S+O</re-formula>
2337 // </clr>
2338 // </cla>
2339 // </cleavageagents>
2340 // <fragmentationpathways>
2341 // <fgp>
2342 // <name>a</name>
2343 // <end>LE</end>
2344 // <formula>-C1O1</formula>
2345 // <fgr>
2346 // <name>a-fgr-1</name>
2347 // <formula>+H200</formula>
2348 // <prev-mnm-code>E</prev-mnm-code>
2349 // <this-mnm-code>D</this-mnm-code>
2350 // <next-mnm-code>F</next-mnm-code>
2351 // <comment>comment here!</comment>
2352 // </fgr>
2353 // </fgp>
2354 // </fragmentationpathways>
2355 // </polchemdefdata>
2356 // </polchemdefinition>
2357
2358
2359
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 68 times.
68 if(!file.open(QIODevice::ReadOnly))
2360 return false;
2361
2362
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
68 if(!doc.setContent(&file))
2363 {
2364 qDebug() << "Failed to set doc content.";
2365
2366 file.close();
2367 return false;
2368 }
2369
2370
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 file.close();
2371
2372 // qDebug() << "Closed the polymer chemistry definition file.";
2373
2374
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 68 times.
✗ Branch 5 not taken.
68 element = doc.documentElement();
2375
2376
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
136 if(element.tagName() != "polchemdefinition")
2377 {
2378 qDebug() << "Polymer chemistry definition file is erroneous\n";
2379 return false;
2380 }
2381
2382 ///////////////////////////////////////////////
2383 // Check the version of the document.
2384
2385 68 QString text;
2386
2387
3/6
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 68 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 68 times.
68 if(!element.hasAttribute("version"))
2388 text = "1";
2389 else
2390
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 68 times.
✗ Branch 5 not taken.
68 text = element.attribute("version");
2391
2392 // qDebug() << "The format of the definition:" << text;
2393
2394 68 bool ok = false;
2395
2396
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 int version = text.toInt(&ok, 10);
2397
2398
2/4
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
68 if(version < 1 || !ok)
2399 {
2400 qDebug() << "Polymer chemistry definition file has bad "
2401 "version number:"
2402 << version;
2403
2404 return false;
2405 }
2406
2407 //FIXME, done already file.close();
2408
2409 // qDebug() << "The version of the Polymer Chemistry Definition file is:"
2410 // << version;
2411
2412
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 1 times.
68 if(version == 1)
2413
2/4
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
134 return PolChemDef::renderXmlPolChemDefFileVersion1(pol_chem_def_sp);
2414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 else if(version == 2)
2415
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 return PolChemDef::renderXmlPolChemDefFileVersion2(pol_chem_def_sp);
2416
2417 return false;
2418 68 }
2419
2420 /*!
2421 \brief Returns a string with the XML DTD for a polymer chemistry
2422 definition file.
2423 */
2424 QString
2425 1 PolChemDef::formatXmlDtd()
2426 {
2427 1 QString string = QString(
2428 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
2429 "<!-- DTD for polymer definitions, used by the\n"
2430 "'massXpert' mass spectrometry application.\n"
2431 "Copyright 2006,2007,2008 Filippo Rusconi\n"
2432 "Licensed under the GNU GPL -->\n"
2433 "<!DOCTYPE polchemdefinition [\n"
2434 "<!ELEMENT polchemdefinition (polchemdefdata)>\n"
2435 "<!ATTLIST polchemdefinition version NMTOKEN #REQUIRED>\n"
2436 "<!ELEMENT polchemdefdata "
2437 "(name,leftcap,rightcap,codelen,ionizerule,monomers,modifs,"
2438 "crosslinkers,"
2439 "cleavageagents,fragmentationpathways)>\n"
2440 "<!ELEMENT ionizerule (formula,charge,level)>\n"
2441 "<!ELEMENT monomers (mnm*)>\n"
2442 "<!ELEMENT modifs (mdf*)>\n"
2443 "<!ELEMENT crosslinkers (clk*)>\n"
2444 "<!ELEMENT cleavageagents (cla*)>\n"
2445 "<!ELEMENT fragmentationpathways (fgp*)>\n"
2446 "<!ELEMENT mnm (name,code,formula)>\n"
2447 "<!ELEMENT mdf (name,formula,targets,maxcount)>\n"
2448 "<!ELEMENT clk (name,formula,modifname*)>\n"
2449 "<!ELEMENT cla (name,pattern,clr*)>\n"
2450 "<!ELEMENT fgp (name,end,formula,sidechaincontrib,comment?,fgr*)>\n"
2451 "<!ELEMENT clr "
2452 "(name,(le-mnm-code,le-formula)?,(re-mnm-code,re-formula)?)>\n"
2453 "<!ELEMENT fgr "
2454 "(name,formula,prev-mnm-code?,curr-mnm-code?,next-mnm-code?,comment?)"
2455 ">\n"
2456 "<!ELEMENT leftcap (#PCDATA)>\n"
2457 "<!ELEMENT rightcap (#PCDATA)>\n"
2458 "<!ELEMENT codelen (#PCDATA)>\n"
2459 "<!ELEMENT charge (#PCDATA)>\n"
2460 "<!ELEMENT maxcount (#PCDATA)>\n"
2461 "<!ELEMENT level (#PCDATA)>\n"
2462 "<!ELEMENT name (#PCDATA)>\n"
2463 "<!ELEMENT modifname (#PCDATA)>\n"
2464 "<!ELEMENT code (#PCDATA)>\n"
2465 "<!ELEMENT formula (#PCDATA)>\n"
2466 "<!ELEMENT sidechaincontrib (#PCDATA)>\n"
2467 "<!ELEMENT targets (#PCDATA)>\n"
2468 "<!ELEMENT pattern (#PCDATA)>\n"
2469 "<!ELEMENT end (#PCDATA)>\n"
2470 "<!ELEMENT le-mnm-code (#PCDATA)>\n"
2471 "<!ELEMENT re-mnm-code (#PCDATA)>\n"
2472 "<!ELEMENT le-formula (#PCDATA)>\n"
2473 "<!ELEMENT re-formula (#PCDATA)>\n"
2474 "<!ELEMENT comment (#PCDATA)>\n"
2475 "<!ELEMENT prev-mnm-code (#PCDATA)>\n"
2476 "<!ELEMENT curr-mnm-code (#PCDATA)>\n"
2477 "<!ELEMENT next-mnm-code (#PCDATA)>\n"
2478 1 "]>\n");
2479
2480 1 return string;
2481 }
2482
2483 /*!
2484 \brief Writes the polymer chemistry definition to file.
2485
2486 The file's name is from m_xmlDataFilePath.
2487
2488 Returns true if successful, false otherwise.
2489 */
2490 bool
2491 1 PolChemDef::writeXmlFile()
2492 {
2493 1 QString indent(" ");
2494 1 QString lead;
2495
2496 1 int offset = 0;
2497 1 int iter = 0;
2498
2499 // We are asked to send an xml description of the polymer chemistry
2500 // definition.
2501
2502
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QFile file(m_xmlDataFilePath);
2503
2504
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 if(!file.open(QIODevice::WriteOnly))
2505 {
2506 qDebug() << "Failed to open file" << m_xmlDataFilePath << "for writing.";
2507
2508 return false;
2509 }
2510
2511
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 QTextStream stream(&file);
2512
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 stream.setEncoding(QStringConverter::Utf8);
2513
2514 // The DTD
2515
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 stream << formatXmlDtd();
2516
2517
2518 // Open the <polchemdefinition> element.
2519
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 stream << QString("<polchemdefinition version=\"%1\">\n")
2520
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 .arg(POL_CHEM_DEF_FILE_FORMAT_VERSION);
2521
2522 // Prepare the lead.
2523 1 ++offset;
2524 1 lead.clear();
2525 1 iter = 0;
2526 1 while(iter < offset)
2527 {
2528
3/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 lead += indent;
2529 ++iter;
2530 }
2531
2532 // Open the <polchemdefdata> element.
2533
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<polchemdefdata>\n").arg(lead);
2534
2535 // Prepare the lead.
2536 1 ++offset;
2537 1 lead.clear();
2538 1 iter = 0;
2539
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2540 {
2541
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2542 2 ++iter;
2543 }
2544
2545
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
2 stream << QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
2546
2547
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 stream << QString("%1<leftcap>%2</leftcap>\n")
2548
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 .arg(lead)
2549
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 .arg(m_leftCap.getActionFormula(/*with_title*/ true));
2550
2551
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 stream << QString("%1<rightcap>%2</rightcap>\n")
2552
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 .arg(lead)
2553
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 .arg(m_rightCap.getActionFormula(/*with_title*/ true));
2554
2555
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
2 stream << QString("%1<codelen>%2</codelen>\n").arg(lead).arg(m_codeLength);
2556
2557 // Before writing the ionization rule, set the level to 1. This
2558 // member datum is set to 0 in the constructor.
2559
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 m_ionizer.setLevel(1);
2560
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 stream << m_ionizer.formatXmlIonizeRuleElement(offset);
2561
2562
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<monomers>\n").arg(lead);
2563
2564 // Prepare the lead.
2565 1 ++offset;
2566 1 lead.clear();
2567 1 iter = 0;
2568
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
5 while(iter < offset)
2569 {
2570
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
2571 3 ++iter;
2572 }
2573
2574
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1 times.
22 for(const auto &monomer_csp : m_monomers)
2575
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
42 stream << monomer_csp->formatXmlMnmElement(offset);
2576
2577 // Prepare the lead.
2578 1 --offset;
2579 1 lead.clear();
2580 1 iter = 0;
2581
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2582 {
2583
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2584 2 ++iter;
2585 }
2586
2587
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</monomers>\n").arg(lead);
2588
2589
2590
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<modifs>\n").arg(lead);
2591
2592 // Prepare the lead.
2593 1 ++offset;
2594 1 lead.clear();
2595 1 iter = 0;
2596
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
5 while(iter < offset)
2597 {
2598
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
2599 3 ++iter;
2600 }
2601
2602
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
27 for(const auto &modif_csp : m_modifs)
2603
2/4
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 stream << modif_csp->formatXmlMdfElement(offset);
2604
2605 // Prepare the lead.
2606 1 --offset;
2607 1 lead.clear();
2608 1 iter = 0;
2609
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2610 {
2611
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2612 2 ++iter;
2613 }
2614
2615
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</modifs>\n").arg(lead);
2616
2617
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<crosslinkers>\n").arg(lead);
2618
2619 // Prepare the lead.
2620 1 ++offset;
2621 1 lead.clear();
2622 1 iter = 0;
2623
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
5 while(iter < offset)
2624 {
2625
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
2626 3 ++iter;
2627 }
2628
2629
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for(const auto &cross_linker_csp : m_crossLinkers)
2630
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 stream << cross_linker_csp->formatXmlClkElement(offset);
2631
2632 // Prepare the lead.
2633 1 --offset;
2634 1 lead.clear();
2635 1 iter = 0;
2636
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2637 {
2638
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2639 2 ++iter;
2640 }
2641
2642
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</crosslinkers>\n").arg(lead);
2643
2644
2645
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<cleavageagents>\n").arg(lead);
2646
2647 // Prepare the lead.
2648 1 ++offset;
2649 1 lead.clear();
2650 1 iter = 0;
2651
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
5 while(iter < offset)
2652 {
2653
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
2654 3 ++iter;
2655 }
2656
2657
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for(const auto &cleavage_agent_csp : m_cleavageAgents)
2658
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
16 stream << cleavage_agent_csp->formatXmlClaElement(offset);
2659
2660 // Prepare the lead.
2661 1 --offset;
2662 1 lead.clear();
2663 1 iter = 0;
2664
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2665 {
2666
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2667 2 ++iter;
2668 }
2669
2670
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</cleavageagents>\n").arg(lead);
2671
2672
2673
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1<fragmentationpathways>\n").arg(lead);
2674
2675
2676 // Prepare the lead.
2677 1 ++offset;
2678 1 lead.clear();
2679 1 iter = 0;
2680
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
5 while(iter < offset)
2681 {
2682
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
2683 3 ++iter;
2684 }
2685
2686
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 for(const auto &fragmentation_pathway_csp : m_fragmentationPathways)
2687
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 stream << fragmentation_pathway_csp->formatXmlFgpElement(offset);
2688
2689 // Prepare the lead.
2690 1 --offset;
2691 1 lead.clear();
2692 1 iter = 0;
2693
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
4 while(iter < offset)
2694 {
2695
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 lead += indent;
2696 2 ++iter;
2697 }
2698
2699
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</fragmentationpathways>\n").arg(lead);
2700
2701 // Prepare the lead.
2702 1 --offset;
2703 1 lead.clear();
2704 1 iter = 0;
2705 1 while(iter < offset)
2706 {
2707
3/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 lead += indent;
2708 ++iter;
2709 }
2710
2711
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</polchemdefdata>\n").arg(lead);
2712
2713 // Prepare the lead.
2714 1 --offset;
2715 1 lead.clear();
2716 1 iter = 0;
2717 1 while(iter < offset)
2718 {
2719 lead += indent;
2720 ++iter;
2721 }
2722
2723
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 stream << QString("%1</polchemdefinition>\n").arg(lead);
2724
2725
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 file.close();
2726
2727 1 return true;
2728 1 }
2729
2730 /*!
2731 \brief Validates this PolChemDef instance by checking the validity of all its
2732 members data. Returns true if validation was successful, false otherwise. Any
2733 error is added to \a error_list_p if non-nullptr.
2734 */
2735 bool
2736 55 PolChemDef::validate(ErrorList *error_list_p) const
2737 {
2738 // So we can return immediately upon error.
2739 55 m_isValid = false;
2740
2741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(m_isotopicDataFilePath.isEmpty())
2742 {
2743 if(error_list_p != nullptr)
2744 error_list_p->push_back("The IsotopicData file path is empty.");
2745 return false;
2746 }
2747
2748 55 QFileInfo file_info(m_isotopicDataFilePath);
2749
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
55 if(!file_info.exists())
2750 {
2751 if(error_list_p != nullptr)
2752 error_list_p->push_back("The IsotopicData file cannot be found.");
2753 return false;
2754 }
2755
2756
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(msp_isotopicData == nullptr || msp_isotopicData.get() == nullptr)
2757 {
2758 if(error_list_p != nullptr)
2759 error_list_p->push_back("The IsotopicData are not available.");
2760 return false;
2761 }
2762
2763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(m_name.isEmpty())
2764 {
2765 if(error_list_p != nullptr)
2766 error_list_p->push_back("The PolChemDef name is empty.");
2767 return false;
2768 }
2769
2770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(m_xmlDataFilePath.isEmpty())
2771 {
2772 if(error_list_p != nullptr)
2773 error_list_p->push_back("The PolChemDef file path is empty.");
2774 return false;
2775 }
2776
2777
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 file_info.setFile(m_xmlDataFilePath);
2778
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
55 if(!file_info.exists())
2779 {
2780 if(error_list_p != nullptr)
2781 error_list_p->push_back("The PolChemDef file cannot be found.");
2782 return false;
2783 }
2784
2785
3/6
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 55 times.
110 if(!m_leftCap.validate(msp_isotopicData, error_list_p))
2786 {
2787 if(error_list_p != nullptr)
2788 error_list_p->push_back("The left cap formula failed to validate.");
2789 return false;
2790 }
2791
2792
3/6
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 55 times.
110 if(!m_rightCap.validate(msp_isotopicData, error_list_p))
2793 {
2794 if(error_list_p != nullptr)
2795 error_list_p->push_back("The right cap formula failed to validate.");
2796 return false;
2797 }
2798
2799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(m_codeLength < 1)
2800 {
2801 if(error_list_p != nullptr)
2802 error_list_p->push_back("The code length is less than 1.");
2803 return false;
2804 }
2805
2806
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
55 if(!m_ionizer.validate(error_list_p))
2807 {
2808 if(error_list_p != nullptr)
2809 error_list_p->push_back("The ionization rule failed to validate.");
2810 return false;
2811 }
2812
2813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(!m_modifs.size())
2814 {
2815 if(error_list_p != nullptr)
2816 error_list_p->push_back("There is not a single Modif instance.");
2817 return false;
2818 }
2819
2820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if(!m_monomers.size())
2821 {
2822 if(error_list_p != nullptr)
2823 error_list_p->push_back("There is not a single Monomer instance.");
2824 return false;
2825 }
2826
2827 // Good!
2828 55 m_isValid = true;
2829 55 return m_isValid;
2830 55 }
2831
2832 /*!
2833 \brief Returns the validity status of thie PolChemDef instance.
2834 */
2835 bool
2836 26701 PolChemDef::isValid() const
2837 {
2838 26701 return m_isValid;
2839 }
2840
2841
2842 } // namespace libXpertMassCore
2843 } // namespace MsXpS
2844