GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/Monomer.cpp
Date: 2025-11-19 15:26:11
Lines:
506/653
77.5%
Functions:
49/57
86.0%
Branches:
523/1138
46.0%

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 <vector>
36
37
38 /////////////////////// Qt includes
39 #include <QChar>
40 #include <QString>
41 #include <QUuid>
42
43
44 /////////////////////// Local includes
45 #include "MsXpS/libXpertMassCore/globals.hpp"
46 #include "MsXpS/libXpertMassCore/Monomer.hpp"
47 #include "MsXpS/libXpertMassCore/Formula.hpp"
48 #include "MsXpS/libXpertMassCore/Utils.hpp"
49
50
51 int monomerMetaTypeId = qRegisterMetaType<MsXpS::libXpertMassCore::Monomer>(
52 "MsXpS::libXpertMassCore::Monomer");
53
54
55 namespace MsXpS
56 {
57 namespace libXpertMassCore
58 {
59
60
61 /*!
62 \class MsXpS::libXpertMassCore::Monomer
63 \inmodule libXpertMassCore
64 \ingroup PolChemDefBuildingdBlocks
65 \inheaderfile Monomer.hpp
66
67 \brief The Monomer class provides abstractions to work with monomers.
68
69 In libmass, a momomer is an entity that is part of a polymer chemistry
70 definition. A monomer models a chemical entity that is part of a polymer.
71
72 In protein chemistry, that would be a \e{residue}, that is, an amino-acid that
73 has been polymerized into a residue chain (that is, a protein, or a peptide).
74 The chemical reaction that polymerizez an amino acid into an elongating protein
75 structure is a condensation, with loss of H2O from the amino acid to actually
76 lead to a what is called a \e{residue} of a monomer, or for short a \e{residue}.
77
78 \note The monomer, that is partly defined by its formula, has the formula of the
79 \e{residue}, not of the amino acid. This is always true, whatever the polymer
80 chemistry definition at hand: protein, saccharide, nucleic acid.
81 */
82
83
84 /*!
85 \variable MsXpS::libXpertMassCore::Monomer::mcsp_polChemDef
86
87 \brief The polymer chemistry definition that is the context in which the Monomer
88 instance exists.
89 */
90
91 /*!
92 \variable MsXpS::libXpertMassCore::Monomer::m_name
93
94 \brief The name of the monomer, like Lysine, Adenine.
95 */
96
97 /*!
98 \variable MsXpS::libXpertMassCore::Monomer::m_code
99
100 \brief The code of the monomer, like K for lysine, A for adenine.
101 */
102
103 /*!
104 \variable MsXpS::libXpertMassCore::Monomer::m_formula
105
106 \brief The formula of the monomer.
107 */
108
109 /*!
110 \variable MsXpS::libXpertMassCore::Monomer::m_modifs
111
112 \brief The container of \l Modif instances that are involved in the modification
113 of this Monomer.
114
115 \note
116
117 The Modif pointers stored in the m_modifs member are ModifSPtr pointers.
118 */
119
120 /*!
121 \variable MsXpS::libXpertMassCore::Monomer::m_isValid
122
123 \brief The validity status of the Monomer.
124 */
125
126 /*!
127 \typedef MsXpS::libXpertMassCore::MonomerRPtr
128 \relates MsXpS::libXpertMassCore::Monomer
129
130 Synonym for Monomer *.
131 */
132
133 /*!
134 \typedef MsXpS::libXpertMassCore::MonomerCstRPtr
135 \relates MsXpS::libXpertMassCore::Monomer
136
137 Synonym for const Monomer *.
138 */
139
140 /*!
141 \typedef MsXpS::libXpertMassCore::MonomerUPtr
142 \relates MsXpS::libXpertMassCore::Monomer
143
144 Synonym for std::unique_ptr<Monomer>.
145 */
146
147 /*!
148 \typedef MsXpS::libXpertMassCore::MonomerCstUPtr
149 \relates MsXpS::libXpertMassCore::Monomer
150
151 Synonym for std::unique_ptr<const Monomer>.
152 */
153
154 /*!
155 \typedef MsXpS::libXpertMassCore::MonomerSPtr
156 \relates MsXpS::libXpertMassCore::Monomer
157
158 Synonym for std::shared_ptr<Monomer>.
159 */
160
161 /*!
162 \typedef MsXpS::libXpertMassCore::MonomerCstSPtr
163 \relates MsXpS::libXpertMassCore::Monomer
164
165 Synonym for std::shared_ptr<const Monomer>.
166 */
167
168 /*!
169 \typedef MsXpS::libXpertMassCore::MonomerWPtr
170 \relates MsXpS::libXpertMassCore::Monomer
171
172 Synonym for std::weak_ptr<Monomer>.
173 */
174
175 /*!
176 \typedef MsXpS::libXpertMassCore::MonomerCstWPtr
177 \relates MsXpS::libXpertMassCore::Monomer
178
179 Synonym for std::weak_ptr<const Monomer>.
180 */
181
182 /*!
183 \typealias MsXpS::libXpertMassCore::UuidMonomerCstWPtrPair
184 \relates MsXpS::libXpertMassCore::Monomer
185
186 Synonym for std::pair<QString, MonomerCstWPtr> items.
187
188 These pairs are used to store a unique identifier (Uuid) string related to
189 a std::shared_ptr<const Monomer> type. This kind of pair is used in a
190 container in the \l CrossLink class. The fact that the std::shared_ptr is
191 converted to a std::weak_ptr is interesting because the item in the pair will
192 not increase the reference count.
193 */
194
195
196 /*!
197 \brief Constructs a monomer starting from an XML <mnm> \a element according to
198 \a version and using the reference polymer chemistry definition \a
199 pol_chem_def_csp.
200
201 This is the current format:
202 \code
203 <mnm>
204 <name>Glycine</name>
205 <code>G</code>
206 <formula>C2H3N1O1</formula>
207 </mnm>
208 \endcode
209 */
210 4317 Monomer::Monomer(PolChemDefCstSPtr pol_chem_def_csp,
211 const QDomElement &element,
212 4317 int version)
213
5/8
✓ Branch 3 taken 4317 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4317 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4317 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 9 times.
✓ Branch 12 taken 4308 times.
4317 : mcsp_polChemDef(pol_chem_def_csp)
214 {
215
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4308 times.
4317 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
216
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 qCritical() << "Constructing Monomer with no PolChemDef.";
217
218
3/4
✓ Branch 1 taken 4317 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 4287 times.
4317 if(!renderXmlMnmElement(element, version))
219
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 qCritical() << "Failed to fully render or validate the Monomer XML element "
220
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 "for construction of Monomer instance.";
221
222 // We cannot ask for validation because the polymer chemistry definition
223 // might be unavailable when using the XML element rendering.
224
225 // qDebug() << "Constructed Monomer" << m_name << ":" << toString();
226
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
4317 }
227
228
229 /*!
230 \brief Constructs a monomer with its member data set to \a name, \a code, \a
231 formula_string,
232 The \a pol_chem_def_csp and both masses \a mono and \a avg.
233
234 The member m_isValid validity status is set to the result of this Monomer
235 validation.
236 */
237 77154 Monomer::Monomer(PolChemDefCstSPtr pol_chem_def_csp,
238 const QString &name,
239 const QString &code,
240 const QString &formula_string,
241 double mono,
242 77154 double avg)
243 154308 : mcsp_polChemDef(pol_chem_def_csp),
244
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 76938 times.
77154 m_name(name),
245
2/2
✓ Branch 0 taken 76980 times.
✓ Branch 1 taken 174 times.
77154 m_code(code),
246
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 76971 times.
77154 m_formula(formula_string),
247 77154 m_mono(mono),
248
2/2
✓ Branch 2 taken 77136 times.
✓ Branch 3 taken 18 times.
154308 m_avg(avg)
249 {
250
3/4
✓ Branch 0 taken 77136 times.
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 77136 times.
✗ Branch 4 not taken.
77154 if(mcsp_polChemDef != nullptr && mcsp_polChemDef.get() != nullptr)
251 {
252 77136 ErrorList error_list;
253
1/2
✓ Branch 1 taken 77136 times.
✗ Branch 2 not taken.
77136 m_isValid = validate(&error_list);
254
255
2/2
✓ Branch 0 taken 76956 times.
✓ Branch 1 taken 180 times.
77136 if(!m_isValid)
256 {
257
2/4
✓ Branch 1 taken 76956 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76956 times.
✗ Branch 5 not taken.
153912 qCritical() << "Construction of Monomer with validation errors:\n"
258
3/6
✓ Branch 1 taken 76956 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76956 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 76956 times.
✗ Branch 8 not taken.
153912 << Utils::joinErrorList(error_list, ", ");
259 }
260 77136 }
261 else
262 m_isValid = false;
263
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
77154 }
264
265 /*!
266 \brief Constructs a monomer as a copy of \a other.
267 */
268 76950 Monomer::Monomer(const Monomer &other)
269 : PropListHolder(other),
270 153900 mcsp_polChemDef(other.mcsp_polChemDef),
271
1/2
✓ Branch 0 taken 76950 times.
✗ Branch 1 not taken.
76950 m_name(other.m_name),
272
1/2
✓ Branch 0 taken 76950 times.
✗ Branch 1 not taken.
76950 m_code(other.m_code),
273
2/2
✓ Branch 0 taken 76920 times.
✓ Branch 1 taken 30 times.
76950 m_formula(other.m_formula),
274 76950 m_mono(other.m_mono),
275
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 76947 times.
153900 m_avg(other.m_avg)
276 {
277
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 76947 times.
76950 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
278
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 qCritical() << "Copy-constructing Monomer with no PolChemDef.";
279
280 // We do a real duplication of the Modif instances.
281
2/2
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 76950 times.
76977 for(ModifSPtr modif_sp : other.m_modifs)
282
4/10
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
108 storeModif(std::make_shared<Modif>(*modif_sp));
283
284 76950 ErrorList error_list;
285
1/2
✓ Branch 1 taken 76950 times.
✗ Branch 2 not taken.
76950 m_isValid = validate(&error_list);
286
287
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 76917 times.
76950 if(!m_isValid)
288 {
289
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
66 qCritical() << "Copy-construction of Monomer with validation errors:\n"
290
3/6
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33 times.
✗ Branch 8 not taken.
66 << Utils::joinErrorList(error_list, ", ");
291 }
292
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
76950 }
293
294 /*!
295 \brief Destroys the monomer.
296 */
297 274386 Monomer::~Monomer()
298 {
299 274386 m_modifs.clear();
300
2/2
✓ Branch 5 taken 137175 times.
✓ Branch 6 taken 18 times.
548736 }
301
302
303 //////////////// THE POLCHEMDEF /////////////////////
304 /*!
305 \brief Sets the polymer chemistry definition to \a pol_chem_def_csp.
306 */
307 void
308 12 Monomer::setPolChemDefCstSPtr(PolChemDefCstSPtr &pol_chem_def_csp)
309 {
310 12 mcsp_polChemDef = pol_chem_def_csp;
311
312 12 ErrorList error_list;
313
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 m_isValid = validate(&error_list);
314
315
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if(!m_isValid)
316
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 qCritical() << "Failed to validate the Monomer with errors:\n"
317
3/6
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
24 << Utils::joinErrorList(error_list, ", ");
318 12 }
319
320 /*!
321 \brief Returns the polymer chemistry definition.
322 */
323 const PolChemDefCstSPtr &
324 42 Monomer::getPolChemDefCstSPtr() const
325 {
326 42 return mcsp_polChemDef;
327 }
328
329 //////////////// THE NAME /////////////////////
330
331 /*!
332 \brief Sets the \a name.
333 */
334 void
335 12 Monomer::setName(const QString &name)
336 {
337 12 m_name = name;
338
339 12 ErrorList error_list;
340
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 m_isValid = validate(&error_list);
341
342
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 if(!m_isValid)
343
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 qCritical() << "Failed to validate the Monomer with errors:\n"
344
3/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
18 << Utils::joinErrorList(error_list, ", ");
345 12 }
346
347 /*!
348 \brief Returns the name.
349 */
350 QString
351 708 Monomer::getName() const
352 {
353
2/2
✓ Branch 0 taken 696 times.
✓ Branch 1 taken 12 times.
708 return m_name;
354 }
355
356
357 //////////////// THE CODE /////////////////////
358 /*!
359 \brief Sets the code to \a code
360
361 */
362 void
363 42 Monomer::setCode(const QString &code)
364 {
365 42 m_code = code;
366
367 42 ErrorList error_list;
368
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 m_isValid = validate(&error_list);
369
370
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 9 times.
42 if(!m_isValid)
371
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
66 qCritical() << "Failed to validate the Monomer with errors:\n"
372
3/6
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 33 times.
✗ Branch 8 not taken.
66 << Utils::joinErrorList(error_list, ", ");
373 42 }
374
375
376 /*!
377 \brief Returns the code
378 */
379 QString
380 2269411 Monomer::getCode() const
381 {
382
2/2
✓ Branch 0 taken 2269399 times.
✓ Branch 1 taken 12 times.
2269411 return m_code;
383 }
384
385
386 /*!
387 \brief Checks the code's syntactic validity.
388
389 If \a code_length is not -1, then that length is used for the
390 check. Otherwise, the length from the polymer chemistry definition (if
391 available) is used.
392
393 The monomer code is verified and has to verify these criteria:
394
395 \list
396 \li It must be non-empty
397 \li Its character length has to be less or equal to the code length parameter
398 in the polymer chemistry definition (see PolChemDef::m_codeLength)
399 \li The first character is uppercase
400 \li All the remaining characters are lowercase
401 \endlist
402
403 Returns true if the code syntax checked successfully, false otherwise.
404
405 \sa validate()
406 */
407 bool
408 240672 Monomer::checkCodeSyntax(int code_length) const
409 {
410 240672 int local_code_length = code_length;
411
412
1/2
✓ Branch 0 taken 240672 times.
✗ Branch 1 not taken.
240672 if(local_code_length == -1)
413 {
414
2/2
✓ Branch 0 taken 240660 times.
✓ Branch 1 taken 12 times.
240672 if(mcsp_polChemDef != nullptr || mcsp_polChemDef.get() != nullptr)
415 {
416 240660 local_code_length = mcsp_polChemDef->getCodeLength();
417 }
418 else
419 {
420 24 qCritical() << "Checking code syntax with unlimited length because "
421
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 "Monomer has no PolChemDef.";
422 12 local_code_length = 1000;
423 }
424 }
425
426 // qDebug() << "Checking code syntax:" << m_code
427 // << "with code length:" << local_code_length;
428
429 // The code has to be at least one character long.
430
431 // The first letter in the code has to be uppercase.
432 // All the remaining authorized characters have to be
433 // lowercase.
434
435
4/4
✓ Branch 0 taken 240471 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 240447 times.
✓ Branch 3 taken 24 times.
240672 if(m_code.length() < 1 || m_code.length() > local_code_length)
436 {
437
2/4
✓ Branch 2 taken 225 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 225 times.
✗ Branch 6 not taken.
450 qCritical() << "The code has a length:" << m_code.length()
438
1/2
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
225 << "that does not match the expected code length:"
439
1/2
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
225 << local_code_length;
440 225 m_isValid = false;
441 225 return false;
442 }
443
444 // Note that the actual monomer code length might be less than the
445 // codeLength member datum in the polymer chemistry
446 // definition.
447
448 240447 QString regexp_string =
449
1/2
✓ Branch 2 taken 240447 times.
✗ Branch 3 not taken.
240447 QString("([A-Z])([a-z]{0,%1})").arg(local_code_length - 1);
450
1/2
✓ Branch 1 taken 240447 times.
✗ Branch 2 not taken.
240447 QRegularExpression regexp(regexp_string);
451
1/2
✓ Branch 1 taken 240447 times.
✗ Branch 2 not taken.
240447 QRegularExpressionMatch match = regexp.match(m_code);
452
453
1/2
✓ Branch 1 taken 240447 times.
✗ Branch 2 not taken.
240447 if(match.hasMatch())
454 {
455 // qDebug() << "First uppercase char:" << match.captured(1);
456 // qDebug() << "Remaining lowercase chars:" << match.captured(2);
457
458 return true;
459 }
460 else
461 {
462 qDebug() << "Failed to RegExp match the monomer code:" << m_code
463 << "against an expected code length of:" << local_code_length;
464 }
465
466 return false;
467
468 #if 0
469 // Old version
470 for(int iter = 0; iter < m_code.size(); ++iter)
471 {
472 // Test that the m_code length is not greater than codeLength.
473 if(iter + 1 > codeLength)
474 {
475 PolChemDefEntity::m_isValid = false;
476 return false;
477 }
478
479 // And now check the character syntax.
480 QChar curChar = m_code.at(iter);
481
482 if(iter == 0)
483 {
484 if(curChar.category() != QChar::Letter_Uppercase)
485 {
486 PolChemDefEntity::m_isValid = false;
487 return false;
488 }
489 }
490 else if(curChar.category() == QChar::Letter_Uppercase)
491 {
492 PolChemDefEntity::m_isValid = false;
493 return false;
494 }
495 }
496
497 return true;
498 #endif
499 240447 }
500
501 //////////////// THE FORMULA /////////////////////
502
503 /*!
504 \brief Sets the formula to \a formula_string.
505 */
506 void
507 9 Monomer::setFormula(const QString &formula_string)
508 {
509 9 m_formula = formula_string;
510
511 9 ErrorList error_list;
512
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 m_isValid = validate(&error_list);
513
514
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(!m_isValid)
515
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 qCritical() << "Failed to validate the Monomer with errors:\n"
516
3/6
✓ 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.
6 << Utils::joinErrorList(error_list, ", ");
517 9 }
518
519 /*
520 \brief Returns the formula of this Monomer.
521 */
522 const QString &
523 22098 Monomer::getFormula() const
524 {
525 22098 return m_formula;
526 }
527
528
529 //////////////// THE MODIFICATIONS /////////////////////
530
531 /*!
532 \brief Returns the container of Modif instances that modify this Monomer.
533 */
534 const std::vector<ModifSPtr> &
535 1809 Monomer::getModifsCstRef() const
536 {
537 1809 return m_modifs;
538 }
539
540
541 /*!
542 \brief Returns the list of Modif names in the same order as the Modif instances
543 are stored in the member container.
544 */
545 std::vector<QString>
546 Monomer::modifNamesInOrder() const
547 {
548 std::vector<QString> names;
549
550 for(const ModifSPtr &modif_sp : m_modifs)
551 names.push_back(modif_sp->getName());
552
553 return names;
554 }
555
556
557 /*
558 \brief Returns true if this monomer is a target of Modif \a modif, false
559 otherwise.
560 */
561 bool
562 1404 Monomer::isModifTarget(const Modif &modif) const
563 {
564 // Pure convenience function.
565 // qDebug() << "The modif:" << modif.toString();
566
567 1404 return modif.doesTargetMonomer(m_code);
568 }
569
570
571 /*!
572 \brief Modifies this monomer using \a modif.
573
574 These two verifications that are done:
575
576 \list
577
578 \li This monomer must be a target of \a modif;
579
580 \li The count of \a modif modifications in this monomer must be at most the
581 authorized count - 1, to accomodate this new modification [see
582 Modif::maxCount()].
583
584 \endlist
585
586 The two restrictions above can be overridden by setting \a override to true.
587
588 If errors are encountered, these are reported as strings in \a error_list_p.
589
590 Returns a string with the Uuid of the allocated Modif instance.
591 */
592 QString
593 408 Monomer::modify(const Modif &modif, bool override, ErrorList *error_list_p)
594 {
595
3/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 402 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
408 if(!isModifTarget(modif) && !override)
596 {
597 // This monomer is not a target for the modif, and no override
598 // is allowed.
599
600 6 error_list_p->push_back(
601 6 QString("%1 not target of Modif %2 (no overriding allowed)")
602
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 .arg(m_name)
603
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 .arg(modif.getName()));
604
605 6 return QString();
606 }
607
608 402 qDebug() << "Good, the monomer is target of this modif.";
609
610
1/2
✓ Branch 2 taken 402 times.
✗ Branch 3 not taken.
402 int count = countModifsByName(modif.getName());
611
612 402 qDebug() << "There are" << count << "modifs by that name.";
613
614
4/4
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 363 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 24 times.
402 if(count >= modif.getMaxCount() && !override)
615 {
616 // This monomer has already the maximum count of 'modif' objects.
617
618 24 error_list_p->push_back(
619 24 QString("%1 already modified %2 times (no overriding allowed)")
620
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 .arg(m_name)
621
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
48 .arg(count));
622
623 24 return QString();
624 }
625
626 // We do a real allocation of a new Modif instance.
627 378 qDebug() << "Now allocating ModifSPtr:" << modif.getName()
628 << "and calling storeModifSPtrAsUuid with it.";
629
630 378 ModifSPtr modif_sp = std::make_shared<Modif>(modif);
631
632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
378 if(modif_sp == nullptr || modif_sp.get() == nullptr)
633 qFatalStream() << "Failed to allocated new Modif object.";
634
635
1/2
✓ Branch 1 taken 378 times.
✗ Branch 2 not taken.
378 QString uuid = storeModif(modif_sp);
636
637 378 qDebug() << "The stored Modif:" << uuid << getModifForUuid(uuid)->getName();
638
639 378 return uuid;
640
1/2
✓ Branch 0 taken 378 times.
✗ Branch 1 not taken.
756 }
641
642
643 /*!
644 \brief Modifies this monomer using \a modif_name.
645
646 \a modif_name is used to find a Modif instance in the polymer chemistry
647 definition.
648
649 If such a Modif is found, it is used to modify this Monomer.
650
651 Returns a string with the Uuid of the allocated Modif instance.
652 */
653 QString
654 6 Monomer::modify(const QString &modif_name, bool override, ErrorList *error_list_p)
655 {
656 6 ModifCstSPtr modif_csp = mcsp_polChemDef->getModifCstSPtrByName(modif_name);
657
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(modif_csp == nullptr)
659 {
660 qCritical() << "Modif by name" << modif_name << "is not known.";
661 return QString();
662 }
663
664
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 return modify(*modif_csp, override, error_list_p);
665 6 }
666
667 /*!
668 \brief Removes from this monomer the Modif instance tagged using the Uuid \a
669 uuid string.
670
671 Returns true if the unmodification was actually performed, false otherwise.
672 */
673 bool
674 39 Monomer::unmodify(const QString &uuid)
675 {
676
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 std::vector<UuidModifWPtrPair>::iterator the_iterator = std::find_if(
677 m_uuidModifPairs.begin(),
678 m_uuidModifPairs.end(),
679
8/22
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 39 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 39 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 39 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 39 times.
✗ Branch 23 not taken.
390 [uuid](UuidModifWPtrPair &pair) { return pair.first == uuid; });
680
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if(the_iterator == m_uuidModifPairs.end())
682 {
683 qCritical() << "The modification was not found.";
684 return false;
685 }
686
687 // Sanity check
688 195 if((*the_iterator).second.expired() ||
689
5/10
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 39 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 39 times.
117 (*the_iterator).second.lock() == nullptr ||
690
2/6
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
78 !hasModif((*the_iterator).second.lock()))
691 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
692
693
3/6
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 39 times.
78 if(!removeModif((*the_iterator).second.lock()))
694 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
695
696 return true;
697 }
698
699
700 /*!
701 \brief Removes \e{all} the modification from this monomer.
702
703 Returns true if at least one Modif instance was removed, false if this Monomer
704 instance was not modified.
705 */
706 bool
707 6 Monomer::unmodify()
708 {
709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 std::size_t modif_count = m_modifs.size();
710
711 // Sanity check
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(m_modifs.size() != m_uuidModifPairs.size())
713 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
714
715 6 m_modifs.clear();
716
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_uuidModifPairs.clear();
717
718 6 return modif_count != 0;
719 }
720
721
722 /*!
723 \brief Returns true if this monomer has at least one modification, false
724 otherwise.
725 */
726 bool
727 50418 Monomer::isModified() const
728 {
729 50418 return m_modifs.size();
730 }
731
732 /*!
733 \brief Returns the count of modifications by name \a modif_name in this
734 monomer.
735 */
736 int
737 429 Monomer::countModifsByName(const QString &modif_name)
738 {
739
1/2
✓ Branch 0 taken 429 times.
✗ Branch 1 not taken.
429 int count = std::count_if(
740
4/8
✓ Branch 0 taken 429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 429 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 429 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 429 times.
✗ Branch 14 not taken.
3003 m_modifs.begin(), m_modifs.end(), [modif_name](const ModifSPtr &modif_sp) {
741 231 return modif_sp->getName() == modif_name;
742 429 });
743
744 429 return count;
745 }
746
747
748 //////////////// OPERATORS /////////////////////
749
750 /*!
751 \brief Assigns \a other's member data to this monomer.
752
753 The copy is deep, in particular with the mpa_modifList being copied.
754
755 Returns a reference to this monomer.
756 */
757 Monomer &
758 76929 Monomer::operator=(const Monomer &other)
759 {
760
1/2
✓ Branch 0 taken 76929 times.
✗ Branch 1 not taken.
76929 if(&other == this)
761 return *this;
762
763 76929 mcsp_polChemDef = other.mcsp_polChemDef;
764 76929 m_name = other.m_name;
765 76929 m_code = other.m_code;
766 76929 m_formula = other.m_formula;
767 76929 m_mono = other.m_mono;
768 76929 m_avg = other.m_avg;
769
770 // We want the modifs to be stored anew. So first clear.
771 76929 m_modifs.clear();
772
773 // We do a real duplication of the Modif instances.
774
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 76929 times.
76935 for(const ModifSPtr &modif_sp : other.m_modifs)
775
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
18 storeModif(std::make_shared<Modif>(*modif_sp));
776
777 76929 PropListHolder::operator=(other);
778
779 76929 ErrorList error_list;
780
781
1/2
✓ Branch 1 taken 76929 times.
✗ Branch 2 not taken.
76929 m_isValid = validate(&error_list);
782
783
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 76926 times.
76929 if(!m_isValid)
784 {
785
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 qCritical() << "Assignment of Monomer with validation errors:\n"
786
3/6
✓ 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.
6 << Utils::joinErrorList(error_list, ", ");
787 }
788
789 // qDebug() << "Assignment of Monomer produced *this Monomer:" << toString();
790
791 76929 return *this;
792 76929 }
793
794
795 /*!
796 \brief Returns true if this monomer and \a other are identical, false
797 otherwise.
798
799 The comparison involves also the comparison of the Modif objects in
800 mpa_modifList.
801 */
802 bool
803 273 Monomer::operator==(const Monomer &other) const
804 {
805
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 240 times.
273 if(&other == this)
806 return true;
807
808 // We cannot compare the PolChemDef, because that would cause
809 // an infinite loop: (each instance of this class in the PolChemDef would
810 // try to compare the PolChemDef...).
811
812
6/6
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 210 times.
✓ Branch 5 taken 6 times.
240 if(m_name != other.m_name || m_code != other.m_code ||
813
5/6
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 210 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 210 times.
✗ Branch 5 not taken.
456 m_formula != other.m_formula || m_mono != other.m_mono ||
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 m_avg != other.m_avg)
815 return false;
816
817
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 198 times.
210 if(m_modifs.size() != other.m_modifs.size())
818 {
819 // qDebug() << "The Modif containers have different sizes.";
820 return false;
821 }
822
823 // We do a deep Modif instance comparison.
824
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 12 times.
204 for(std::size_t iter = 0; iter < m_modifs.size(); ++iter)
825 {
826
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
12 if(*m_modifs.at(iter) != *other.m_modifs.at(iter))
827 {
828 // qDebug() << "At least one Modif instance differs in both Monomer
829 // instances.";
830 return false;
831 }
832 }
833
834 return true;
835 }
836
837
838 /*!
839 \brief Returns true if \c this monomer and \a other differ, false
840 otherwise.
841
842 Returns the negated result of operator==(other).
843 */
844 bool
845 5901 Monomer::operator!=(const Monomer &other) const
846 {
847
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 5682 times.
5901 if(&other == this)
848 return false;
849
850 219 return !operator==(other);
851 }
852
853
854 //////////////// VALIDATIONS /////////////////////
855 /*!
856 \brief Returns the Monomer instance from the polymer chemistry definition
857 registered in this instance.
858
859 The key to search the Monomer is this instance's member name.
860
861 If there is no PolChemDef available, nullptr is returned.
862
863 If no Monomer instance is found by this instance's name, nullptr is returned.
864 */
865 MonomerSPtr
866 6 Monomer::getFromPolChemDefByName() const
867 {
868
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
869 return nullptr;
870
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(m_name.isEmpty())
872 return nullptr;
873
874 6 return mcsp_polChemDef->getMonomerCstSPtrByName(m_name);
875 }
876
877 /*!
878 \brief Returns the Monomer instance from the polymer chemistry definition
879 registered in this instance.
880
881 The key to search the Monomer is this instance's member code.
882
883 If there is no PolChemDef available, nullptr is returned.
884
885 If no Monomer instance is found by this instance's code, nullptr is returned.
886 */
887 MonomerSPtr
888 6 Monomer::getFromPolChemDefByCode() const
889 {
890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
891 return nullptr;
892
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(m_code.isEmpty())
894 return nullptr;
895
896 6 return mcsp_polChemDef->getMonomerCstSPtrByCode(m_code);
897 }
898
899 /*!
900 \brief Returns the status of this Monomer instance the polymer chemistry
901 definition registered in this instance.
902
903 The key to search the Monomer is this instance's member name.
904
905 If there is no PolChemDef available,
906 Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE is returned.
907
908 If no Monomer instance is found by this instance's name,
909 Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN is returned, otherwise
910 Enums::PolChemDefEntityStatus::ENTITY_KNOWN is returned.
911 */
912 Enums::PolChemDefEntityStatus
913 21 Monomer::isKnownByNameInPolChemDef() const
914 {
915
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
21 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
916 return Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE;
917
918
4/4
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 6 times.
30 if(mcsp_polChemDef->getMonomerCstSPtrByName(m_name) != nullptr)
919 12 return Enums::PolChemDefEntityStatus::ENTITY_KNOWN;
920
921 return Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN;
922 }
923
924 /*!
925 \brief Returns the status of this Monomer instance the polymer chemistry
926 definition registered in this instance.
927
928 The key to search the Monomer is this instance's member code.
929
930 If there is no PolChemDef available,
931 Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE is returned.
932
933 If no Monomer instance is found by this instance's code,
934 Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN is returned, otherwise
935 Enums::PolChemDefEntityStatus::ENTITY_KNOWN is returned.
936 */
937 Enums::PolChemDefEntityStatus
938 120201 Monomer::isKnownByCodeInPolChemDef() const
939 {
940
1/2
✓ Branch 0 taken 120201 times.
✗ Branch 1 not taken.
120201 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
941 return Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE;
942
943
4/4
✓ Branch 1 taken 120198 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 120198 times.
✓ Branch 4 taken 3 times.
240399 if(mcsp_polChemDef->getMonomerCstSPtrByCode(m_code) != nullptr)
944 120198 return Enums::PolChemDefEntityStatus::ENTITY_KNOWN;
945
946 return Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN;
947 }
948
949
950 /*!
951 \brief Returns true if this monomer is valid, false otherwise.
952
953 Validation of the monomer occurs if:
954
955 \list
956 \li Its name is not empty
957 \li Its code is not empty and its syntax is correct
958 \li Its formula validates
959 \li Its modifications (if any) validate
960 \endlist
961
962 If errors are encountered, describing message are stored in \a error_list_p.
963
964 \sa checkCodeSyntax()
965 */
966 bool
967 236391 Monomer::validate(ErrorList *error_list_p) const
968 {
969
2/2
✓ Branch 0 taken 236364 times.
✓ Branch 1 taken 27 times.
236391 qsizetype error_count = error_list_p->size();
970
971
3/4
✓ Branch 0 taken 236364 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 236364 times.
✗ Branch 3 not taken.
472755 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
972
5/8
✓ Branch 1 taken 236364 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 236364 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 236364 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 27 times.
✓ Branch 8 taken 236364 times.
709119 mcsp_polChemDef->getIsotopicDataCstSPtr() == nullptr ||
973
8/14
✓ Branch 0 taken 236364 times.
✓ Branch 1 taken 27 times.
✓ Branch 3 taken 236364 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 236364 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 236364 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 236364 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 236364 times.
✓ Branch 13 taken 27 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
945510 mcsp_polChemDef->getIsotopicDataCstSPtr().get() == nullptr ||
974
4/8
✓ Branch 1 taken 236364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 236364 times.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
472755 !mcsp_polChemDef->getIsotopicDataCstSPtr()->size())
975 {
976 54 error_list_p->push_back("The PolChemDef or IsotopicData are not available");
977 54 qCritical()
978 << "The polymer chemistry definition member datum is nullptr or "
979 "its isotopic data are be either nullptr or empty. Monomer "
980 "validation "
981
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 "failed.";
982
983 27 m_isValid = false;
984 27 return false;
985 }
986
987
2/2
✓ Branch 0 taken 76944 times.
✓ Branch 1 taken 159420 times.
236364 if(m_name.isEmpty())
988 {
989
1/2
✓ Branch 2 taken 76944 times.
✗ Branch 3 not taken.
76944 qCritical() << "The Monomer name is empty.";
990 153888 error_list_p->push_back("The Monomer name is empty");
991 }
992
993 // qDebug() << "Now checking the code syntax.";
994
2/2
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 236112 times.
236364 if(!checkCodeSyntax())
995 {
996
1/2
✓ Branch 2 taken 252 times.
✗ Branch 3 not taken.
252 qCritical() << "The Monomer code does not pass the syntax test.";
997 504 error_list_p->push_back("The Monomer code does not pass the syntax test");
998 }
999
1000 236364 Formula temp_formula(m_formula);
1001
5/8
✓ Branch 1 taken 236364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 236364 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 77034 times.
✓ Branch 9 taken 159330 times.
472728 if(!temp_formula.validate(mcsp_polChemDef->getIsotopicDataCstSPtr(),
1002 error_list_p))
1003 {
1004
2/4
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77034 times.
✗ Branch 5 not taken.
77034 qCritical() << "The Monomer formula failed to validate.";
1005
1/2
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
154068 error_list_p->push_back("The Monomer formula failed to validate");
1006 }
1007
1008 236364 double mono = 0.0;
1009 236364 double avg = 0.0;
1010
1011
5/8
✓ Branch 1 taken 236364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 236364 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 77034 times.
✓ Branch 9 taken 159330 times.
472728 if(!calculateMasses(mcsp_polChemDef->getIsotopicDataCstSPtr(), mono, avg))
1012 {
1013
2/4
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77034 times.
✗ Branch 5 not taken.
77034 qCritical() << "Failed to calculate the Monomer masses.";
1014
1/2
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
154068 error_list_p->push_back("Failed to calculate the Monomer masses");
1015 }
1016
1017 // qDebug() << qSetRealNumberPrecision(6)
1018 // << "Validation calculated masses (not member data):" << mono << "-"
1019 // << avg;
1020
1021
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 236364 times.
236421 for(const ModifSPtr &modif_sp : m_modifs)
1022 {
1023 57 ErrorList local_error_list;
1024
3/4
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 54 times.
57 if(!modif_sp->validate(&local_error_list))
1025 {
1026
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.
6 qCritical() << "Monomer's Modif" << modif_sp->getName()
1027
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 << "failed to validate successfully.";
1028
1029
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 error_list_p->push_back(QString("Failed to validate Monomer's Modif %1")
1030
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 .arg(modif_sp->getName()));
1031 }
1032 57 }
1033
1034 // If we added errors, then that means that the Monomer was not valid.
1035 236364 m_isValid = (error_list_p->size() > error_count ? false : true);
1036
1037 236364 return m_isValid;
1038 236364 }
1039
1040 /*!
1041 \brief Returns the validity status of this Monomer.
1042
1043 \sa validate()
1044 */
1045 bool
1046 4419 Monomer::isValid() const
1047 {
1048 4419 return m_isValid;
1049 }
1050
1051
1052 //////////////// MASS OPERATIONS /////////////////////
1053
1054 /*!
1055 \brief Calculates this monomer's monoisotopic and avg masses and sets the
1056 results to \a mono and \a avg.
1057
1058 The calculation is performed by computing the masses of this monomer's formula,
1059 accounting the chemical entities defined by \a monomer_chemical_entities.
1060
1061 The calculations are performed using reference data in \a isotopic_data_csp.
1062
1063 Returns true if the calculations were successful, false otherwise.
1064
1065 \sa Formula::accountMasses()
1066 */
1067 bool
1068 236376 Monomer::calculateMasses(const IsotopicDataCstSPtr &isotopic_data_csp,
1069 double &mono,
1070 double &avg,
1071 Enums::ChemicalEntity monomer_chemical_entities) const
1072 {
1073 236376 IsotopicDataCstSPtr local_isotopic_data_csp = isotopic_data_csp;
1074
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236376 times.
236376 if(local_isotopic_data_csp == nullptr ||
1076 local_isotopic_data_csp.get() == nullptr)
1077 {
1078 if(mcsp_polChemDef != nullptr)
1079 local_isotopic_data_csp = mcsp_polChemDef->getIsotopicDataCstSPtr();
1080
1081 if(local_isotopic_data_csp == nullptr ||
1082 local_isotopic_data_csp.get() == nullptr)
1083 {
1084 qCritical() << "Failed to find usable isotopic data.";
1085 m_isValid = false;
1086 return m_isValid;
1087 }
1088 }
1089
1090 236376 mono = 0;
1091 236376 avg = 0;
1092
1093 236376 bool ok;
1094
1095 // Formula temp_formula(m_formula);
1096
2/4
✓ Branch 1 taken 236376 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236376 times.
✗ Branch 5 not taken.
709128 Formula(m_formula).accountMasses(ok, local_isotopic_data_csp, mono, avg);
1097
1098
2/2
✓ Branch 0 taken 77034 times.
✓ Branch 1 taken 159342 times.
236376 if(!ok)
1099 {
1100
3/8
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77034 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 77034 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
154068 qCritical() << "Failed accounting masses for Monomer:" << m_name
1101
2/4
✓ Branch 1 taken 77034 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77034 times.
✗ Branch 5 not taken.
77034 << "and formula:" << m_formula;
1102 77034 m_isValid = false;
1103 77034 return m_isValid;
1104 }
1105
1106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 159342 times.
159342 if(static_cast<int>(monomer_chemical_entities) &
1107 static_cast<int>(Enums::ChemicalEntity::MODIF))
1108 {
1109 for(const ModifSPtr &modif_sp : m_modifs)
1110 modif_sp->accountMasses(mono, avg, /*times*/ 1);
1111 }
1112
1113 return true;
1114 236376 }
1115
1116 /*!
1117 \brief Calculates this monomer's monoisotopic and avg masses.
1118
1119 The calculation is performed by computing the masses
1120 of this monomer's formula, accounting or not the entities described by \a
1121 monomer_chemical_entities.
1122
1123 The reference data for the computations are accessed at \a isotopic_data_csp.
1124
1125 Returns true if the calculations were successful, false otherwise.
1126
1127 \sa Formula::accountMasses()
1128 */
1129 bool
1130 11661 Monomer::calculateMasses(const IsotopicDataCstSPtr &isotopic_data_csp,
1131 Enums::ChemicalEntity monomer_chemical_entities)
1132 {
1133 11661 IsotopicDataCstSPtr local_isotopic_data_csp = isotopic_data_csp;
1134
1135
2/2
✓ Branch 0 taken 11655 times.
✓ Branch 1 taken 6 times.
11661 if(local_isotopic_data_csp == nullptr ||
1136 local_isotopic_data_csp.get() == nullptr)
1137 {
1138
1/2
✓ Branch 0 taken 11655 times.
✗ Branch 1 not taken.
11655 if(mcsp_polChemDef != nullptr)
1139
2/4
✓ Branch 1 taken 11655 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11655 times.
23310 local_isotopic_data_csp = mcsp_polChemDef->getIsotopicDataCstSPtr();
1140
1141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11655 times.
11655 if(local_isotopic_data_csp == nullptr ||
1142 local_isotopic_data_csp.get() == nullptr)
1143 {
1144 qCritical() << "Failed to find usable isotopic data.";
1145 m_isValid = false;
1146 return m_isValid;
1147 }
1148 }
1149
1150 11661 m_mono = 0;
1151 11661 m_avg = 0;
1152
1153 11661 bool ok;
1154
1155 // Formula temp_formula(m_formula);
1156
2/4
✓ Branch 1 taken 11661 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 11661 times.
✗ Branch 6 not taken.
23322 Formula(m_formula).accountMasses(ok, local_isotopic_data_csp, m_mono, m_avg);
1157
1158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11661 times.
11661 if(!ok)
1159 {
1160 qCritical() << "Failed accounting masses for Monomer:" << m_name
1161 << "and formula:" << m_formula;
1162 m_isValid = false;
1163 return m_isValid;
1164 }
1165
1166 // qDebug() << "After calculating the masses: the Monomer:" << toString();
1167 // qDebug() << "flags:" << static_cast<int>(monomer_chemical_entities)
1168 // << chemicalEntityMap[monomer_chemical_entities];
1169
1170
2/2
✓ Branch 0 taken 7368 times.
✓ Branch 1 taken 4293 times.
11661 if(static_cast<int>(monomer_chemical_entities) &
1171 static_cast<int>(Enums::ChemicalEntity::MODIF))
1172 {
1173
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 7368 times.
7455 for(const ModifSPtr &modif_sp : m_modifs)
1174
1/2
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
87 modif_sp->accountMasses(&m_mono, &m_avg, /*times*/ 1);
1175 }
1176
1177 return true;
1178 11661 }
1179
1180 /*!
1181 \brief Calculates this monomer's monoisotopic and avg masses.
1182
1183 The calculation is performed by computing the masses
1184 of this monomer's formula.
1185
1186 If \a monomer_chemical_entities & MONOMER_CHEMENT_MODIF is true, then the
1187 masses are updated to account for the mass of modifications.
1188
1189 Set \a ok to true if the calculations were successful, false otherwise.
1190
1191 Returns this object.
1192
1193 \sa Formula::accountMasses()
1194 */
1195 Monomer &
1196 6 Monomer::calculateMasses(bool &ok,
1197 const IsotopicDataCstSPtr &isotopic_data_csp,
1198 Enums::ChemicalEntity monomer_chemical_entities)
1199 {
1200 6 ok = calculateMasses(isotopic_data_csp, monomer_chemical_entities);
1201 6 return *this;
1202 }
1203
1204 /*!
1205 \brief Increases \a mono_p and \a avg_p by the corresponding member masses
1206 first compounded by \a times.
1207
1208 Returns true.
1209 */
1210 const Monomer &
1211 18 Monomer::accountMasses(double *mono_p, double *avg_p, int times) const
1212 {
1213
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if(mono_p != nullptr)
1214 18 *mono_p += m_mono * times;
1215
1216
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if(avg_p != nullptr)
1217 18 *avg_p += m_avg * times;
1218
1219 18 return *this;
1220 }
1221
1222
1223 /*!
1224 \brief Increases \a mono and \a avg by the corresponding member masses first
1225 compounded by \a times.
1226
1227 Returns true.
1228 */
1229 const Monomer &
1230 56934 Monomer::accountMasses(double &mono, double &avg, int times) const
1231 {
1232 56934 mono += m_mono * times;
1233 56934 avg += m_avg * times;
1234
1235 56934 return *this;
1236 }
1237
1238
1239 /*!
1240 \brief Returns the mass of the type defined by \a mass_type.
1241 */
1242 double
1243 48 Monomer::getMass(Enums::MassType mass_type) const
1244 {
1245
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if(mass_type == Enums::MassType::MONO)
1246 24 return m_mono;
1247
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 else if(mass_type == Enums::MassType::AVG)
1248 24 return m_avg;
1249
1250 qFatalStream()
1251 << "Mass cannot be anything else than Enums::MassType::MONO or Enums::MassType::AVG.";
1252
1253 return -1;
1254 }
1255
1256
1257 //////////////// FORMULA OPERATIONS /////////////////////
1258
1259 /*
1260 \brief Calculates a Formula representing this monomer .
1261
1262 The calculated formula accounts for this monomer's formula and for its
1263 modifications formulas if any and if \a (monomer_chemical_entities &
1264 MONOMER_CHEMENT_MODIF) is true.
1265
1266 This monomer's formula must validate using Modif::validate.
1267
1268 Returns the Formula.
1269
1270 \sa Modif::accountFormula()
1271 */
1272 QString
1273 861 Monomer::calculateFormula(Enums::ChemicalEntity monomer_chemical_entities) const
1274 {
1275 // We want to return the calculated formula of this monomer that accounts
1276 // for its modifications if so is requested.
1277
1278 861 IsotopicDataCstSPtr isotopic_data_csp =
1279 861 mcsp_polChemDef->getIsotopicDataCstSPtr();
1280
1281 // qDebug() << "Calculating formula for monomer: " << m_name
1282 //<< "with chemical entities:" << monomer_chemical_entities;
1283
1284
1/2
✓ Branch 1 taken 861 times.
✗ Branch 2 not taken.
861 Formula formula(m_formula);
1285
1286 // The m_formula above is only a text string. We need to convert that
1287 // into the symbol/count pair by validating it with true true params.
1288 // The formula is asked to validate with storage of the found symbol/count
1289 // pairs and with resetting of the previous contents of the symbol/count
1290 // map.
1291
1292 // We need to seed the symbol/count pairs because the following call
1293 // (accountFormula()) will update the pairs' values.
1294 861 ErrorList error_list;
1295
4/6
✓ Branch 2 taken 861 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 861 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 858 times.
1722 if(!formula.validate(
1296 isotopic_data_csp, /*store*/ true, /*reset*/ true, &error_list))
1297 {
1298 3 qDebug() << "Formula:" << formula.getActionFormula()
1299 << "failed to validate with errors:"
1300 << Utils::joinErrorList(error_list, ", ");
1301
1302 3 return QString();
1303 }
1304
1305 858 bool ok = false;
1306
1307
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 444 times.
858 if(static_cast<int>(monomer_chemical_entities) &
1308 static_cast<int>(Enums::ChemicalEntity::MODIF))
1309 {
1310
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 414 times.
432 for(const ModifSPtr &modif_sp : m_modifs)
1311 {
1312
3/8
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
36 formula.accountFormula(modif_sp->formula(/*with_title*/ false),
1313
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 mcsp_polChemDef->getIsotopicDataCstSPtr(),
1314 1,
1315 ok);
1316
1317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if(!ok)
1318 return QString();
1319 }
1320 }
1321
1322
1/2
✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
858 return formula.getActionFormula();
1323
1/2
✓ Branch 1 taken 861 times.
✗ Branch 2 not taken.
1722 }
1324
1325 /*!
1326 \brief Parses the monomer XML \a element specifically for \a version.
1327
1328 Parses the monomer XML element passed as argument and for each
1329 encountered data will set the data to this monomer (this is
1330 called XML rendering).The parsing is delegated to a function that is specific
1331 for for \a version of the polymer chemistry definition.
1332
1333 The XML element is found in the polymer chemistry definition and has the
1334 following form:
1335
1336 \code
1337 <monomers>
1338 <mnm>
1339 <name>Glycine</name>
1340 <code>G</code>
1341 <formula>C2H3N1O1</formula>
1342 </mnm>
1343 <mnm>
1344 <name>Alanine</name>
1345 <code>A</code>
1346 <formula>C3H5N1O1</formula>
1347 </mnm>
1348 \endcode
1349
1350 After setting all the data, this monomer calculates it masses and
1351 validates itself. If any of these steps fails, the error is reported
1352 by returning false.
1353
1354 \sa validate()
1355 */
1356 bool
1357 4317 Monomer::renderXmlMnmElement(const QDomElement &element,
1358 [[maybe_unused]] int version)
1359 {
1360
1361 /* In a polymer chemistry definition, the xml node we are in is
1362 * structured this way:
1363 *
1364 * <mnm>
1365 * <name>Glycine</name>
1366 * <code>G</code>
1367 * <formula>C2H3N1O1</formula>
1368 * </mnm>
1369 *
1370 * And the element parameter points to the
1371 *
1372 * <mnm> element tag:
1373 * ^
1374 * |
1375 * +----- here we are right now.
1376 *
1377 * Which means that element.tagName() == "mnm" and that we'll have
1378 * to go one step down to the first child of the current node in
1379 * order to get to the <name> element.
1380 *
1381 */
1382
1383 4317 m_isValid = true;
1384
1385 // QString str;
1386 // QTextStream stream(&str);
1387 // QDomNode node = element;
1388 // node.save(stream, 2 /*indent*/);
1389 // qDebug().noquote() << "The element:\n" << str;
1390
1391
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4314 times.
8634 if(element.tagName() != "mnm")
1392 {
1393
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 qCritical() << "The expected <mnm> element is not found.";
1394 3 m_isValid = false;
1395 3 return m_isValid;
1396 }
1397
1398 4314 QDomElement child;
1399
1400
3/6
✓ Branch 1 taken 4314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4314 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4314 times.
✗ Branch 8 not taken.
8628 child = element.firstChildElement("name");
1401
1402
8/10
✓ Branch 1 taken 4314 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4311 times.
✓ Branch 4 taken 3 times.
✓ Branch 6 taken 4311 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4308 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 4308 times.
8625 if(child.isNull() || child.text().isEmpty())
1403 {
1404
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 qCritical() << "The Monomer did not render correctly: problem with the "
1405
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 "<name> element.";
1406 6 m_isValid = false;
1407 6 return m_isValid;
1408 }
1409
1/2
✓ Branch 1 taken 4308 times.
✗ Branch 2 not taken.
4308 m_name = child.text();
1410 // qDebug() << "The name:" << m_name;
1411
1412
3/6
✓ Branch 1 taken 4308 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4308 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4308 times.
✗ Branch 8 not taken.
8616 child = child.nextSiblingElement("code");
1413
1414
3/4
✓ Branch 1 taken 4308 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 4305 times.
4308 if(child.isNull())
1415 {
1416
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical() << "The Monomer did not render correctly: problem with the "
1417
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "<code> element.";
1418 3 m_isValid = false;
1419 3 return m_isValid;
1420 }
1421
1/2
✓ Branch 1 taken 4305 times.
✗ Branch 2 not taken.
4305 m_code = child.text();
1422 // qDebug() << "The code:" << m_code;
1423
1424
3/4
✓ Branch 1 taken 4305 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 4302 times.
4305 if(!checkCodeSyntax())
1425 {
1426
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical() << "The Monomer did not render correctly: problem with the "
1427
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "code text.";
1428 3 m_isValid = false;
1429 3 return m_isValid;
1430 }
1431
1432
3/6
✓ Branch 1 taken 4302 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4302 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4302 times.
✗ Branch 8 not taken.
8604 child = child.nextSiblingElement("formula");
1433
1434
3/4
✓ Branch 1 taken 4302 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 4299 times.
4302 if(child.isNull())
1435 {
1436
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical() << "The Monomer did not render correctly: problem with the "
1437
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "<formula> element.";
1438 3 m_isValid = false;
1439 3 return m_isValid;
1440 }
1441
1442
1/2
✓ Branch 1 taken 4299 times.
✗ Branch 2 not taken.
4299 Formula temp_formula;
1443
1444
3/4
✓ Branch 1 taken 4299 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 4296 times.
4299 if(!temp_formula.renderXmlFormulaElement(child))
1445 {
1446
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
1447 << "The Monomer did not render correctly: the formula did not "
1448
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 "render correctly.";
1449 3 m_isValid = false;
1450 3 return m_isValid;
1451 }
1452
1/2
✓ Branch 1 taken 4296 times.
✗ Branch 2 not taken.
4296 m_formula = temp_formula.getActionFormula(/*with_title*/ true);
1453 // qDebug() << "The formula:" << m_formula;
1454
1455 4296 ErrorList error_list;
1456
1/2
✓ Branch 1 taken 4296 times.
✗ Branch 2 not taken.
4296 m_isValid = validate(&error_list);
1457
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4287 times.
4296 if(!m_isValid)
1458 {
1459
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 qCritical() << "The Monomer did not validate successfully after "
1460
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 "rendering, with errors:";
1461
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 Utils::joinErrorList(error_list, ", ");
1462 }
1463 else
1464 {
1465 // At this point, because we are creating a Monomer from scratch,
1466 // and not by copying or by assignment, we calculate the masses
1467 // explicitely (validate() does that but not on member m_mono/m_avg
1468 // because the method is const.).
1469
1470
3/6
✓ Branch 1 taken 4287 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4287 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4287 times.
4287 if(!calculateMasses(nullptr))
1471 {
1472 qCritical() << "The Monomer's masses could not be calculated.";
1473 }
1474 }
1475
1476 // qDebug() << "Correctly rendered Monomer" << m_name << ":" << toString();
1477
1478 4296 return m_isValid;
1479 8613 }
1480
1481
1482 /*!
1483 \brief Formats this monomer's data as a string suitable to be used as an XML
1484 element in the polymer chemistry definition.
1485
1486 The typical monomer element that is generated in this function looks like
1487 this:
1488
1489 \code
1490 <monomers>
1491 <mnm>
1492 <name>Glycine</name>
1493 <code>G</code>
1494 <formula>C2H3N1O1</formula>
1495 </mnm>
1496 \endcode
1497
1498 The formatting of the XML element takes into account \a offset and \a
1499 indent by prepending the string with \a offset * \a indent character
1500 substring.
1501
1502 \a indent defaults to two spaces.
1503
1504 Returns a dynamically allocated string that needs to be freed after
1505 use.
1506 */
1507 QString
1508 63 Monomer::formatXmlMnmElement(int offset, const QString &indent) const
1509 {
1510 63 int newOffset;
1511 63 int iter = 0;
1512
1513 63 QString lead("");
1514 63 QString text;
1515
1516 // Prepare the lead.
1517 63 newOffset = offset;
1518
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 63 times.
252 while(iter < newOffset)
1519 {
1520
1/2
✓ Branch 1 taken 189 times.
✗ Branch 2 not taken.
189 lead += indent;
1521 189 ++iter;
1522 }
1523
1524
2/4
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
126 text += QString("%1<mnm>\n").arg(lead);
1525
1526 // Prepare the lead.
1527 63 ++newOffset;
1528 63 lead.clear();
1529 63 iter = 0;
1530
2/2
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 63 times.
378 while(iter < newOffset)
1531 {
1532
1/2
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
252 lead += indent;
1533 252 ++iter;
1534 }
1535
1536 // Continue with indented elements.
1537
1538
3/6
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63 times.
✗ Branch 8 not taken.
126 text += QString("%1<name>%2</name>\n").arg(lead).arg(m_name);
1539
1540
3/6
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63 times.
✗ Branch 8 not taken.
126 text += QString("%1<code>%2</code>\n").arg(lead).arg(m_code);
1541
1542
3/6
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63 times.
✗ Branch 8 not taken.
126 text += QString("%1<formula>%2</formula>\n").arg(lead).arg(m_formula);
1543
1544 // Prepare the lead for the closing element.
1545 63 --newOffset;
1546 63 lead.clear();
1547 63 iter = 0;
1548
2/2
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 63 times.
315 while(iter < newOffset)
1549 {
1550
1/2
✓ Branch 1 taken 189 times.
✗ Branch 2 not taken.
189 lead += indent;
1551 189 ++iter;
1552 }
1553
1554
2/4
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
126 text += QString("%1</mnm>\n").arg(lead);
1555
1556 63 return text;
1557 63 }
1558
1559
1560 /*!
1561 \brief Parses into this monomer the XML monomer \a element passed as argument.
1562
1563 The XML element comes from a polymer sequence file, where the monomer is
1564 singled out (not in a sequence string) because it might be modified, like
1565 this:
1566
1567 \code
1568 <monomer>
1569 <code>S</code>
1570 <mdf>
1571 <name>Phosphorylation</name>
1572 <formula>H1O3P1</formula>
1573 <targets>*</targets>
1574 <maxcount>1</maxcount>
1575 </mdf>
1576 </monomer>
1577 <codes>GRKASGSSPTSPINADKVENEDAFLEEVAEEKPHVKPYFTKTILDMEVVEGSAARFDCKIEGYPDPEVM</codes>
1578 <monomer>
1579 <code>W</code>
1580 <mdf>
1581 <name>Oxidation</name>
1582 <formula>O1</formula>
1583 <targets>*</targets>
1584 <maxcount>1</maxcount>
1585 </mdf>
1586 </monomer>
1587 <codes>YKDDQPVKESRHFQIDYDEEGNCSLTISEVCGDDDAKYTCKAVNSLGEATCTAELLVETMGKEGEGEGEGEEDEEEEEE</codes>
1588 \endcode
1589
1590 \a version indicates the format version of this XML \a element.
1591
1592 As soon as the monomer code is known, while parsing the \a element, the
1593 corresponding monomer is searched in the list of monomers in the member
1594 polymer chemistry definition (\c mcsp_polChemDef). Then, the found monomer is
1595 copied into \c this monomer so that both monomers are identical, effectively
1596 initializing this monomer to the monomer described by the \a element.
1597
1598 If the \a element contains one or more \c mdf modifications, these
1599 modifications are allocated as \l{Modif}'s and validated. If these
1600 modifications validate successfully, they are appended to this monomer's list
1601 of modifications.
1602
1603 Returns true if initialization of his monomer with the contents of \a
1604 element succeeded, false otherwise.
1605
1606 \sa formatXmlMonomerElement(int offset, const QString &indent)
1607 */
1608 bool
1609 156 Monomer::renderXmlMonomerElement(const QDomElement &element,
1610 [[maybe_unused]] int version)
1611 {
1612 156 qDebug();
1613
1614 156 m_isValid = true;
1615
1616 // QString str;
1617 // QTextStream stream(&str);
1618 // QDomNode node = element;
1619 // node.save(stream, 2 /*indent*/);
1620 // qDebug().noquote() << "The element:\n" << str;
1621
1622
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
312 if(element.tagName() != "monomer")
1623 {
1624 qCritical() << "The expected <monomer> element is not found.";
1625 m_isValid = false;
1626 return m_isValid;
1627 }
1628
1629 156 qDebug() << "Indeed a monomer element.";
1630
1631 156 QDomElement child;
1632
1633
3/6
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 156 times.
✗ Branch 8 not taken.
312 child = element.firstChildElement("code");
1634
1635
5/10
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 156 times.
312 if(child.isNull() || child.text().isEmpty())
1636 {
1637 qCritical() << "The Monomer did not render correctly: problem with the "
1638 "<code> element.";
1639 m_isValid = false;
1640 return m_isValid;
1641 }
1642
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 QString code = child.text();
1643
1644 156 qDebug() << "The code:" << code;
1645
1646 // Use the code to access the corresponding Monomer in the list of Monomers
1647 // in the polymer chemistry definition.
1648
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 MonomerSPtr monomer_csp = mcsp_polChemDef->getMonomerCstSPtrByCode(code);
1649
1650 156 qDebug() << "monomer pointer:" << monomer_csp.get();
1651
1652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if(monomer_csp == nullptr)
1653 {
1654 qCritical() << "The monomer's code is not found in the polymer chemistry "
1655 "definition.";
1656
1657 m_isValid = false;
1658 return m_isValid;
1659 }
1660
1661 156 qDebug() << "monomer name:" << monomer_csp->getName();
1662
1663
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 *this = *monomer_csp;
1664
1665 // Sanity check
1666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if(m_code != code)
1667 qFatal("Programming error. Both codes should be identical.");
1668
1669 // And now we have to manage the mdf objects.
1670
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
312 child = child.nextSiblingElement();
1671
1672
3/4
✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 156 times.
312 while(!child.isNull())
1673 {
1674
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 156 times.
312 if(child.tagName() != "mdf")
1675 {
1676 qCritical()
1677 << "The Monomer did not render correctly: problem with the "
1678 "<mdf> element.";
1679
1680 m_isValid = false;
1681 return m_isValid;
1682 }
1683
1684
1/4
✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
156 Modif modif(mcsp_polChemDef, child, version);
1685
1686 156 qDebug() << "20250428-Created Modif:" << modif.getName()
1687 << "with Formula:" << modif.getFormula();
1688
1689
4/8
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 156 times.
312 if(!modif.calculateMasses(mcsp_polChemDef->getIsotopicDataCstSPtr()))
1690 {
1691 qCritical() << "Failed to calculate masses for Monomer's Modif"
1692 << modif.getName();
1693
1694 m_isValid = false;
1695 return m_isValid;
1696 }
1697
1698 // The validation will take care of checking that the <targets>
1699 // element did have correct text inside.
1700
1701 156 ErrorList error_list;
1702
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 156 times.
156 if(!modif.validate(&error_list))
1703 {
1704 qCritical() << "Failed to validate modification" << modif.getName()
1705 << "with errors:"
1706 << Utils::joinErrorList(error_list, ", ");
1707
1708 m_isValid = false;
1709 return m_isValid;
1710 }
1711
1712 156 error_list.clear();
1713
1714 // qDebug() << "At this point, going to modify the monomer.";
1715
1/2
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
156 QString uuid = modify(modif, /*override*/ false, &error_list);
1716
1717 // qDebug() << "The returned uuid:" << uuid;
1718
1719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if(uuid.isEmpty())
1720 {
1721 qCritical() << "The monomer could not be modified, with errors:"
1722 << Utils::joinErrorList(error_list, ", ");
1723
1724 m_isValid = false;
1725 return m_isValid;
1726 }
1727
1728
2/4
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
312 child = child.nextSiblingElement();
1729 156 }
1730
1731 156 m_isValid = true;
1732 156 return m_isValid;
1733 312 }
1734
1735
1736 /*!
1737 \brief Formats a string suitable to be used as an XML element in a
1738 polymer sequence file.
1739
1740 The typical monomer element that is generated in this function looks like
1741 this:
1742
1743 \code
1744 <monomer>
1745 <code>S</code>
1746 <prop>
1747 <name>MODIF</name>
1748 <data>Phosphorylation</data>
1749 </prop>
1750 <prop>
1751 <name>COMMENT</name>
1752 <data>Phosphorylation is only partial</data>
1753 </prop>
1754 </monomer>
1755 \endcode
1756
1757 The formatting of the XML element takes into account \a offset and \a
1758 indent by prepending the string with \a offset * \a indent character
1759 substring.
1760
1761 \a indent defaults to two spaces.
1762
1763 Returns a string.
1764 */
1765 QString
1766 3 Monomer::formatXmlMonomerElement(int offset, const QString &indent) const
1767 {
1768 3 int newOffset;
1769 3 int iter = 0;
1770
1771 3 QString lead("");
1772 3 QString text;
1773
1774 // Prepare the lead.
1775 3 newOffset = offset;
1776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 while(iter < newOffset)
1777 {
1778 lead += indent;
1779 ++iter;
1780 }
1781
1782
3/6
✓ 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.
6 text.append(QString("%1<monomer>\n").arg(lead));
1783
1784 // Prepare the lead for the <code> child that is indented.
1785 3 ++newOffset;
1786 3 lead.clear();
1787 3 iter = 0;
1788
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
9 while(iter < newOffset)
1789 {
1790
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 lead += indent;
1791 3 ++iter;
1792 }
1793
1794 3 QString code_element_string =
1795
3/6
✓ 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.
3 QString("%1<code>%2</code>\n").arg(lead).arg(m_code);
1796 3 qDebug() << "code element:" << code_element_string;
1797
1798
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 text.append(code_element_string);
1799
1800 // The monomer may have any number of modif objects, which we have
1801 // to document here.
1802
1803 // Continue with indented <mdf> element(s) (same indent as for <code>).
1804
1805
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for(const ModifSPtr &modif_sp : m_modifs)
1806
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 text.append(modif_sp->formatXmlMdfElement(newOffset, indent));
1807
1808 // Prepare the lead for the closing element.
1809 3 --newOffset;
1810 3 lead.clear();
1811 3 iter = 0;
1812
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
6 while(iter < newOffset)
1813 {
1814 lead += indent;
1815 ++iter;
1816 }
1817
1818
3/6
✓ 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.
6 text.append(QString("%1</monomer>\n").arg(lead));
1819
1820 // QString debug_message =
1821 // QString("%1\n%2\n").arg("Returning string:").arg(text);
1822 // qDebug().noquote() << debug_message;
1823
1824 3 return text;
1825 3 }
1826
1827
1828 //////////////// UTILS /////////////////////
1829
1830 /*!
1831 \brief Stores the Modif instance \a modif_sp pointer in the member container.
1832
1833 The \a modif_sp is stored as is, without duplication.
1834
1835 Returns the Uuid string associated to the stored Modif.
1836 */
1837 QString
1838 411 Monomer::storeModif(const ModifSPtr &modif_sp)
1839 {
1840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 411 times.
411 if(modif_sp == nullptr)
1841 qFatalStream() << "The provided ModifSPtr is nullptr.";
1842
1843 411 qDebug() << "Right before storage, there are currently" << m_modifs.size()
1844 << "modifications.";
1845
1846 // Do not store an item twice.
1847
3/6
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 411 times.
822 if(hasModif(modif_sp) || !getUuidForModif(modif_sp).isEmpty())
1848 qFatalStream() << "It is prohibited to store the same ModifSPtr more than once.";
1849
1850 411 qDebug() << "Ok, we can go on.";
1851
1852 // Even if we get a ref to shared_ptr, the reference count increment will
1853 // occur.
1854 411 m_modifs.push_back(modif_sp);
1855 411 QString uuid = QUuid::createUuid().toString();
1856
1/2
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
411 m_uuidModifPairs.push_back(UuidModifWPtrPair(uuid, modif_sp));
1857
1858 411 qDebug() << "Right after storage, there are currently" << m_modifs.size()
1859 << "modifications.";
1860
1861 411 return uuid;
1862 }
1863
1864 /*!
1865 \brief Stores the Modif instance \a modif in the member container.
1866
1867 The \a modif is used to craft a ModifSPtr that is stored.
1868
1869 Returns the Uuid string associated to the stored Modif.
1870 */
1871 QString
1872 Monomer::storeModif(const Modif &modif)
1873 {
1874 ModifSPtr modif_sp = std::make_shared<Modif>(modif);
1875
1876 if(modif_sp == nullptr)
1877 {
1878 qFatalStream() << "Failed to allocate ModifSPtr.";
1879 return "";
1880 }
1881
1882 return storeModif(modif_sp);
1883 }
1884
1885
1886 /*!
1887 \brief Returns true if \a modif_sp was found in the member container of Modif
1888 instances, false otherwise.
1889 */
1890 bool
1891 930 Monomer::hasModif(const ModifSPtr &modif_sp) const
1892 {
1893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 930 times.
930 if(modif_sp == nullptr)
1894 qFatalStream() << "Pointer cannot be nullptr.";
1895
1896 930 std::vector<ModifSPtr>::const_iterator the_iterator_cst =
1897 1860 std::find_if(m_modifs.cbegin(),
1898 m_modifs.cend(),
1899
5/10
✓ Branch 1 taken 930 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 930 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 930 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 930 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 930 times.
✗ Branch 15 not taken.
5580 [modif_sp](const ModifSPtr &the_modif_sp) {
1900
11/14
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 33 times.
✓ Branch 10 taken 12 times.
✓ Branch 11 taken 78 times.
✓ Branch 12 taken 51 times.
✓ Branch 13 taken 126 times.
345 return the_modif_sp == modif_sp;
1901 });
1902
1903
2/2
✓ Branch 0 taken 822 times.
✓ Branch 1 taken 108 times.
930 if(the_iterator_cst == m_modifs.cend())
1904 {
1905 822 std::vector<UuidModifWPtrPair>::const_iterator the_pair_iterator_cst =
1906 1644 std::find_if(m_uuidModifPairs.cbegin(),
1907 m_uuidModifPairs.cend(),
1908
5/10
✓ Branch 2 taken 822 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 822 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 822 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 822 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 822 times.
✗ Branch 16 not taken.
4932 [modif_sp](const UuidModifWPtrPair &the_pair) {
1909
2/2
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 6 times.
234 return the_pair.second.lock() == modif_sp;
1910 });
1911
1912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 822 times.
822 if(the_pair_iterator_cst != m_uuidModifPairs.cend())
1913 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
1914
1915 822 return false;
1916 }
1917
1918 return true;
1919 }
1920
1921 /*!
1922 \brief Returns true if \a modif_sp was found in the member container of
1923 Uuid-Modif pairs, false otherwise.
1924 */
1925 bool
1926 Monomer::hasUuid(const ModifSPtr &modif_sp) const
1927 {
1928 if(modif_sp == nullptr)
1929 qFatalStream() << "Pointer cannot be nullptr.";
1930
1931 std::vector<UuidModifWPtrPair>::const_iterator the_iterator_cst =
1932 std::find_if(m_uuidModifPairs.cbegin(),
1933 m_uuidModifPairs.cend(),
1934 [modif_sp](const UuidModifWPtrPair &the_pair) {
1935 return the_pair.second.lock() == modif_sp;
1936 });
1937
1938 if(the_iterator_cst == m_uuidModifPairs.cend())
1939 return false;
1940
1941 // Sanity check
1942
1943 if(!hasModif(modif_sp))
1944 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
1945
1946 return true;
1947 }
1948
1949 /*!
1950 \brief Returns the Monomer instance pointer in the member container that is
1951 associated to the \a uuid Uuid string.
1952
1953 If no such Monomer instance pointer is found, nullptr is returned.
1954 */
1955 ModifSPtr
1956 33 Monomer::getModifForUuid(const QString &uuid) const
1957 {
1958 33 qDebug() << "There are currently" << m_modifs.size()
1959 << "modifications. The Modif uuid that is asked for:" << uuid;
1960
1961
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 3 times.
33 std::vector<std::pair<QString, ModifWPtr>>::const_iterator the_iterator_cst =
1962 66 std::find_if(m_uuidModifPairs.cbegin(),
1963 m_uuidModifPairs.cend(),
1964
8/8
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 3 times.
✓ Branch 8 taken 30 times.
✓ Branch 9 taken 3 times.
285 [uuid](const UuidModifWPtrPair &the_pair) {
1965 57 qDebug() << "Iterating into" << the_pair.first
1966 << "while searching for" << uuid;
1967
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 9 times.
✓ Branch 12 taken 27 times.
✓ Branch 13 taken 3 times.
48 return the_pair.first == uuid;
1968 });
1969
1970
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30 times.
33 if(the_iterator_cst == m_uuidModifPairs.cend())
1971 3 return nullptr;
1972
1973 30 ModifSPtr modif_sp = (*the_iterator_cst).second.lock();
1974
1975 // Sanity check
1976
1977
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
30 if(!hasModif(modif_sp))
1978 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
1979
1980 30 return modif_sp;
1981 30 }
1982
1983 /*!
1984 \brief Returns the UUID string identifying \a modif_sp in the member container.
1985
1986 If no such Modif is found, an empty string is returned.
1987 */
1988 QString
1989 450 Monomer::getUuidForModif(const ModifSPtr &modif_sp) const
1990 {
1991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450 times.
450 if(modif_sp == nullptr)
1992 qFatalStream() << "Pointer cannot be nullptr.";
1993
1994 450 std::vector<UuidModifWPtrPair>::const_iterator the_iterator_cst =
1995 900 std::find_if(m_uuidModifPairs.cbegin(),
1996 m_uuidModifPairs.cend(),
1997
5/10
✓ Branch 2 taken 450 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 450 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 450 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 450 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 450 times.
✗ Branch 16 not taken.
2700 [modif_sp](const UuidModifWPtrPair &the_pair) {
1998 // Do not query the modif_sp managed object because it can
1999 // be nullptr!
2000
2/2
✓ Branch 1 taken 153 times.
✓ Branch 2 taken 3 times.
156 return the_pair.second.lock() == modif_sp;
2001 });
2002
2003
2/2
✓ Branch 0 taken 411 times.
✓ Branch 1 taken 39 times.
450 if(the_iterator_cst == m_uuidModifPairs.cend())
2004 {
2005 // Sanity check
2006
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
411 if(hasModif(modif_sp))
2007 qFatalStream() << "Inconsistency between the m_modifs and the "
2008 "m_uuidModifPairs vectors.";
2009
2010 411 return QString();
2011 }
2012
2013 // Sanity check
2014
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if(!hasModif(modif_sp))
2015 qFatalStream()
2016 << "Inconsistency between the m_modifs and the m_uuidModifPairs vectors.";
2017
2018
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
489 return (*the_iterator_cst).first;
2019 }
2020
2021
2022 /*!
2023 \brief Returns a container of QString instances that correspond to the UUID
2024 strings that identify all the Modif instances involved in this Monomer.
2025
2026 If no Modif is found, an empty container is returned.
2027 */
2028 std::vector<QString>
2029 Monomer::getAllModifUuids() const
2030 {
2031 std::vector<QString> the_uuid_strings;
2032
2033 for(const UuidModifCstWPtrPair pair : m_uuidModifPairs)
2034 the_uuid_strings.push_back(pair.first);
2035
2036 // Sanity check
2037 if(the_uuid_strings.size() != m_modifs.size())
2038 qFatalStream() << "Inconsistency between the <object>_s and <uuid-object> pairs.";
2039
2040 return the_uuid_strings;
2041 }
2042
2043 void
2044 Monomer::cleanupModifs()
2045 {
2046 qDebug() << "At beginning, count of UUID-Modif pairs:"
2047 << m_uuidModifPairs.size();
2048
2049 std::vector<UuidModifWPtrPair>::iterator the_iterator =
2050 m_uuidModifPairs.begin();
2051 std::vector<UuidModifWPtrPair>::iterator the_end_iterator =
2052 m_uuidModifPairs.end();
2053
2054 while(the_iterator != the_end_iterator)
2055 {
2056 if((*the_iterator).second.expired() ||
2057 (*the_iterator).second.lock() == nullptr ||
2058 !hasModif((*the_iterator).second.lock()))
2059 the_iterator = m_uuidModifPairs.erase(the_iterator);
2060 else
2061 ++the_iterator;
2062 }
2063
2064 qDebug() << "At end, count of UUID-Modif pairs:" << m_uuidModifPairs.size();
2065 }
2066
2067
2068 bool
2069 39 Monomer::removeModif(ModifSPtr modif_sp)
2070 {
2071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if(modif_sp == nullptr || modif_sp.get() == nullptr)
2072 qFatalStream() << "Cannot be that pointer is nullptr.";
2073
2074 // We will need this anyway.
2075 39 QString uuid = getUuidForModif(modif_sp);
2076
2077 // Some controls are in order: we have to check that at index, there is
2078 // a ModifSPtr that is present both in m_modifs and in
2079 // m_uuidModifPairs.
2080
2081
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
78 std::vector<ModifSPtr>::const_iterator the_iterator_cst = std::find_if(
2082
2/4
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
117 m_modifs.begin(), m_modifs.end(), [modif_sp](ModifSPtr iter_modif_sp) {
2083
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 return iter_modif_sp == modif_sp;
2084
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 });
2085
2086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if(the_iterator_cst == m_modifs.end())
2087 {
2088 qCritical() << "The ModifSPtr was not found in the container.";
2089
2090 if(!uuid.isEmpty())
2091 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
2092
2093 return false;
2094 }
2095
2096 // At this point, both containers contain modif_sp.
2097
2098 39 m_modifs.erase(the_iterator_cst);
2099
2100
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 std::vector<UuidModifWPtrPair>::const_iterator the_pair_iterator_cst =
2101 78 std::find_if(m_uuidModifPairs.cbegin(),
2102 m_uuidModifPairs.cend(),
2103
2/4
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
195 [uuid](const UuidModifWPtrPair &the_pair) {
2104 // Do not query the modif_sp managed object because it can
2105 // be nullptr!
2106
4/14
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
39 return the_pair.first == uuid;
2107 });
2108
2109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if(the_pair_iterator_cst == m_uuidModifPairs.cend())
2110 qFatalStream() << "Inconsistency between m_modifs and m_uuidModifPairs.";
2111
2112 39 m_uuidModifPairs.erase(the_pair_iterator_cst);
2113
2114 39 return true;
2115 39 }
2116
2117 /*!
2118 \brief Clears all the data of the Monomer instance.
2119 */
2120 void
2121 Monomer::clear()
2122 {
2123 mcsp_polChemDef = nullptr;
2124 m_name = "";
2125 m_code = "";
2126 m_formula = "";
2127
2128 m_mono = 0.0;
2129 m_avg = 0.0;
2130
2131 m_modifs.clear();
2132
2133 m_isValid = false;
2134 }
2135
2136 /*!
2137 \brief Returns a text string representing this Monomer instance.
2138 */
2139 QString
2140 Monomer::toString() const
2141 {
2142 return QString(
2143 "Monomer: %1 - %2 - %3 - %4 - %5 - modifs: %6 - is valid: %7\n")
2144 .arg(m_name)
2145 .arg(m_code)
2146 .arg(m_formula)
2147 .arg(m_mono, 0, 'f', ATOM_DEC_PLACES)
2148 .arg(m_avg, 0, 'f', ATOM_DEC_PLACES)
2149 .arg(m_modifs.size())
2150 .arg(m_isValid);
2151 }
2152
2153
2154 } // namespace libXpertMassCore
2155 } // namespace MsXpS
2156