1 /* massXpert - the true massist's program.
2    --------------------------------------
3    Copyright(C) 2006,2007 Filippo Rusconi
4 
5    http://www.massxpert.org/massXpert
6 
7    This file is part of the massXpert project.
8 
9    The massxpert project is the successor to the "GNU polyxmass"
10    project that is an official GNU project package(see
11    www.gnu.org). The massXpert project is not endorsed by the GNU
12    project, although it is released ---in its entirety--- under the
13    GNU General Public License. A huge part of the code in massXpert
14    is actually a C++ rewrite of code in GNU polyxmass. As such
15    massXpert was started at the Centre National de la Recherche
16    Scientifique(FRANCE), that granted me the formal authorization to
17    publish it under this Free Software License.
18 
19    This software is free software; you can redistribute it and/or
20    modify it under the terms of the GNU  General Public
21    License version 3, as published by the Free Software Foundation.
22 
23 
24    This software is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27    General Public License for more details.
28 
29    You should have received a copy of the GNU General Public License
30    along with this software; if not, write to the
31 
32    Free Software Foundation, Inc.,
33 
34    51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
35 */
36 
37 
38 /////////////////////// Local includes
39 #include "oligomer.hpp"
40 #include "polymer.hpp"
41 #include "ionizeRule.hpp"
42 
43 
44 namespace massXpert
45 {
46 
47   //! Constructs an oligomer.
48   /*!
49 
50     \param polymer Polymer in which \c this oligomer spans a region. Cannot
51     be 0.
52 
53     \param ponderable Ponderable used to initialized the data in \c
54     this. Note that the initialization is shallow, as the data in the
55     property list are not copied.
56 
57     \param name Name of the oligomer.
58 
59     \param startIndex Index of the first monomer of \c this oligomer in
60     the polymer sequence(note that this index is stored in the very first
61     Coordinates item in the CoordinateList).
62 
63     \param endIndex Index of the last monomer of \c this oligomer in the
64     polymer sequence(note that this index is stored in the very first
65     Coordinates item in the CoordinateList).
66 
67     \param ionizeRule IonizeRule to be used to initialize the Ionizable ancestor.
68 
69     \param isIonized Indicates if the oligomer should be considered
70     ionized.
71   */
Oligomer(Polymer * polymer,const QString & name,const QString & description,const Ponderable & ponderable,const IonizeRule & ionizeRule,const CalcOptions & calcOptions,bool isIonized,int startIndex,int endIndex)72   Oligomer::Oligomer(Polymer *polymer ,
73                      const QString &name,
74                      const QString &description,
75                      const Ponderable &ponderable,
76                      const IonizeRule &ionizeRule,
77                      const CalcOptions & calcOptions,
78                      bool isIonized,
79                      int startIndex, int endIndex)
80     : Ionizable(polymer->polChemDef(), name, ponderable,
81                 ionizeRule, isIonized),
82       mp_polymer(polymer),
83       m_description(description),
84       m_calcOptions(calcOptions)
85   {
86     setStartEndIndices(startIndex, endIndex);
87   }
88 
89 
90   //! Constructs an oligomer.
91   /*! The oligomer is constructed with its \c mp_polymer member set to
92     0. This means that no reference to the polymer can be done. This
93     constructor is useful when the oligomer must be created out of any
94     polymer context, like when oligomers are created starting from raw
95     text data in the MzLab window.
96 
97     \param polChemDef Polymer chemistry definition on which \c this
98     oligomer is based. Cannot be 0.
99 
100     \param ponderable Ponderable used to initialized the data in \c
101     this. Note that the initialization is shallow, as the data in the
102     property list are not copied.
103 
104     \param name Name of the oligomer.
105 
106     \param startIndex Index of the first monomer of \c this oligomer in
107     the polymer sequence(note that this index is stored in the very first
108     Coordinates item in the CoordinateList).
109 
110     \param endIndex Index of the last monomer of \c this oligomer in the
111     polymer sequence(note that this index is stored in the very first
112     Coordinates item in the CoordinateList).
113 
114     \param ionizeRule IonizeRule to be used to initialize the Ionizable ancestor.
115 
116     \param isIonized Indicates if the oligomer should be considered
117     ionized.
118   */
Oligomer(const PolChemDef * polChemDef,const QString & name,const QString & description,const Ponderable & ponderable,const IonizeRule & ionizeRule,const CalcOptions & calcOptions,bool isIonized,int startIndex,int endIndex)119   Oligomer::Oligomer(const PolChemDef *polChemDef,
120                      const QString &name,
121                      const QString &description,
122                      const Ponderable &ponderable,
123                      const IonizeRule &ionizeRule,
124                      const CalcOptions &calcOptions,
125                      bool isIonized,
126                      int startIndex, int endIndex)
127     : Ionizable(polChemDef, name, ponderable, ionizeRule, isIonized),
128       mp_polymer(0),
129       m_description(description),
130       m_calcOptions(calcOptions)
131   {
132     setStartEndIndices(startIndex, endIndex);
133     // if (startIndex < 0)
134     //   qDebug() << __FILE__ << __LINE__
135     //            << "Construct with startIndex:" << startIndex;
136   }
137 
138 
139   //! Constructs an oligomer.
140   /*!
141 
142     \param polymer Polymer in which \c this oligomer spans a region. Cannot
143     be 0.
144 
145     \param ponderable Ponderable used to initialized the data in \c
146     this. Note that the initialization is shallow, as the data in the
147     property list are not copied.
148 
149     \param name Name of the oligomer.
150 
151     \param startIndex Index of the first monomer of \c this oligomer in
152     the polymer sequence(note that this index is stored in the very first
153     Coordinates item in the CoordinateList).
154 
155     \param endIndex Index of the last monomer of \c this oligomer in the
156     polymer sequence(note that this index is stored in the very first
157     Coordinates item in the CoordinateList).
158   */
Oligomer(Polymer * polymer,const QString & name,const QString & description,const Ponderable & ponderable,int startIndex,int endIndex,const CalcOptions & calcOptions)159   Oligomer::Oligomer(Polymer *polymer,
160                      const QString &name,
161                      const QString &description,
162                      const Ponderable &ponderable,
163                      int startIndex, int endIndex,
164                      const CalcOptions &calcOptions)
165     : Ionizable(polymer->polChemDef(), name, ponderable),
166       mp_polymer(polymer),
167       m_description(description),
168       m_calcOptions(calcOptions)
169   {
170     setStartEndIndices(startIndex, endIndex);
171     if (startIndex < 0)
172       qDebug() << __FILE__ << __LINE__
173                << "Construct with startIndex:" << startIndex;
174   }
175 
176 
177   //! Constructs an oligomer.
178   /*! The oligomer is constructed with its \c mp_polymer member set to
179     0. This means that no reference to the polymer can be done. This
180     constructor is useful when the oligomer must be created out of any
181     polymer context, like when oligomers are created starting from raw
182     text data in the MzLab window.
183 
184     \param polChemDef Polymer chemistry definition on which \c this
185     oligomer is based. Cannot be 0.
186 
187     \param ponderable Ponderable used to initialized the data in \c
188     this. Note that the initialization is shallow, as the data in the
189     property list are not copied.
190 
191     \param name Name of the oligomer.
192 
193     \param startIndex Index of the first monomer of \c this oligomer in
194     the polymer sequence(note that this index is stored in the very first
195     Coordinates item in the CoordinateList).
196 
197     \param endIndex Index of the last monomer of \c this oligomer in the
198     polymer sequence(note that this index is stored in the very first
199     Coordinates item in the CoordinateList).
200   */
Oligomer(const PolChemDef * polChemDef,const QString & name,const QString & description,const Ponderable & ponderable,const CalcOptions & calcOptions,int startIndex,int endIndex)201   Oligomer::Oligomer(const PolChemDef *polChemDef,
202                      const QString &name,
203                      const QString &description,
204                      const Ponderable &ponderable,
205                      const CalcOptions &calcOptions,
206                      int startIndex, int endIndex)
207     : Ionizable(polChemDef, name, ponderable),
208       mp_polymer(0),
209       m_description(description),
210       m_calcOptions(calcOptions)
211   {
212     setStartEndIndices(startIndex, endIndex);
213     if (startIndex < 0)
214       qDebug() << __FILE__ << __LINE__
215                << "Construct with startIndex:" << startIndex;
216   }
217 
218 
Oligomer(const Ionizable & ionizable,const CalcOptions & calcOptions,int startIndex,int endIndex)219   Oligomer::Oligomer(const Ionizable& ionizable,
220                      const CalcOptions &calcOptions,
221                      int startIndex, int endIndex)
222     : Ionizable(ionizable),
223       mp_polymer(0),
224       m_description("NOT_SET"),
225       m_calcOptions(calcOptions)
226   {
227     setStartEndIndices(startIndex, endIndex);
228     if (startIndex < 0)
229       qDebug() << __FILE__ << __LINE__
230                << "Construct with startIndex:" << startIndex;
231   }
232 
233 
234   //! Constructs an oligomer.
235   /*!
236 
237     \param polymer Polymer in which \c this oligomer spans a region. Cannot
238     be 0.
239 
240     \param name Name of the oligomer.
241 
242     \param startIndex Index of the first monomer of \c this oligomer in
243     the polymer sequence.
244 
245     \param endIndex Index of the last monomer of \c this oligomer in the
246     polymer sequence.
247 
248     \param mono Monoisotopic mass.
249 
250     \param avg Average mass.
251   */
Oligomer(Polymer * polymer,const QString & name,const QString & description,double mono,double avg,int startIndex,int endIndex,const CalcOptions & calcOptions)252   Oligomer::Oligomer(Polymer *polymer ,
253                      const QString &name,
254                      const QString &description,
255                      double mono, double avg,
256                      int startIndex, int endIndex,
257                      const CalcOptions &calcOptions)
258     : Ionizable(mp_polymer->polChemDef(), name, Ponderable(mono, avg)),
259       mp_polymer(polymer),
260       m_description(description),
261       m_calcOptions(calcOptions)
262   {
263     setStartEndIndices(startIndex, endIndex);
264     if (startIndex < 0)
265       qDebug() << __FILE__ << __LINE__
266                << "Construct with startIndex:" << startIndex;
267   }
268 
269 
270   //! Constructs an oligomer.
271   /*! The oligomer is constructed with its \c mp_polymer member set to
272     0. This means that no reference to the polymer can be done. This
273     constructor is useful when the oligomer must be created out of any
274     polymer context, like when oligomers are created starting from raw
275     text data in the MzLab window.
276 
277     \param polChemDef Polymer chemistry definition on which \c this
278     oligomer is based. Cannot be 0.
279 
280     \param name Name of the oligomer.
281 
282     \param startIndex Index of the first monomer of \c this oligomer in
283     the polymer sequence.
284 
285     \param endIndex Index of the last monomer of \c this oligomer in the
286     polymer sequence.
287 
288     \param mono Monoisotopic mass.
289 
290     \param avg Average mass.
291   */
Oligomer(const PolChemDef * polChemDef,const QString & name,const QString & description,const CalcOptions & calcOptions,double mono,double avg,int startIndex,int endIndex)292   Oligomer::Oligomer(const PolChemDef *polChemDef,
293                      const QString &name,
294                      const QString &description,
295                      const CalcOptions &calcOptions,
296                      double mono, double avg,
297                      int startIndex, int endIndex)
298     : Ionizable(polChemDef, name, Ponderable(mono, avg)),
299       mp_polymer(0),
300       m_description(description),
301       m_calcOptions(calcOptions)
302   {
303     setStartEndIndices(startIndex, endIndex);
304   }
305 
306 
307   //! Constructs a copy of \p other.
308   /*!  The copying is shallow, as the data in the property list are not
309     copied.
310 
311     \param other oligomer to be used as a mold.
312   */
Oligomer(const Oligomer & other)313   Oligomer::Oligomer(const Oligomer &other)
314     : CoordinateList(other), Ionizable(other), PropListHolder(other),
315       mp_polymer(other.mp_polymer),
316       m_description(other.m_description),
317       m_calcOptions(other.m_calcOptions)
318   {
319   }
320 
321 
322   //! Destroys the oligomer.
~Oligomer()323   Oligomer::~Oligomer()
324   {
325     //   qDebug() << "~Oligomer()";
326   }
327 
328 
329 
330   //! Returns the polymer.
331   /*! \return the polymer.
332    */
333   const Polymer *
polymer() const334   Oligomer::polymer() const
335   {
336     return mp_polymer;
337   }
338 
339 
340   //! Sets the start and end indices.
341   /*! \param value1 New start index
342     \param value2 New end index
343   */
344   void
setStartEndIndices(int value1,int value2)345   Oligomer::setStartEndIndices(int value1, int value2)
346   {
347     if (!CoordinateList::size())
348       {
349 	Coordinates *coordinates = new Coordinates(value1, value2);
350 	append(coordinates);
351 
352 	//       qDebug() << __FILE__ << __LINE__
353 	// 		<< "[start--end]:" << startIndex() << endIndex();
354       }
355     else
356       {
357 	Coordinates *coordinates = first();
358 	coordinates->setStart(value1);
359 	coordinates->setEnd(value2);
360 
361 	//       qDebug() << __FILE__ << __LINE__
362 	// 		<< "[start--end]:" << startIndex() << endIndex();
363       }
364   }
365 
366 
367   //! Sets the start index.
368   /*! \param value New start index.
369    */
370   void
setStartIndex(int value)371   Oligomer::setStartIndex(int value)
372   {
373     if (value < 0)
374       qDebug() << __FILE__ << __LINE__
375                << "setStartIndex with value:" << value;
376 
377     if (!CoordinateList::size())
378       {
379 	Coordinates *coordinates = new Coordinates();
380 	coordinates->setStart(value);
381 	append(coordinates);
382       }
383     else
384       {
385 	Coordinates *coordinates = first();
386 	coordinates->setStart(value);
387       }
388   }
389 
390 
391   //! Returns the start index.
392   /*! \return the start index.
393    */
394   int
startIndex() const395   Oligomer::startIndex() const
396   {
397     if (!CoordinateList::size())
398       return -1;
399 
400     Coordinates *coordinates = first();
401     return coordinates->start();
402   }
403 
404 
405   //! Sets the end index.
406   /*! \param value New end index.
407    */
408   void
setEndIndex(int value)409   Oligomer::setEndIndex(int value)
410   {
411     if (!CoordinateList::size())
412       {
413 	Coordinates *coordinates = new Coordinates();
414 	coordinates->setEnd(value);
415 	append(coordinates);
416       }
417     else
418       {
419 	Coordinates *coordinates = first();
420 	coordinates->setEnd(value);
421       }
422   }
423 
424 
425   //! Returns the end index.
426   /*! \return the end index.
427    */
428   int
endIndex() const429   Oligomer::endIndex() const
430   {
431     if (!CoordinateList::size())
432       return -1;
433 
434     Coordinates *coordinates = first();
435     return coordinates->end();
436   }
437 
438 
439   void
setDescription(const QString & description)440   Oligomer::setDescription(const QString &description)
441   {
442     m_description = description;
443   }
444 
445 
446   QString
description() const447   Oligomer::description() const
448   {
449     return m_description;
450   }
451 
452 
453   int
appendCoordinates(CoordinateList * list)454   Oligomer::appendCoordinates(CoordinateList *list)
455   {
456     Q_ASSERT(list);
457 
458     int count = 0;
459 
460     for (int iter = 0; iter < list->size(); ++iter)
461       {
462 	Coordinates *iterCoordinates = list->at(iter);
463 
464 	Coordinates *coordinates = new Coordinates(*iterCoordinates);
465 
466 	append(coordinates);
467 
468 	++count;
469       }
470 
471     return count;
472   }
473 
474 
475   void
setIonizeRule(IonizeRule & ionizeRule)476   Oligomer::setIonizeRule(IonizeRule &ionizeRule)
477   {
478     m_ionizeRule = ionizeRule;
479   }
480 
481 
482   IonizeRule &
ionizeRule()483   Oligomer::ionizeRule()
484   {
485     return m_ionizeRule;
486   }
487 
488   void
setCalcOptions(const CalcOptions & calcOptions)489   Oligomer::setCalcOptions(const CalcOptions &calcOptions)
490   {
491     m_calcOptions = calcOptions;
492   }
493 
494 
495   const CalcOptions &
calcOptions() const496   Oligomer::calcOptions() const
497   {
498     return m_calcOptions;
499   }
500 
501   void
updateCalcOptions()502   Oligomer::updateCalcOptions()
503   {
504     // The data that need update are the CoordinateList elements
505     // depending on the internal ::OligomerList data.
506 
507     m_calcOptions.setCoordinateList(*(static_cast<CoordinateList *>(this)));
508   }
509 
510 
511 
512   const Monomer &
atLeftEnd() const513   Oligomer::atLeftEnd() const
514   {
515 //     qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
516 // 	   << startIndex();
517 
518     return *(mp_polymer->at(startIndex()));
519   }
520 
521 
522   const Monomer &
atRightEnd() const523   Oligomer::atRightEnd() const
524   {
525 //     qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
526 // 	   << endIndex();
527 
528     return *(mp_polymer->at(endIndex()));
529 
530 
531   }
532 
533 
534   const Monomer *
monomerAt(int index) const535   Oligomer::monomerAt(int index) const
536   {
537     Q_ASSERT(index >= 0);
538     Q_ASSERT(index < mp_polymer->size() - 1);
539 
540 //     qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
541 // 	      << index;
542 
543     return mp_polymer->at(index);
544   }
545 
546 
547   QList<CrossLink *> *
crossLinkList()548   Oligomer::crossLinkList()
549   {
550     return &m_crossLinkList;
551   }
552 
553 
554   bool
addCrossLink(CrossLink * crossLink)555   Oligomer::addCrossLink(CrossLink *crossLink)
556   {
557     // Add the cross-link only if it does not exist already. Return true
558     // only if the crossLink has been added.
559 
560     if (!m_crossLinkList.contains(crossLink))
561       {
562 	m_crossLinkList.append(crossLink);
563 
564 	return true;
565       }
566 
567     return false;
568   }
569 
570 
571   // ELEMENTAL CALCULATION FUNCTION
572   /////////////////////////////////
573 
574   QString
elementalComposition()575   Oligomer::elementalComposition()
576   {
577     int times = 0;
578 
579     if (m_calcOptions.selectionType() == SELECTION_TYPE_RESIDUAL_CHAINS)
580       {
581 	times = 1;
582 
583         // qDebug() << __FILE__ << __LINE__
584         //          << "SELECTION_TYPE_RESIDUAL_CHAINS ; times:" << times;
585       }
586     else
587       {
588         // 	times = CoordinateList::size();
589 
590         // Use the version whereby we can perform a sanity check that
591         // m_calcOptions was updated with the proper CoordinateList
592         // data.
593 
594         times = m_calcOptions.coordinateList().size();
595         if(times != CoordinateList::size())
596           qFatal("Fatal error at %s@%d. Aborting.",__FILE__, __LINE__);
597 
598         // qDebug() << __FILE__ << __LINE__
599         //          << "SELECTION_TYPE_OLIGOMERS ; times:" << times;
600       }
601 
602     return mp_polymer->elementalComposition
603       (m_ionizeRule,
604        *(static_cast<CoordinateList *>(this)),
605        m_calcOptions);
606   }
607 
608 
609   /////////////////////////////////
610   // ELEMENTAL CALCULATION FUNCTION
611 
612 
613   int
makeMonomerText()614   Oligomer::makeMonomerText()
615   {
616     // Prepare the text version of the oligomer's sequence by basing
617     // it on the coordinates of *this oligomer and set that text to
618     // m_monomerText.
619 
620     if (!mp_polymer)
621       return 0;
622 
623     QString *text = monomerText();
624 
625     m_monomerText = *text;
626 
627     delete(text);
628 
629     return m_monomerText.size();
630   }
631 
632 
633   QString *
monomerText()634   Oligomer::monomerText()
635   {
636     // Allocate a new string to hold the text version of *this
637     // oligomer's sequence.
638 
639     // There are two situations:
640 
641     // 1. The mp_polymer member is non-0, we can get access to it. Ask
642     // the polymer to do the work. This is the most faithful
643     // situation. But the caller must first ensure that the polymer
644     // actually exists.
645 
646     // 2. The mp_polymer member is 0, we may have the oligomer
647     // sequence stored in *this oligomer. Test that.
648 
649     QString *text = new QString();
650 
651     if (mp_polymer)
652       {
653 	// For each oligomer(if more than one, which is the case when the
654 	// oligomer is actually a cross-linked oligomer), create a string...
655 
656 	int oligomerCount = CoordinateList::size();
657 
658 	for(int iter = 0; iter < oligomerCount; ++iter)
659 	  {
660 	    Coordinates *coordinates = CoordinateList::at(iter);
661 
662 	    QString *local =
663 	      mp_polymer->monomerText(coordinates->start(),
664 				       coordinates->end(),
665 				       true);
666 	    text->append(*local);
667 
668 	    // If this is a cross-linked oligomer and we are not appending
669 	    // text for the __last__ oligomer, then append "~" to let the
670 	    // user know that the sequences are cross-linked.
671 	    if (oligomerCount > 1 && iter < oligomerCount - 1)
672 	      text->append("~");
673 
674 	    delete(local);
675 	  }
676       }
677     else
678       {
679 	if(m_monomerText.size())
680 	  {
681 	    *text = m_monomerText;
682 
683 	    return text;
684 	  }
685 	else
686 	  {
687 	    if (m_monomerList.size())
688 	      return Sequence::monomerText(0, m_monomerList.size(), true);
689 	  }
690       }
691 
692     return text;
693   }
694 
695 
696   //! Calculates the masses(mono and avg).
697   /*! The calculation is performed by computing the mono and avg masses
698     of the sequence stretch as described by the start and end indices in
699     the polymer sequence. Default calculation options are used.
700 
701     \return true if calculations were successful, false otherwise.
702 
703     \sa calculateMasses(const CalcOptions &calcOptions, const
704     IonizeRule &ionizeRule)
705 
706     \sa Polymer::ionize()
707 
708     \sa CalcOptions::CalcOptions()
709   */
710   bool
calculateMasses()711   Oligomer::calculateMasses()
712   {
713     CalcOptions calcOptions;
714 
715     calcOptions.setCapping(MXT_CAP_NONE);
716 
717     IonizeRule rule;
718 
719     return calculateMasses(&calcOptions, &rule);
720   }
721 
722 
723   //! Calculates the masses(mono and avg).
724   /*! The calculation is performed by computing the mono and avg masses
725     of the sequence stretch as described by the start and end indices in
726     the polymer sequence.
727 
728     \param calcOptions Calculation options to be used for the mass
729     calculation.
730 
731     \param ionizeRule Ionization rule to be used for the mass
732     calculation.
733 
734     \return true if calculations were successful, false otherwise.
735 
736     \sa Polymer::calculateMasses()
737 
738     \sa Polymer::ionize()
739   */
740   bool
calculateMasses(const CalcOptions * calcOptions,const IonizeRule * ionizeRule)741   Oligomer::calculateMasses(const CalcOptions *calcOptions,
742 			     const IonizeRule *ionizeRule)
743   {
744     Q_ASSERT(calcOptions);
745 
746     CalcOptions localOptions(*calcOptions);
747 
748     // The coordinates of the oligomer are the following:
749 
750     // MAMISGMSGRKAS
751 
752     // For a tryptic peptide obtained from protein above, we'd have
753 
754     // MAMISGMSGR, that is in the oligomer coordinates:
755 
756     // [0] MAMISGMSGR [9]
757 
758     // When computing the mass of the oligomer, we have to do a
759 
760     // for (iter == [0] ; iter < [9 + 1]; ++iter)
761 
762     // Which is why we increment add 1 to m_endIndex in the function below.
763 
764     // A polymer might be something made of more than one residual chain
765     // in case it is a cross-linked oligomer. Compute the mass fore each
766     // residual chain, without accounting for the cross-links...
767 
768     m_mono = 0;
769     m_avg = 0;
770 
771     // An oligomer _is_ a CoordinateList, and we need that list in the
772     // calcOptions so that we can call the Polymer::accountMasses
773     // function.
774 
775     localOptions.setCoordinateList(*this);
776 
777     // We do not want to take into account the cross-links because
778     // we'll be doing this here and because it cannot work if the
779     // cross-links are taken into account from the polymer.
780 
781     int flags = localOptions.monomerEntities();
782     flags &= ~MXT_MONOMER_CHEMENT_CROSS_LINK;
783     localOptions.setMonomerEntities(flags);
784 
785     Polymer::accountMasses(mp_polymer,
786 			    localOptions, &m_mono, &m_avg);
787 
788 //     qDebug() << __FILE__ << __LINE__
789 // 	      << "After accounting masses(prior to cross-links):"
790 // 	      << "mono mass is:" << m_mono;
791 
792     // At this point, we have added the mass of each constituent
793     // oligomer's residual chain. Let's deal with the cross-links.
794 
795     for (int iter = 0; iter < m_crossLinkList.size(); ++iter)
796       {
797 	CrossLink *crossLink = m_crossLinkList.at(iter);
798 
799 	if(!crossLink->accountMasses(&m_mono, &m_avg))
800 	  return false;
801 
802 // 	qDebug() << __FILE__ << __LINE__
803 // 		  << "After accounting cross-link:"
804 // 		  << crossLink->name()
805 // 		  << "mono mass is:" << m_mono;
806       }
807 
808     // If an ionizeRule is provided, use it. Otherwise, ionize
809     // automatically using the ::Ionizable IonizeRule.
810     if (ionizeRule)
811       {
812 	// Note that if ionizeRule is invalid, then the ionization is
813 	// not performed.
814 
815 	if(ionizeRule->isValid())
816 	  {
817 	    /*
818 	      if (ionize(mp_polymer, *ionizeRule) == -1)
819 	      The line above is a huge bug. While we should be
820 	      ionizing this oligomer, we end up ionizing the polymer !
821 	    */
822 
823 	    if (ionize(*ionizeRule) == -1)
824 	      return false;
825 	  }
826       }
827     else
828       {
829 	if(ionize() == -1)
830 	  return false;
831       }
832 
833 //     qDebug() << __FILE__ << __LINE__
834 // 	      << "Coming out from the calculateMasses function:"
835 // 	      << "mono mass is:" << m_mono;
836 
837     return true;
838   }
839 
840 
841   //! Tells if the oligomer contains at least one modified monomer.
842   /*! Iterates in the polymer sequence from start index to end index and
843     if one of the iterated monomers contain a PxmModif modification,
844     returns true;
845 
846     \return true if at least one monomer is modified, false otherwise.
847   */
848   bool
isModified()849   Oligomer::isModified()
850   {
851     int oligomerCount = CoordinateList::size();
852 
853     for (int iter = 0; iter < oligomerCount; ++iter)
854       {
855 	Coordinates *coordinates = CoordinateList::at(iter);
856 
857 	for(int jter = coordinates->start();
858 	     jter < coordinates->end() + 1; ++jter)
859 	  {
860 // 	    qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
861 // 		      << iter;
862 
863 	    const Monomer *monomer = mp_polymer->at(jter);
864 
865 	    if (monomer->isModified())
866 	      return true;
867 	  }
868       }
869 
870     return false;
871   }
872 
873 
874   int
size()875   Oligomer::size()
876   {
877     int sum = 0;
878 
879     int oligomerCount = CoordinateList::size();
880 
881     // The size of an oligomer is the sum of all its oligomeric
882     // components as described by the various coordinates.
883 
884     for (int iter = 0; iter < oligomerCount; ++iter)
885       {
886 	Coordinates *coordinates = CoordinateList::at(iter);
887 
888 	sum += coordinates->length();
889       }
890 
891     return sum;
892   }
893 
894 
895   bool
encompasses(int index) const896   Oligomer::encompasses(int index) const
897   {
898     int oligomerCount = CoordinateList::size();
899 
900     for (int iter = 0; iter < oligomerCount; ++iter)
901       {
902 	Coordinates *coordinates = CoordinateList::at(iter);
903 
904 	if(index <= coordinates->start() && index >= coordinates->end())
905 	  return true;
906       }
907 
908     return false;
909   }
910 
911 
912 
913   bool
encompasses(const Monomer * monomer) const914   Oligomer::encompasses(const Monomer *monomer) const
915   {
916     int oligomerCount = CoordinateList::size();
917 
918     for (int iter = 0; iter < oligomerCount; ++iter)
919       {
920 	Coordinates *coordinates = CoordinateList::at(iter);
921 
922 	for(int jter = coordinates->start();
923 	     jter < coordinates->end() + 1; ++jter)
924 	  {
925 // 	    qDebug() << __FILE__ << __LINE__ << "Going to call at() with value"
926 // 		      << jter;
927 
928 	    if (mp_polymer->at(jter) == monomer)
929 	      return true;
930 	  }
931       }
932 
933     return false;
934   }
935 
936 } // namespace massXpert
937