GCC Code Coverage Report


./
File: src/XpertMass/Oligomer.cpp
Date: 2024-08-24 11:26:06
Lines:
0/260
0.0%
Functions:
0/39
0.0%
Branches:
0/296
0.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 /////////////////////// Local includes
35 #include "Oligomer.hpp"
36 #include "Polymer.hpp"
37 #include "IonizeRule.hpp"
38
39
40 namespace MsXpS
41 {
42
43 namespace libXpertMass
44 {
45
46
47 /*!
48 \class MsXpS::libXpertMass::Oligomer
49 \inmodule libXpertMass
50 \ingroup PolChemDefBuildingdBlocks
51 \inheaderfile Oligomer.hpp
52
53 \brief The Oligomer class provides abstractions to work with
54 an oligomer molecule (peptide , for example).
55
56 The notion of an oligomer is that it is part of a \l Polymer and is thus
57 defined by a range of \l Monomer indices in this Polymer (the \l Coordinates).
58
59 The start index cannot be less than 0 nor greater than the size of the polymer
60 minus one, and the end index follows the same rule.
61
62 Derived from \l Ionizable (itself derived from \l Ponderable), an oligomer is
63 also characterized by a monoisotopic
64 mass and an average mass.
65
66 All computations about an oligomer (fragmentation, composition, for
67 example, isoelectric point, ...) can only be performed by referring
68 to the sequence of its "enclosing" \l Polymer. Therefore, an Oligomer
69 should never exist after the destruction of its "enclosing" polymer.
70 */
71
72 /*!
73 \variable MsXpS::libXpertMass::Oligomer::mp_polymer
74
75 \brief The \l Polymer instance of which this Oligomer is part.
76 */
77
78 /*!
79 \variable MsXpS::libXpertMass::Oligomer::m_description
80
81 \brief The description of the Oligomer.
82 */
83
84
85 /*!
86 \variable MsXpS::libXpertMass::Oligomer::m_isModified
87
88 \brief Tell if the Oligomer is modified.
89 */
90
91 /*!
92 \variable MsXpS::libXpertMass::Oligomer::m_crossLinkList
93
94 \brief The list of CrossLink events in the oligomer sequence.
95 */
96
97 /*!
98 \variable MsXpS::libXpertMass::Oligomer::m_calcOptions
99
100 \brief The calculation options definining how calculations are
101 performed.
102 */
103
104 /*!
105 \typedef OligomerSPtr
106 \relates Oligomer
107
108 Synonym for std::shared_ptr<Oligomer> OligomerSPtr.
109 */
110
111 /*!
112 \typedef OligomerCstSPtr
113 \relates Oligomer
114
115 Synonym for std::shared_ptr<const Oligomer> OligomerSPtr.
116 */
117
118 /*!
119 \brief Constructs an oligomer.
120
121 The Oligomer instance is constructed with these arguments:
122
123 \a polymer: The polymer instance that encloses this Oligomer. Used to intialize
124 the member m_polymer and the Ionizable base class' polymer
125 chemistry definition
126
127 \a name: The name of this Oligomer, used to intialize the Ionizable base class
128
129 \a description: The description of this Oligomer (m_description)
130
131 \a modified: Tells if the Oligomer is modified
132
133 \a ponderable: Used to initialize the Ionizable base class
134
135 \a ionizeRule: Used to initialize the Ionizable base class
136
137 \a calcOptions: Used to initialize the m_calcOptions member
138
139 \a isIonized: Tells if this Oligomer instance is ionized
140
141 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
142
143 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
144 */
145 Oligomer::Oligomer(Polymer *polymer,
146 const QString &name,
147 const QString &description,
148 bool modified,
149 const Ponderable &ponderable,
150 const IonizeRule &ionizeRule,
151 const CalcOptions &calcOptions,
152 bool isIonized,
153 int startIndex,
154 int endIndex)
155 : Ionizable(
156 polymer->getPolChemDefCstSPtr(), name, ponderable, ionizeRule, isIonized),
157 mp_polymer(polymer),
158 m_description(description),
159 m_isModified{modified},
160 m_calcOptions(calcOptions)
161 {
162 setStartEndIndices(startIndex, endIndex);
163 }
164
165
166 /*!
167 \brief Constructs an oligomer.
168
169 The Oligomer instance is constructed with these arguments:
170
171 \a pol_chem_def_csp: The polymer chemistry definition used to initialize the
172 Ionizable base class
173
174 \a name: The name of this Oligomer, used to intialize the Ionizable base class
175
176 \a description: The description of this Oligomer (m_description)
177
178 \a modified: Tells if the Oligomer is modified
179
180 \a ponderable: Used to initialize the Ionizable base class
181
182 \a ionizeRule: Used to initialize the Ionizable base class
183
184 \a calcOptions: Used to initialize the m_calcOptions member
185
186 \a isIonized: Tells if this Oligomer instance is ionized
187
188 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
189
190 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
191 */
192 Oligomer::Oligomer(PolChemDefCstSPtr pol_chem_def_csp,
193 const QString &name,
194 const QString &description,
195 bool modified,
196 const Ponderable &ponderable,
197 const IonizeRule &ionizeRule,
198 const CalcOptions &calcOptions,
199 bool isIonized,
200 int startIndex,
201 int endIndex)
202 : Ionizable(pol_chem_def_csp, name, ponderable, ionizeRule, isIonized),
203 mp_polymer(nullptr),
204 m_description(description),
205 m_isModified{modified},
206 m_calcOptions(calcOptions)
207 {
208 setStartEndIndices(startIndex, endIndex);
209 // if (startIndex < 0)
210 // qDebug() << __FILE__ << __LINE__
211 // << "Construct with startIndex:" << startIndex;
212 }
213
214
215 /*!
216 \brief Constructs an oligomer.
217
218 The Oligomer instance is constructed with these arguments:
219
220 \a polymer: The polymer instance that encloses this Oligomer. Used to intialize
221 the member m_polymer and the Ionizable base class' polymer
222
223 \a name: The name of this Oligomer, used to intialize the Ionizable base class
224
225 \a description: The description of this Oligomer (m_description)
226
227 \a modified: Tells if the Oligomer is modified
228
229 \a ponderable: Used to initialize the Ionizable base class
230
231 \a calcOptions: Used to initialize the m_calcOptions member
232
233 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
234
235 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
236 */
237 Oligomer::Oligomer(Polymer *polymer,
238 const QString &name,
239 const QString &description,
240 bool modified,
241 const Ponderable &ponderable,
242 int startIndex,
243 int endIndex,
244 const CalcOptions &calcOptions)
245 : Ionizable(polymer->getPolChemDefCstSPtr(), name, ponderable),
246 mp_polymer(polymer),
247 m_description(description),
248 m_isModified(modified),
249 m_calcOptions(calcOptions)
250 {
251 setStartEndIndices(startIndex, endIndex);
252 if(startIndex < 0)
253 qDebug() << __FILE__ << __LINE__
254 << "Construct with startIndex:" << startIndex;
255 }
256
257
258 /*!
259 \brief Constructs an oligomer.
260
261 The Oligomer instance is constructed with these arguments:
262
263 \a pol_chem_def_csp: The polymer chemistry definition used to initialize the
264 Ionizable base class
265
266 \a name: The name of this Oligomer, used to intialize the Ionizable base class
267
268 \a description: The description of this Oligomer (m_description)
269
270 \a modified: Tells if the Oligomer is modified
271
272 \a ponderable: Used to initialize the Ionizable base class
273
274 \a calcOptions: Used to initialize the m_calcOptions member
275
276 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
277
278 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
279 */
280 Oligomer::Oligomer(PolChemDefCstSPtr pol_chem_def_csp,
281 const QString &name,
282 const QString &description,
283 bool modified,
284 const Ponderable &ponderable,
285 const CalcOptions &calcOptions,
286 int startIndex,
287 int endIndex)
288 : Ionizable(pol_chem_def_csp, name, ponderable),
289 mp_polymer(nullptr),
290 m_description(description),
291 m_isModified{modified},
292 m_calcOptions(calcOptions)
293 {
294 setStartEndIndices(startIndex, endIndex);
295 if(startIndex < 0)
296 qDebug() << __FILE__ << __LINE__
297 << "Construct with startIndex:" << startIndex;
298 }
299
300
301 /*!
302 \brief Constructs an oligomer.
303
304 The Oligomer instance is constructed with these arguments:
305
306 \a ionizable: Used to initialize the Ionizable base class
307
308 \a calcOptions: Used to initialize the m_calcOptions member
309
310 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
311
312 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
313 */
314 Oligomer::Oligomer(const Ionizable &ionizable,
315 const CalcOptions &calcOptions,
316 int startIndex,
317 int endIndex)
318 : Ionizable(ionizable),
319 mp_polymer(nullptr),
320 m_description("NOT_SET"),
321 m_calcOptions(calcOptions)
322 {
323 setStartEndIndices(startIndex, endIndex);
324 if(startIndex < 0)
325 qDebug() << __FILE__ << __LINE__
326 << "Construct with startIndex:" << startIndex;
327 }
328
329
330 /*!
331 \brief Constructs an oligomer.
332
333 The Oligomer instance is constructed with these arguments:
334
335 \a polymer: Use to initialize the member mp_polymer and also to
336 initialize the Ionizable base class (by using its polymer chemistry definition
337 member).
338
339 \a name: The name of this Oligomer, used to intialize the Ionizable base class
340
341 \a description: The description of this Oligomer (m_description)
342
343 \a modified: Tells if the Oligomer is modified
344
345 \a mono and \a avg: Used to initialize the Ionizable::Ponderable base class
346
347 \a calcOptions: Used to initialize the m_calcOptions member
348
349 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
350
351 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
352 */
353 Oligomer::Oligomer(Polymer *polymer,
354 const QString &name,
355 const QString &description,
356 bool modified,
357 double mono,
358 double avg,
359 int startIndex,
360 int endIndex,
361 const CalcOptions &calcOptions)
362 : Ionizable(polymer->getPolChemDefCstSPtr(), name, Ponderable(mono, avg)),
363 mp_polymer(polymer),
364 m_description(description),
365 m_isModified{modified},
366 m_calcOptions(calcOptions)
367 {
368 setStartEndIndices(startIndex, endIndex);
369 if(startIndex < 0)
370 qDebug() << __FILE__ << __LINE__
371 << "Construct with startIndex:" << startIndex;
372 }
373
374
375 /*!
376 \brief Constructs an oligomer.
377
378 The Oligomer instance is constructed with these arguments:
379
380 \a pol_chem_def_csp: The polymer chemistry definition used to initialize the
381 Ionizable base class
382
383 \a name: The name of this Oligomer, used to intialize the Ionizable base class
384
385 \a description: The description of this Oligomer (m_description)
386
387 \a modified: Tells if the Oligomer is modified
388
389 \a calcOptions: Used to initialize the m_calcOptions member
390
391 \a mono and \a avg: Used to initialize the Ionizable::Ponderable base class
392
393 \a startIndex: The oligomer's start index coordinate in the enclosing Polymer
394
395 \a endIndex: The oligomer's end index coordinate in the enclosing Polymer
396 */
397 Oligomer::Oligomer(PolChemDefCstSPtr pol_chem_def_csp,
398 const QString &name,
399 const QString &description,
400 bool modified,
401 const CalcOptions &calcOptions,
402 double mono,
403 double avg,
404 int startIndex,
405 int endIndex)
406 : Ionizable(pol_chem_def_csp, name, Ponderable(mono, avg)),
407 mp_polymer(0),
408 m_description(description),
409 m_isModified{modified},
410 m_calcOptions(calcOptions)
411 {
412 setStartEndIndices(startIndex, endIndex);
413 }
414
415
416 /*!
417 \brief Constructs the Oligomer as a copy of \a other.
418 */
419 Oligomer::Oligomer(const Oligomer &other)
420 : Sequence(other),
421 CoordinateList(other),
422 Ionizable(other),
423 PropListHolder(other),
424 mp_polymer(other.mp_polymer),
425 m_description(other.m_description),
426 m_isModified{other.m_isModified},
427 m_calcOptions(other.m_calcOptions)
428 {
429 }
430
431
432 /*!
433 \brief Destructs this Oligomer.
434 */
435 Oligomer::~Oligomer()
436 {
437 // qDebug() << "~Oligomer()";
438 }
439
440
441 /*!
442 \brief Returns the polymer.
443 */
444 const Polymer *
445 Oligomer::polymer() const
446 {
447 return mp_polymer;
448 }
449
450
451 /*!
452 \brief Sets the start and end indices to \a value1 and \a value2 respectively.
453
454 The values are used to construct a Coordinates instance that is allocated on
455 the heap and added to member CoordinateList if that list is empty. If the
456 CoordinateList is not empty, then the values are set to the first Coordinates
457 instance in that list.
458
459 \sa setStartIndex(), setEndIndex()
460 */
461 void
462 Oligomer::setStartEndIndices(int value1, int value2)
463 {
464 if(!CoordinateList::size())
465 {
466 Coordinates *coordinates = new Coordinates(value1, value2);
467 append(coordinates);
468
469 // qDebug() << __FILE__ << __LINE__
470 // << "[start--end]:" << startIndex() << endIndex();
471 }
472 else
473 {
474 Coordinates *coordinates = first();
475 coordinates->setStart(value1);
476 coordinates->setEnd(value2);
477
478 // qDebug() << __FILE__ << __LINE__
479 // << "[start--end]:" << startIndex() << endIndex();
480 }
481 }
482
483
484 /*!
485 \brief Sets the start index to \a value.
486
487 The value is used to construct a Coordinates instance that is allocated on
488 the heap and added to member CoordinateList if that list is empty. If the
489 CoordinateList is not empty, then the value is set to the first Coordinates
490 instance in that list.
491 */
492 void
493 Oligomer::setStartIndex(int value)
494 {
495 if(value < 0)
496 qDebug() << __FILE__ << __LINE__ << "setStartIndex with value:" << value;
497
498 if(!CoordinateList::size())
499 {
500 Coordinates *coordinates = new Coordinates();
501 coordinates->setStart(value);
502 append(coordinates);
503 }
504 else
505 {
506 Coordinates *coordinates = first();
507 coordinates->setStart(value);
508 }
509 }
510
511
512 /*!
513 \brief Returns the start index, or -1 if no Coordinates instance is found in
514 the CoordinateList member.
515
516 The start index that is returned is the start index of the first Coordinates
517 instance of the CoordinateList member.
518 */
519 int
520 Oligomer::startIndex() const
521 {
522 if(!CoordinateList::size())
523 return -1;
524
525 Coordinates *coordinates = first();
526 return coordinates->start();
527 }
528
529
530 /*!
531 \brief Sets the end index to \a value.
532
533 The value is used to construct a Coordinates instance that is allocated on
534 the heap and added to member CoordinateList if that list is empty. If the
535 CoordinateList is not empty, then the value is set to the first Coordinates
536 instance in that list.
537 */
538 void
539 Oligomer::setEndIndex(int value)
540 {
541 if(!CoordinateList::size())
542 {
543 Coordinates *coordinates = new Coordinates();
544 coordinates->setEnd(value);
545 append(coordinates);
546 }
547 else
548 {
549 Coordinates *coordinates = first();
550 coordinates->setEnd(value);
551 }
552 }
553
554
555 /*!
556 \brief Returns the end index.
557
558 The end index that is returned is the end index of the first Coordinates
559 instance of the CoordinateList member.
560 */
561 int
562 Oligomer::endIndex() const
563 {
564 if(!CoordinateList::size())
565 return -1;
566
567 Coordinates *coordinates = first();
568 return coordinates->end();
569 }
570
571 /*!
572 \brief Set the description to \a description.
573 */
574 void
575 Oligomer::setDescription(const QString &description)
576 {
577 m_description = description;
578 }
579
580 /*!
581 \brief Returns the description.
582 */
583 QString
584 Oligomer::description() const
585 {
586 return m_description;
587 }
588
589 /*!
590 \brief Add to the member CoordinateList all the Coordinates instances found in
591 \a list.
592
593 The added Coordinates instances are copies of the instances found in \a list.
594
595 Returns the count of added Coordinates instances allocated on the heap.
596 */
597 int
598 Oligomer::appendCoordinates(CoordinateList *list)
599 {
600 Q_ASSERT(list);
601
602 int count = 0;
603
604 for(int iter = 0; iter < list->size(); ++iter)
605 {
606 Coordinates *iterCoordinates = list->at(iter);
607
608 Coordinates *coordinates = new Coordinates(*iterCoordinates);
609
610 append(coordinates);
611
612 ++count;
613 }
614
615 return count;
616 }
617
618 /*!
619 \brief Set the IonizeRule member to \a ionize_rule.
620
621 \sa MsXpS::libXpertMass::Ionizable::m_ionizeRule
622 */
623 void
624 Oligomer::setIonizeRule(IonizeRule &ionize_rule)
625 {
626 m_ionizeRule = ionize_rule;
627 }
628
629
630 /*!
631 \brief Returns a reference to the IonizeRule member.
632 */
633 IonizeRule &
634 Oligomer::ionizeRule()
635 {
636 return m_ionizeRule;
637 }
638
639 /*!
640 \brief Set the calculation options to \a calc_options.
641
642 \sa m_calcOptions
643 */
644 void
645 Oligomer::setCalcOptions(const CalcOptions &calc_options)
646 {
647 m_calcOptions = calc_options;
648 }
649
650 /*!
651 \brief Returns the calculation options.
652 */
653 const CalcOptions &
654 Oligomer::calcOptions() const
655 {
656 return m_calcOptions;
657 }
658
659
660 /*!
661 \brief Updates the member calculation options with this Oligomer's
662 CoordinateList.
663
664 The data in m_calcOptions that need updating are the CoordinateList elements.
665 */
666 void
667 Oligomer::updateCalcOptions()
668 {
669 // The data that need update are the CoordinateList elements
670 // depending on the internal ::OligomerList data.
671
672 m_calcOptions.setCoordinateList(*(dynamic_cast<CoordinateList *>(this)));
673 }
674
675 /*!
676 \brief Returns the Monomer in the enclosing Polymer that is located at the
677 start index of this oligomer.
678
679 \sa atRightEnd(), startIndex()
680 */
681 const Monomer &
682 Oligomer::atLeftEnd() const
683 {
684 // qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
685 // << startIndex();
686
687 return *(mp_polymer->at(startIndex()));
688 }
689
690
691 /*!
692 \brief Returns the Monomer in the enclosing Polymer that is located at the
693 end index of this oligomer.
694
695 \sa atLeftEnd(), endIndex()
696 */
697 const Monomer &
698 Oligomer::atRightEnd() const
699 {
700 // qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
701 // << endIndex();
702
703 return *(mp_polymer->at(endIndex()));
704 }
705
706 /*!
707 \brief Return the Monomer that is located in the enclosing Polymer at \a index.
708 */
709 const Monomer *
710 Oligomer::monomerAt(int index) const
711 {
712 Q_ASSERT(index >= 0);
713 Q_ASSERT(index < mp_polymer->size() - 1);
714
715 // qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
716 // << index;
717
718 return mp_polymer->at(index);
719 }
720
721 /*!
722 \brief Returns the member crossLinkList.
723 */
724 QList<CrossLink *> *
725 Oligomer::crossLinkList()
726 {
727 return &m_crossLinkList;
728 }
729
730 /*!
731 \brief Add the \a cross_link CrossLink to this Oligomer's list of \l{CrossLink}s
732
733 Returns true if the cross-link was added succesfully, or false if \a cross_link
734 was already in the list.
735 */
736 bool
737 Oligomer::addCrossLink(CrossLink *cross_link)
738 {
739 // Add the cross-link only if it does not exist already. Return true
740 // only if the crossLink has been added.
741
742 if(!m_crossLinkList.contains(cross_link))
743 {
744 m_crossLinkList.append(cross_link);
745
746 return true;
747 }
748
749 return false;
750 }
751
752
753 // ELEMENTAL CALCULATION FUNCTION
754 /////////////////////////////////
755
756 /*!
757 \brief Returns the elemental composition of this Oligomer instance.
758 */
759 QString
760 Oligomer::elementalComposition()
761 {
762 return elementalComposition(m_calcOptions, m_ionizeRule);
763 }
764
765
766 /*!
767 \brief Returns the elemental composition of this Oligomer instance.
768
769 The computation of the elemental composition is performed as configured in \a
770 calc_options and using the ionization described in \a ionize_rule.
771 */
772 QString
773 Oligomer::elementalComposition(const CalcOptions &calc_options,
774 const IonizeRule &ionize_rule)
775 {
776 int times = 0;
777
778 if(calc_options.selectionType() == SELECTION_TYPE_RESIDUAL_CHAINS)
779 {
780 times = 1;
781
782 // qDebug() << __FILE__ << __LINE__
783 // << "SELECTION_TYPE_RESIDUAL_CHAINS ; times:" << times;
784 }
785 else
786 {
787 // times = CoordinateList::size();
788
789 // Use the version whereby we can perform a sanity check that
790 // calc_options was updated with the proper CoordinateList
791 // data.
792
793 times = calc_options.coordinateList().size();
794 if(times != CoordinateList::size())
795 qFatal("Fatal error at %s@%d. Aborting.", __FILE__, __LINE__);
796
797 // qDebug() << __FILE__ << __LINE__
798 // << "SELECTION_TYPE_OLIGOMERS ; times:" << times;
799 }
800
801 return mp_polymer->elementalComposition(
802 ionize_rule, *(static_cast<CoordinateList *>(this)), calc_options);
803 }
804
805 /////////////////////////////////
806 // ELEMENTAL CALCULATION FUNCTION
807
808 /*!
809 \brief Calculates the sequence of this Oligomer and sets it to the Sequence
810 base class member m_monomerText.
811
812 Returns the size of m_monomerText. If m_polymer is nullptr, return 0.
813
814 \sa Sequence
815 */
816 int
817 Oligomer::makeMonomerText()
818 {
819 // Prepare the text version of the oligomer's sequence by basing
820 // it on the coordinates of *this oligomer and set that text to
821 // m_monomerText.
822
823 if(mp_polymer == nullptr)
824 return 0;
825
826 QString *text = monomerText();
827
828 m_monomerText = *text;
829
830 delete(text);
831
832 return m_monomerText.size();
833 }
834
835 /*!
836 \brief Returns a string with the sequence of this Oligomer.
837
838 If mp_polymer is non-nullptr, the sequence is calculated by looking
839 into the Polymer using member Coordinates.
840
841 If mp_polymer is nullptr and if Sequence::m_monomerText is not empty, that is
842 returned.
843
844 If mp_polymer is nullptr and if Sequence::m_monomerText is emtpy, then the
845 sequence is crafted by looking into Sequence::m_monomerList.
846
847 \sa makeMonomerText()
848 */
849 QString *
850 Oligomer::monomerText()
851 {
852 // Allocate a new string to hold the text version of *this
853 // oligomer's sequence.
854
855 // There are two situations:
856
857 // 1. The mp_polymer member is non-0, we can get access to it. Ask
858 // the polymer to do the work. This is the most faithful
859 // situation. But the caller must first ensure that the polymer
860 // actually exists.
861
862 // 2. The mp_polymer member is 0, we may have the oligomer
863 // sequence stored in *this oligomer. Test that.
864
865 QString *text = new QString();
866
867 if(mp_polymer)
868 {
869 // For each oligomer(if more than one, which is the case when the
870 // oligomer is actually a cross-linked oligomer), create a string...
871
872 int oligomerCount = CoordinateList::size();
873
874 for(int iter = 0; iter < oligomerCount; ++iter)
875 {
876 Coordinates *coordinates = CoordinateList::at(iter);
877
878 QString *local = mp_polymer->monomerText(
879 coordinates->start(), coordinates->end(), true);
880 text->append(*local);
881
882 // If this is a cross-linked oligomer and we are not appending
883 // text for the __last__ oligomer, then append "~" to let the
884 // user know that the sequences are cross-linked.
885 if(oligomerCount > 1 && iter < oligomerCount - 1)
886 text->append("~");
887
888 delete(local);
889 }
890 }
891 else
892 {
893 if(m_monomerText.size())
894 {
895 *text = m_monomerText;
896
897 return text;
898 }
899 else
900 {
901 if(m_monomerList.size())
902 return Sequence::monomerText(0, m_monomerList.size(), true);
903 }
904 }
905
906 return text;
907 }
908
909
910 /*!
911 \brief Calculates the monoisotopic and average masses.
912
913 The calculation is performed by computing the mono and avg masses
914 of the sequence stretch as described by the start and end indices in
915 the polymer sequence. Default calculation options are used.
916
917 Returns true if calculations were successful, false otherwise.
918 */
919 bool
920 Oligomer::calculateMasses()
921 {
922 CalcOptions calcOptions;
923
924 calcOptions.setCapping(CAP_NONE);
925
926 IonizeRule rule;
927
928 return calculateMasses(&calcOptions, &rule);
929 }
930
931 /*!
932 \brief Calculates the monoisotopic and average masses.
933
934 The calculation is performed by computing the mono and avg masses
935 of the sequence stretch as described by the start and end indices in
936 the polymer sequence. The calculations are configured by \a calc_options
937 and the ionization is defined in \a ionize_rule.
938
939 Returns true if calculations were successful, false otherwise.
940 */
941 bool
942 Oligomer::calculateMasses(const CalcOptions *calc_options,
943 const IonizeRule *ionize_rule)
944 {
945 Q_ASSERT(calc_options);
946
947 CalcOptions localOptions(*calc_options);
948
949 // The coordinates of the oligomer are the following:
950
951 // MAMISGMSGRKAS
952
953 // For a tryptic peptide obtained from protein above, we'd have
954
955 // MAMISGMSGR, that is in the oligomer coordinates:
956
957 // [0] MAMISGMSGR [9]
958
959 // When computing the mass of the oligomer, we have to do a
960
961 // for (iter == [0] ; iter < [9 + 1]; ++iter)
962
963 // Which is why we increment add 1 to m_endIndex in the function below.
964
965 // A polymer might be something made of more than one residual chain
966 // in case it is a cross-linked oligomer. Compute the mass fore each
967 // residual chain, without accounting for the cross-links...
968
969 m_mono = 0;
970 m_avg = 0;
971
972 // An oligomer _is_ a CoordinateList, and we need that list in the
973 // calcOptions so that we can call the Polymer::accountMasses
974 // function.
975
976 localOptions.setCoordinateList(*this);
977
978 // We do not want to take into account the cross-links because
979 // we'll be doing this here and because it cannot work if the
980 // cross-links are taken into account from the polymer.
981
982 int flags = localOptions.monomerEntities();
983 flags &= ~MONOMER_CHEMENT_CROSS_LINK;
984 localOptions.setMonomerEntities(flags);
985
986 Polymer::accountMasses(mp_polymer, localOptions, &m_mono, &m_avg);
987
988 // qDebug() << __FILE__ << __LINE__
989 // << "After accounting masses(prior to cross-links):"
990 // << "mono mass is:" << m_mono;
991
992 // At this point, we have added the mass of each constituent
993 // oligomer's residual chain. Let's deal with the cross-links.
994
995 for(int iter = 0; iter < m_crossLinkList.size(); ++iter)
996 {
997 CrossLink *crossLink = m_crossLinkList.at(iter);
998
999 if(!crossLink->accountMasses(&m_mono, &m_avg))
1000 return false;
1001
1002 // qDebug() << __FILE__ << __LINE__
1003 // << "After accounting cross-link:"
1004 // << crossLink->name()
1005 // << "mono mass is:" << m_mono;
1006 }
1007
1008 // If an ionizeRule is provided, use it. Otherwise, ionize
1009 // automatically using the ::Ionizable IonizeRule.
1010 if(ionize_rule)
1011 {
1012 // Note that if ionizeRule is invalid, then the ionization is
1013 // not performed.
1014
1015 if(ionize_rule->isValid())
1016 {
1017 /*
1018 if (ionize(mp_polymer, *ionizeRule) == -1)
1019 The line above is a huge bug. While we should be
1020 ionizing this oligomer, we end up ionizing the polymer !
1021 */
1022
1023 if(ionize(*ionize_rule) == -1)
1024 return false;
1025 }
1026 }
1027 else
1028 {
1029 if(ionize() == -1)
1030 return false;
1031 }
1032
1033 // qDebug() << __FILE__ << __LINE__
1034 // << "Coming out from the calculateMasses function:"
1035 // << "mono mass is:" << m_mono;
1036
1037 return true;
1038 }
1039
1040 /*!
1041 \brief Set the m_isModified status of this Oligomer to \a modified.
1042 */
1043 void
1044 Oligomer::setModified(bool modified)
1045 {
1046 m_isModified = modified;
1047 }
1048
1049 /*!
1050 \brief Returns the chemical modification status of this Oligomer.
1051
1052 If \a deep is true, the enclosing Polymer must exist (m_polymer cannot be
1053 nullptr) because each monomer of the Polymer is probed for a potential
1054 modification. This function returns true as soon as such a modified monomer is
1055 encountered.
1056
1057 If \a deep is false, the value of m_isModified is returned.
1058
1059 \sa m_isModified, Monomer::isModified()
1060 */
1061 bool
1062 Oligomer::isModified(bool deep /*false*/)
1063 {
1064 // Either we truly go to the polymer instance and check if the oligomer is
1065 // modified or we just ask for the member datum, that might have been set,
1066 // for example, during creation of the oligomer in the Cleaver::cleave()
1067 // function. We need the possibility to ask for the member datum because
1068 // there are circumstances where the oligomer exists and not the original
1069 // polymer (for example if the polymer sequence is edited while a set of
1070 // cleavage oligomers is displayed in the cleavage dialog. When the
1071 // tableviewmodel needs to refresh the contents of the cells, it crashes
1072 // because the polymer has been edited and one monomer is missing from the
1073 // sequence of the oligomer as it had been configured in the first place.
1074
1075 if(deep)
1076 {
1077 if(mp_polymer == nullptr)
1078 qFatal("Programming error.");
1079
1080 int oligomerCount = CoordinateList::size();
1081
1082 for(int iter = 0; iter < oligomerCount; ++iter)
1083 {
1084 Coordinates *coordinates = CoordinateList::at(iter);
1085
1086 for(int jter = coordinates->start(); jter < coordinates->end() + 1;
1087 ++jter)
1088 {
1089 // qDebug() << __FILE__ << __LINE__ << "Going to call at()
1090 // with value"
1091 // << iter;
1092
1093 const Monomer *monomer = mp_polymer->at(jter);
1094
1095 if(monomer->isModified())
1096 return true;
1097 }
1098 }
1099
1100 return false;
1101 }
1102 else
1103 {
1104 return m_isModified;
1105 }
1106 }
1107
1108 /*!
1109 \brief Returns the size of this Oligomer.
1110
1111 The size is computed by adding the length of all the regions of the
1112 enclosing Polymer as documented in the Coordinates instances in the member
1113 coordinateList.
1114 */
1115 int
1116 Oligomer::size()
1117 {
1118 int sum = 0;
1119
1120 int oligomerCount = CoordinateList::size();
1121
1122 // The size of an oligomer is the sum of all its oligomeric
1123 // components as described by the various coordinates.
1124
1125 for(int iter = 0; iter < oligomerCount; ++iter)
1126 {
1127 Coordinates *coordinates = CoordinateList::at(iter);
1128
1129 sum += coordinates->length();
1130 }
1131
1132 return sum;
1133 }
1134
1135 /*!
1136 \brief Returns true if this Oligomer spans at least one region of the
1137 enclosing polymer that contains a Monomer at \a index, false otherwise.
1138 */
1139 bool
1140 Oligomer::encompasses(int index) const
1141 {
1142 int oligomerCount = CoordinateList::size();
1143
1144 for(int iter = 0; iter < oligomerCount; ++iter)
1145 {
1146 Coordinates *coordinates = CoordinateList::at(iter);
1147
1148 if(index <= coordinates->start() && index >= coordinates->end())
1149 return true;
1150 }
1151
1152 return false;
1153 }
1154
1155
1156 /*!
1157 \brief Returns true if this Oligomer spans at least one region of the
1158 enclosing polymer that contains the Monomer \a monomer, false otherwise.
1159
1160 The search is performed by comparing pointers, thus the Monomer to be search \e
1161 is \a monomer.
1162 */
1163 bool
1164 Oligomer::encompasses(const Monomer *monomer) const
1165 {
1166 int oligomerCount = CoordinateList::size();
1167
1168 for(int iter = 0; iter < oligomerCount; ++iter)
1169 {
1170 Coordinates *coordinates = CoordinateList::at(iter);
1171
1172 for(int jter = coordinates->start(); jter < coordinates->end() + 1;
1173 ++jter)
1174 {
1175 // qDebug() << __FILE__ << __LINE__ << "Going to call at() with
1176 // value"
1177 // << jter;
1178
1179 if(mp_polymer->at(jter) == monomer)
1180 return true;
1181 }
1182 }
1183
1184 return false;
1185 }
1186
1187 } // namespace libXpertMass
1188
1189 } // namespace MsXpS
1190